* 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:
parent
1f20dca58b
commit
6432734d1d
8 changed files with 422 additions and 315 deletions
|
@ -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.
|
||||
|
|
42
gdb/gcore.c
42
gdb/gcore.c
|
@ -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, ¬e_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, ¬e_size);
|
||||
else
|
||||
note_data = gdbarch_make_corefile_notes (target_gdbarch, obfd, ¬e_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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
325
gdb/linux-nat.c
325
gdb/linux-nat.c
|
@ -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 (¤t_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 (¤t_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
|
||||
|
|
275
gdb/linux-tdep.c
275
gdb/linux-tdep.c
|
@ -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 (¤t_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 (¤t_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 (¤t_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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue