* gdbarch.sh (make_corefile_notes): New architecture callback.

* gdbarch.c: Regenerate.
	* gdbarch.h: Likewise.

	* gcore.c (write_gcore_file): Try gdbarch_make_corefile_notes
	before target_make_corefile_notes.  If NULL is returned, the
	target does not support core file generation.

	* linux-nat.c: Include "linux-tdep.h".
	(find_signalled_thread, find_stop_signal): Remove.
	(linux_nat_do_thread_registers): Likewise.
	(struct linux_nat_corefile_thread_data): Likewise.
	(linux_nat_corefile_thread_callback): Likewise.
	(iterate_over_spus): Likewise.
	(struct linux_spu_corefile_data): Likewise.
	(linux_spu_corefile_callback): Likewise.
	(linux_spu_make_corefile_notes): Likewise.
	(linux_nat_collect_thread_registers): New function.
	(linux_nat_make_corefile_notes): Replace contents by call to
	linux_make_corefile_notes passing linux_nat_collect_thread_registers
	as native-only callback.

	* linux-tdep.h: Include "bfd.h".
	(struct regcache): Add forward declaration.
	(linux_collect_thread_registers_ftype): New typedef.
	(linux_make_corefile_notes): Add prototype.
	* linux-tdep.c: Include "gdbthread.h", "gdbcore.h", "regcache.h",
	"regset.h", and "elf-bfd.h".
	(find_signalled_thread, find_stop_signal): New functions.
	(linux_spu_make_corefile_notes): Likewise.
	(linux_collect_thread_registers): Likewise.
	(struct linux_corefile_thread_data): New data structure.
	(linux_corefile_thread_callback): New funcion.
	(linux_make_corefile_notes): Likewise.
	(linux_make_corefile_notes_1): Likewise.
	(linux_init_abi): Install it.
This commit is contained in:
Ulrich Weigand 2012-01-20 09:56:56 +00:00
parent 1f20dca58b
commit 6432734d1d
8 changed files with 422 additions and 315 deletions

View file

@ -1,3 +1,42 @@
2012-01-20 Ulrich Weigand <ulrich.weigand@linaro.org>
* gdbarch.sh (make_corefile_notes): New architecture callback.
* gdbarch.c: Regenerate.
* gdbarch.h: Likewise.
* gcore.c (write_gcore_file): Try gdbarch_make_corefile_notes
before target_make_corefile_notes. If NULL is returned, the
target does not support core file generation.
* linux-nat.c: Include "linux-tdep.h".
(find_signalled_thread, find_stop_signal): Remove.
(linux_nat_do_thread_registers): Likewise.
(struct linux_nat_corefile_thread_data): Likewise.
(linux_nat_corefile_thread_callback): Likewise.
(iterate_over_spus): Likewise.
(struct linux_spu_corefile_data): Likewise.
(linux_spu_corefile_callback): Likewise.
(linux_spu_make_corefile_notes): Likewise.
(linux_nat_collect_thread_registers): New function.
(linux_nat_make_corefile_notes): Replace contents by call to
linux_make_corefile_notes passing linux_nat_collect_thread_registers
as native-only callback.
* linux-tdep.h: Include "bfd.h".
(struct regcache): Add forward declaration.
(linux_collect_thread_registers_ftype): New typedef.
(linux_make_corefile_notes): Add prototype.
* linux-tdep.c: Include "gdbthread.h", "gdbcore.h", "regcache.h",
"regset.h", and "elf-bfd.h".
(find_signalled_thread, find_stop_signal): New functions.
(linux_spu_make_corefile_notes): Likewise.
(linux_collect_thread_registers): Likewise.
(struct linux_corefile_thread_data): New data structure.
(linux_corefile_thread_callback): New funcion.
(linux_make_corefile_notes): Likewise.
(linux_make_corefile_notes_1): Likewise.
(linux_init_abi): Install it.
2012-01-20 Ulrich Weigand <ulrich.weigand@linaro.org>
* gdbarch.sh (info_proc): New callback.

View file

@ -71,35 +71,37 @@ write_gcore_file (bfd *obfd)
asection *note_sec = NULL;
/* An external target method must build the notes section. */
note_data = target_make_corefile_notes (obfd, &note_size);
/* FIXME: uweigand/2011-10-06: All architectures that support core file
generation should be converted to gdbarch_make_corefile_notes; at that
point, the target vector method can be removed. */
if (!gdbarch_make_corefile_notes_p (target_gdbarch))
note_data = target_make_corefile_notes (obfd, &note_size);
else
note_data = gdbarch_make_corefile_notes (target_gdbarch, obfd, &note_size);
if (note_data == NULL || note_size == 0)
error (_("Target does not support core file generation."));
/* Create the note section. */
if (note_data != NULL && note_size != 0)
{
note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
SEC_HAS_CONTENTS
| SEC_READONLY
| SEC_ALLOC);
if (note_sec == NULL)
error (_("Failed to create 'note' section for corefile: %s"),
bfd_errmsg (bfd_get_error ()));
note_sec = bfd_make_section_anyway_with_flags (obfd, "note0",
SEC_HAS_CONTENTS
| SEC_READONLY
| SEC_ALLOC);
if (note_sec == NULL)
error (_("Failed to create 'note' section for corefile: %s"),
bfd_errmsg (bfd_get_error ()));
bfd_set_section_vma (obfd, note_sec, 0);
bfd_set_section_alignment (obfd, note_sec, 0);
bfd_set_section_size (obfd, note_sec, note_size);
}
bfd_set_section_vma (obfd, note_sec, 0);
bfd_set_section_alignment (obfd, note_sec, 0);
bfd_set_section_size (obfd, note_sec, note_size);
/* Now create the memory/load sections. */
if (gcore_memory_sections (obfd) == 0)
error (_("gcore: failed to get corefile memory sections from target."));
/* Write out the contents of the note section. */
if (note_data != NULL && note_size != 0)
{
if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
warning (_("writing note section (%s)"),
bfd_errmsg (bfd_get_error ()));
}
if (!bfd_set_section_contents (obfd, note_sec, note_data, 0, note_size))
warning (_("writing note section (%s)"), bfd_errmsg (bfd_get_error ()));
}
static void

View file

@ -239,6 +239,7 @@ struct gdbarch
gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
gdbarch_regset_from_core_section_ftype *regset_from_core_section;
struct core_regset_section * core_regset_sections;
gdbarch_make_corefile_notes_ftype *make_corefile_notes;
gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries;
gdbarch_core_pid_to_str_ftype *core_pid_to_str;
const char * gcore_bfd_target;
@ -395,6 +396,7 @@ struct gdbarch startup_gdbarch =
0, /* fetch_pointer_argument */
0, /* regset_from_core_section */
0, /* core_regset_sections */
0, /* make_corefile_notes */
0, /* core_xfer_shared_libraries */
0, /* core_pid_to_str */
0, /* gcore_bfd_target */
@ -683,6 +685,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of register_reggroup_p, invalid_p == 0 */
/* Skip verify of fetch_pointer_argument, has predicate. */
/* Skip verify of regset_from_core_section, has predicate. */
/* Skip verify of make_corefile_notes, has predicate. */
/* Skip verify of core_xfer_shared_libraries, has predicate. */
/* Skip verify of core_pid_to_str, has predicate. */
/* Skip verify of gcore_bfd_target, has predicate. */
@ -1038,6 +1041,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: long_long_bit = %s\n",
plongest (gdbarch->long_long_bit));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_make_corefile_notes_p() = %d\n",
gdbarch_make_corefile_notes_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: make_corefile_notes = <%s>\n",
host_address_to_string (gdbarch->make_corefile_notes));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_max_insn_length_p() = %d\n",
gdbarch_max_insn_length_p (gdbarch));
@ -3244,6 +3253,30 @@ set_gdbarch_core_regset_sections (struct gdbarch *gdbarch,
gdbarch->core_regset_sections = core_regset_sections;
}
int
gdbarch_make_corefile_notes_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
return gdbarch->make_corefile_notes != NULL;
}
char *
gdbarch_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->make_corefile_notes != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_make_corefile_notes called\n");
return gdbarch->make_corefile_notes (gdbarch, obfd, note_size);
}
void
set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch,
gdbarch_make_corefile_notes_ftype make_corefile_notes)
{
gdbarch->make_corefile_notes = make_corefile_notes;
}
int
gdbarch_core_xfer_shared_libraries_p (struct gdbarch *gdbarch)
{

View file

@ -709,6 +709,14 @@ extern void set_gdbarch_regset_from_core_section (struct gdbarch *gdbarch, gdbar
extern struct core_regset_section * gdbarch_core_regset_sections (struct gdbarch *gdbarch);
extern void set_gdbarch_core_regset_sections (struct gdbarch *gdbarch, struct core_regset_section * core_regset_sections);
/* Create core file notes */
extern int gdbarch_make_corefile_notes_p (struct gdbarch *gdbarch);
typedef char * (gdbarch_make_corefile_notes_ftype) (struct gdbarch *gdbarch, bfd *obfd, int *note_size);
extern char * gdbarch_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size);
extern void set_gdbarch_make_corefile_notes (struct gdbarch *gdbarch, gdbarch_make_corefile_notes_ftype *make_corefile_notes);
/* Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from
core file into buffer READBUF with length LEN. */

View file

@ -631,6 +631,9 @@ M:const struct regset *:regset_from_core_section:const char *sect_name, size_t s
# Supported register notes in a core file.
v:struct core_regset_section *:core_regset_sections:const char *name, int len::::::host_address_to_string (gdbarch->core_regset_sections)
# Create core file notes
M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size
# Read offset OFFSET of TARGET_OBJECT_LIBRARIES formatted shared libraries list from
# core file into buffer READBUF with length LEN.
M:LONGEST:core_xfer_shared_libraries:gdb_byte *readbuf, ULONGEST offset, LONGEST len:readbuf, offset, len

View file

@ -58,6 +58,7 @@
#include <sys/vfs.h>
#include "solib.h"
#include "linux-osdata.h"
#include "linux-tdep.h"
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@ -4479,325 +4480,59 @@ linux_nat_find_memory_regions (find_memory_region_ftype func, void *obfd)
return 0;
}
static int
find_signalled_thread (struct thread_info *info, void *data)
{
if (info->suspend.stop_signal != TARGET_SIGNAL_0
&& ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
return 1;
return 0;
}
static enum target_signal
find_stop_signal (void)
{
struct thread_info *info =
iterate_over_threads (find_signalled_thread, NULL);
if (info)
return info->suspend.stop_signal;
else
return TARGET_SIGNAL_0;
}
/* Records the thread's register state for the corefile note
section. */
static char *
linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
char *note_data, int *note_size,
enum target_signal stop_signal)
linux_nat_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
char *note_data, int *note_size,
enum target_signal stop_signal)
{
unsigned long lwp = ptid_get_lwp (ptid);
struct gdbarch *gdbarch = target_gdbarch;
struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
const struct regset *regset;
int core_regset_p;
struct cleanup *old_chain;
struct core_regset_section *sect_list;
char *gdb_regset;
old_chain = save_inferior_ptid ();
inferior_ptid = ptid;
target_fetch_registers (regcache, -1);
do_cleanups (old_chain);
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
sect_list = gdbarch_core_regset_sections (gdbarch);
/* The loop below uses the new struct core_regset_section, which stores
the supported section names and sizes for the core file. Note that
note PRSTATUS needs to be treated specially. But the other notes are
structurally the same, so they can benefit from the new struct. */
if (core_regset_p && sect_list != NULL)
while (sect_list->sect_name != NULL)
{
regset = gdbarch_regset_from_core_section (gdbarch,
sect_list->sect_name,
sect_list->size);
gdb_assert (regset && regset->collect_regset);
gdb_regset = xmalloc (sect_list->size);
regset->collect_regset (regset, regcache, -1,
gdb_regset, sect_list->size);
if (strcmp (sect_list->sect_name, ".reg") == 0)
note_data = (char *) elfcore_write_prstatus
(obfd, note_data, note_size,
lwp, target_signal_to_host (stop_signal),
gdb_regset);
else
note_data = (char *) elfcore_write_register_note
(obfd, note_data, note_size,
sect_list->sect_name, gdb_regset,
sect_list->size);
xfree (gdb_regset);
sect_list++;
}
/* For architectures that does not have the struct core_regset_section
implemented, we use the old method. When all the architectures have
the new support, the code below should be deleted. */
if (core_regset_p
&& (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
sizeof (gregs)))
!= NULL && regset->collect_regset != NULL)
regset->collect_regset (regset, regcache, -1, &gregs, sizeof (gregs));
else
{
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
fill_gregset (regcache, &gregs, -1);
if (core_regset_p
&& (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
sizeof (gregs)))
note_data = (char *) elfcore_write_prstatus
(obfd, note_data, note_size, ptid_get_lwp (ptid),
target_signal_to_host (stop_signal), &gregs);
if (core_regset_p
&& (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
sizeof (fpregs)))
!= NULL && regset->collect_regset != NULL)
regset->collect_regset (regset, regcache, -1,
&gregs, sizeof (gregs));
else
fill_gregset (regcache, &gregs, -1);
regset->collect_regset (regset, regcache, -1, &fpregs, sizeof (fpregs));
else
fill_fpregset (regcache, &fpregs, -1);
note_data = (char *) elfcore_write_prstatus
(obfd, note_data, note_size, lwp, target_signal_to_host (stop_signal),
&gregs);
if (core_regset_p
&& (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
sizeof (fpregs)))
!= NULL && regset->collect_regset != NULL)
regset->collect_regset (regset, regcache, -1,
&fpregs, sizeof (fpregs));
else
fill_fpregset (regcache, &fpregs, -1);
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
&fpregs, sizeof (fpregs));
}
note_data = (char *) elfcore_write_prfpreg (obfd, note_data, note_size,
&fpregs, sizeof (fpregs));
return note_data;
}
struct linux_nat_corefile_thread_data
{
bfd *obfd;
char *note_data;
int *note_size;
int num_notes;
enum target_signal stop_signal;
};
/* Called by gdbthread.c once per thread. Records the thread's
register state for the corefile note section. */
static int
linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
{
struct linux_nat_corefile_thread_data *args = data;
args->note_data = linux_nat_do_thread_registers (args->obfd,
ti->ptid,
args->note_data,
args->note_size,
args->stop_signal);
args->num_notes++;
return 0;
}
/* Enumerate spufs IDs for process PID. */
static void
iterate_over_spus (int pid, void (*callback) (void *, int), void *data)
{
char path[128];
DIR *dir;
struct dirent *entry;
xsnprintf (path, sizeof path, "/proc/%d/fd", pid);
dir = opendir (path);
if (!dir)
return;
rewinddir (dir);
while ((entry = readdir (dir)) != NULL)
{
struct stat st;
struct statfs stfs;
int fd;
fd = atoi (entry->d_name);
if (!fd)
continue;
xsnprintf (path, sizeof path, "/proc/%d/fd/%d", pid, fd);
if (stat (path, &st) != 0)
continue;
if (!S_ISDIR (st.st_mode))
continue;
if (statfs (path, &stfs) != 0)
continue;
if (stfs.f_type != SPUFS_MAGIC)
continue;
callback (data, fd);
}
closedir (dir);
}
/* Generate corefile notes for SPU contexts. */
struct linux_spu_corefile_data
{
bfd *obfd;
char *note_data;
int *note_size;
};
static void
linux_spu_corefile_callback (void *data, int fd)
{
struct linux_spu_corefile_data *args = data;
int i;
static const char *spu_files[] =
{
"object-id",
"mem",
"regs",
"fpcr",
"lslr",
"decr",
"decr_status",
"signal1",
"signal1_type",
"signal2",
"signal2_type",
"event_mask",
"event_status",
"mbox_info",
"ibox_info",
"wbox_info",
"dma_info",
"proxydma_info",
};
for (i = 0; i < sizeof (spu_files) / sizeof (spu_files[0]); i++)
{
char annex[32], note_name[32];
gdb_byte *spu_data;
LONGEST spu_len;
xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[i]);
spu_len = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
annex, &spu_data);
if (spu_len > 0)
{
xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
args->note_data = elfcore_write_note (args->obfd, args->note_data,
args->note_size, note_name,
NT_SPU, spu_data, spu_len);
xfree (spu_data);
}
}
}
static char *
linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
{
struct linux_spu_corefile_data args;
args.obfd = obfd;
args.note_data = note_data;
args.note_size = note_size;
iterate_over_spus (PIDGET (inferior_ptid),
linux_spu_corefile_callback, &args);
return args.note_data;
}
/* Fills the "to_make_corefile_note" target vector. Builds the note
section for a corefile, and returns it in a malloc buffer. */
static char *
linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
{
struct linux_nat_corefile_thread_data thread_args;
/* The variable size must be >= sizeof (prpsinfo_t.pr_fname). */
char fname[16] = { '\0' };
/* The variable size must be >= sizeof (prpsinfo_t.pr_psargs). */
char psargs[80] = { '\0' };
char *note_data = NULL;
ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
gdb_byte *auxv;
int auxv_len;
if (get_exec_file (0))
{
strncpy (fname, lbasename (get_exec_file (0)), sizeof (fname));
strncpy (psargs, get_exec_file (0), sizeof (psargs));
if (get_inferior_args ())
{
char *string_end;
char *psargs_end = psargs + sizeof (psargs);
/* linux_elfcore_write_prpsinfo () handles zero unterminated
strings fine. */
string_end = memchr (psargs, 0, sizeof (psargs));
if (string_end != NULL)
{
*string_end++ = ' ';
strncpy (string_end, get_inferior_args (),
psargs_end - string_end);
}
}
note_data = (char *) elfcore_write_prpsinfo (obfd,
note_data,
note_size, fname, psargs);
}
/* Dump information for threads. */
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
thread_args.num_notes = 0;
thread_args.stop_signal = find_stop_signal ();
iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
gdb_assert (thread_args.num_notes != 0);
note_data = thread_args.note_data;
auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
NULL, &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
"CORE", NT_AUXV, auxv, auxv_len);
xfree (auxv);
}
note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
make_cleanup (xfree, note_data);
return note_data;
/* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
converted to gdbarch_core_regset_sections, this function can go away. */
return linux_make_corefile_notes (target_gdbarch, obfd, note_size,
linux_nat_collect_thread_registers);
}
/* Implement the to_xfer_partial interface for memory reads using the /proc

View file

@ -22,7 +22,12 @@
#include "linux-tdep.h"
#include "auxv.h"
#include "target.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "regcache.h"
#include "regset.h"
#include "elf/common.h"
#include "elf-bfd.h" /* for elfcore_write_* */
#include "inferior.h"
#include "cli/cli-utils.h"
@ -525,6 +530,275 @@ linux_info_proc (struct gdbarch *gdbarch, char *args,
}
}
/* Determine which signal stopped execution. */
static int
find_signalled_thread (struct thread_info *info, void *data)
{
if (info->suspend.stop_signal != TARGET_SIGNAL_0
&& ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
return 1;
return 0;
}
static enum target_signal
find_stop_signal (void)
{
struct thread_info *info =
iterate_over_threads (find_signalled_thread, NULL);
if (info)
return info->suspend.stop_signal;
else
return TARGET_SIGNAL_0;
}
/* Generate corefile notes for SPU contexts. */
static char *
linux_spu_make_corefile_notes (bfd *obfd, char *note_data, int *note_size)
{
static const char *spu_files[] =
{
"object-id",
"mem",
"regs",
"fpcr",
"lslr",
"decr",
"decr_status",
"signal1",
"signal1_type",
"signal2",
"signal2_type",
"event_mask",
"event_status",
"mbox_info",
"ibox_info",
"wbox_info",
"dma_info",
"proxydma_info",
};
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
gdb_byte *spu_ids;
LONGEST i, j, size;
/* Determine list of SPU ids. */
size = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
NULL, &spu_ids);
/* Generate corefile notes for each SPU file. */
for (i = 0; i < size; i += 4)
{
int fd = extract_unsigned_integer (spu_ids + i, 4, byte_order);
for (j = 0; j < sizeof (spu_files) / sizeof (spu_files[0]); j++)
{
char annex[32], note_name[32];
gdb_byte *spu_data;
LONGEST spu_len;
xsnprintf (annex, sizeof annex, "%d/%s", fd, spu_files[j]);
spu_len = target_read_alloc (&current_target, TARGET_OBJECT_SPU,
annex, &spu_data);
if (spu_len > 0)
{
xsnprintf (note_name, sizeof note_name, "SPU/%s", annex);
note_data = elfcore_write_note (obfd, note_data, note_size,
note_name, NT_SPU,
spu_data, spu_len);
xfree (spu_data);
if (!note_data)
{
xfree (spu_ids);
return NULL;
}
}
}
}
if (size > 0)
xfree (spu_ids);
return note_data;
}
/* Records the thread's register state for the corefile note
section. */
static char *
linux_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
char *note_data, int *note_size,
enum target_signal stop_signal)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct core_regset_section *sect_list;
unsigned long lwp;
sect_list = gdbarch_core_regset_sections (gdbarch);
gdb_assert (sect_list);
/* For remote targets the LWP may not be available, so use the TID. */
lwp = ptid_get_lwp (ptid);
if (!lwp)
lwp = ptid_get_tid (ptid);
while (sect_list->sect_name != NULL)
{
const struct regset *regset;
char *buf;
regset = gdbarch_regset_from_core_section (gdbarch,
sect_list->sect_name,
sect_list->size);
gdb_assert (regset && regset->collect_regset);
buf = xmalloc (sect_list->size);
regset->collect_regset (regset, regcache, -1, buf, sect_list->size);
/* PRSTATUS still needs to be treated specially. */
if (strcmp (sect_list->sect_name, ".reg") == 0)
note_data = (char *) elfcore_write_prstatus
(obfd, note_data, note_size, lwp,
target_signal_to_host (stop_signal), buf);
else
note_data = (char *) elfcore_write_register_note
(obfd, note_data, note_size,
sect_list->sect_name, buf, sect_list->size);
xfree (buf);
sect_list++;
if (!note_data)
return NULL;
}
return note_data;
}
struct linux_corefile_thread_data
{
struct gdbarch *gdbarch;
int pid;
bfd *obfd;
char *note_data;
int *note_size;
int num_notes;
enum target_signal stop_signal;
linux_collect_thread_registers_ftype collect;
};
/* Called by gdbthread.c once per thread. Records the thread's
register state for the corefile note section. */
static int
linux_corefile_thread_callback (struct thread_info *info, void *data)
{
struct linux_corefile_thread_data *args = data;
if (ptid_get_pid (info->ptid) == args->pid)
{
struct cleanup *old_chain;
struct regcache *regcache;
regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
old_chain = save_inferior_ptid ();
inferior_ptid = info->ptid;
target_fetch_registers (regcache, -1);
do_cleanups (old_chain);
args->note_data = args->collect (regcache, info->ptid, args->obfd,
args->note_data, args->note_size,
args->stop_signal);
args->num_notes++;
}
return !args->note_data;
}
/* Fills the "to_make_corefile_note" target vector. Builds the note
section for a corefile, and returns it in a malloc buffer. */
char *
linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
linux_collect_thread_registers_ftype collect)
{
struct linux_corefile_thread_data thread_args;
char *note_data = NULL;
gdb_byte *auxv;
int auxv_len;
/* Process information. */
if (get_exec_file (0))
{
const char *fname = lbasename (get_exec_file (0));
char *psargs = xstrdup (fname);
if (get_inferior_args ())
psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
(char *) NULL);
note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
fname, psargs);
xfree (psargs);
if (!note_data)
return NULL;
}
/* Thread register information. */
thread_args.gdbarch = gdbarch;
thread_args.pid = ptid_get_pid (inferior_ptid);
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
thread_args.num_notes = 0;
thread_args.stop_signal = find_stop_signal ();
thread_args.collect = collect;
iterate_over_threads (linux_corefile_thread_callback, &thread_args);
note_data = thread_args.note_data;
if (!note_data)
return NULL;
/* Auxillary vector. */
auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
NULL, &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
"CORE", NT_AUXV, auxv, auxv_len);
xfree (auxv);
if (!note_data)
return NULL;
}
/* SPU information. */
note_data = linux_spu_make_corefile_notes (obfd, note_data, note_size);
if (!note_data)
return NULL;
make_cleanup (xfree, note_data);
return note_data;
}
static char *
linux_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
/* FIXME: uweigand/2011-10-06: Once all GNU/Linux architectures have been
converted to gdbarch_core_regset_sections, we no longer need to fall back
to the target method at this point. */
if (!gdbarch_core_regset_sections (gdbarch))
return target_make_corefile_notes (obfd, note_size);
else
return linux_make_corefile_notes (gdbarch, obfd, note_size,
linux_collect_thread_registers);
}
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */
@ -533,6 +807,7 @@ linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
set_gdbarch_info_proc (gdbarch, linux_info_proc);
set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes_1);
}
void

View file

@ -20,6 +20,18 @@
#ifndef LINUX_TDEP_H
#define LINUX_TDEP_H
#include "bfd.h"
struct regcache;
typedef char *(*linux_collect_thread_registers_ftype) (const struct regcache *,
ptid_t,
bfd *, char *, int *,
enum target_signal);
char *linux_make_corefile_notes (struct gdbarch *, bfd *, int *,
linux_collect_thread_registers_ftype);
struct type *linux_get_siginfo_type (struct gdbarch *);
extern void linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);