aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorUlrich Weigand <uweigand@de.ibm.com>2012-01-20 09:56:56 +0000
committerUlrich Weigand <uweigand@de.ibm.com>2012-01-20 09:56:56 +0000
commit6432734d1ddb783a4f7ed377dfe5920013ee9872 (patch)
tree788eb35fda8ae21ba5caafe36331cff96d2e7ca9 /gdb
parent1f20dca58b3deb69b2d65df5075f3288c366f93f (diff)
downloadgdb-6432734d1ddb783a4f7ed377dfe5920013ee9872.zip
gdb-6432734d1ddb783a4f7ed377dfe5920013ee9872.tar.gz
gdb-6432734d1ddb783a4f7ed377dfe5920013ee9872.tar.bz2
* 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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog39
-rw-r--r--gdb/gcore.c44
-rw-r--r--gdb/gdbarch.c33
-rw-r--r--gdb/gdbarch.h8
-rwxr-xr-xgdb/gdbarch.sh3
-rw-r--r--gdb/linux-nat.c323
-rw-r--r--gdb/linux-tdep.c275
-rw-r--r--gdb/linux-tdep.h12
8 files changed, 422 insertions, 315 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 1e41e81..ab0407e0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,44 @@
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.
* gdbarch.c, gdbarch.h: Regenerate.
diff --git a/gdb/gcore.c b/gdb/gcore.c
index f9e7590..2a769d3 100644
--- a/gdb/gcore.c
+++ b/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, &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);
- /* 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 ()));
+ if (note_data == NULL || note_size == 0)
+ error (_("Target does not support core file generation."));
- 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);
- }
+ /* Create the note section. */
+ 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);
/* 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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 2dbdda9..7a1db10 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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. */
@@ -1039,6 +1042,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -3245,6 +3254,30 @@ set_gdbarch_core_regset_sections (struct gdbarch *gdbarch,
}
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)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 7d1671d..b611760 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index eb8527c..c4ff5d1 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0a46e83..3a40c03 100644
--- a/gdb/linux-nat.c
+++ b/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;
-
- 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
- fill_gregset (regcache, &gregs, -1);
+ fill_gregset (regcache, &gregs, -1);
- note_data = (char *) elfcore_write_prstatus
- (obfd, note_data, note_size, lwp, target_signal_to_host (stop_signal),
- &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)))
+ 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);
+ 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
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index ff649b8..60fe8b6 100644
--- a/gdb/linux-tdep.c
+++ b/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 (&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
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index 4e9f560..d2f4077 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -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);