From: Alan Modra Date: Thu, 21 Jan 2016 09:28:55 +0000 (+1030) Subject: Use elfcore_write_linux_prstatus in gdb X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e2b337e5a957affa1cb31693e1424d015a6e8f2a;p=thirdparty%2Fbinutils-gdb.git Use elfcore_write_linux_prstatus in gdb The gdb side. Nothing fancy here, though it'd be easier to fill in more fields now. Targets that are known to need a custom gdbarch_elfcore_write_linux_prstatus but don't have one yet can install a stop-gap hook implementation that still calls into elfcore_write_prstatus. It is currently installed for MIPS n32 and Sparc64 (though we're not writting any of pr_{u,s,cu,cs}time yet), and x86-64 x32 too. Signed-off-by: Pedro Alves --- diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index b948ea77fad..c545cd02a56 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -2073,6 +2073,10 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset); tdep->sizeof_gregset = 27 * 8; + /* x32's layout is not compatible with the 32-bit layout. */ + set_gdbarch_elfcore_write_linux_prstatus + (gdbarch, gdb_deprecated_elfcore_write_linux_prstatus); + amd64_x32_init_abi (info, gdbarch); /* Reserve a number for orig_rax. */ diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 41437447af7..fe0acbc8640 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -265,6 +265,7 @@ struct gdbarch gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections; gdbarch_make_corefile_notes_ftype *make_corefile_notes; gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo; + gdbarch_elfcore_write_linux_prstatus_ftype *elfcore_write_linux_prstatus; gdbarch_find_memory_regions_ftype *find_memory_regions; gdbarch_core_xfer_shared_libraries_ftype *core_xfer_shared_libraries; gdbarch_core_xfer_shared_libraries_aix_ftype *core_xfer_shared_libraries_aix; @@ -609,6 +610,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of iterate_over_regset_sections, has predicate. */ /* Skip verify of make_corefile_notes, has predicate. */ /* Skip verify of elfcore_write_linux_prpsinfo, has predicate. */ + /* Skip verify of elfcore_write_linux_prstatus, has predicate. */ /* Skip verify of find_memory_regions, has predicate. */ /* Skip verify of core_xfer_shared_libraries, has predicate. */ /* Skip verify of core_xfer_shared_libraries_aix, has predicate. */ @@ -930,6 +932,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: elfcore_write_linux_prpsinfo = <%s>\n", host_address_to_string (gdbarch->elfcore_write_linux_prpsinfo)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_elfcore_write_linux_prstatus_p() = %d\n", + gdbarch_elfcore_write_linux_prstatus_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: elfcore_write_linux_prstatus = <%s>\n", + host_address_to_string (gdbarch->elfcore_write_linux_prstatus)); fprintf_unfiltered (file, "gdbarch_dump: fast_tracepoint_valid_at = <%s>\n", host_address_to_string (gdbarch->fast_tracepoint_valid_at)); @@ -3465,6 +3473,30 @@ set_gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, gdbarch->elfcore_write_linux_prpsinfo = elfcore_write_linux_prpsinfo; } +int +gdbarch_elfcore_write_linux_prstatus_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->elfcore_write_linux_prstatus != NULL; +} + +char * +gdbarch_elfcore_write_linux_prstatus (struct gdbarch *gdbarch, bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prstatus *info) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->elfcore_write_linux_prstatus != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_elfcore_write_linux_prstatus called\n"); + return gdbarch->elfcore_write_linux_prstatus (obfd, note_data, note_size, info); +} + +void +set_gdbarch_elfcore_write_linux_prstatus (struct gdbarch *gdbarch, + gdbarch_elfcore_write_linux_prstatus_ftype elfcore_write_linux_prstatus) +{ + gdbarch->elfcore_write_linux_prstatus = elfcore_write_linux_prstatus; +} + int gdbarch_find_memory_regions_p (struct gdbarch *gdbarch) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 3fadcd14ba0..5e00b32c9f4 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -61,6 +61,7 @@ struct stap_parse_info; struct parser_state; struct ravenscar_arch_ops; struct elf_internal_linux_prpsinfo; +struct elf_internal_linux_prstatus; struct mem_range; struct syscalls_info; struct thread_info; @@ -818,10 +819,10 @@ typedef char * (gdbarch_make_corefile_notes_ftype) (struct gdbarch *gdbarch, bfd 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); -/* The elfcore writer hook to use to write Linux prpsinfo notes to core - files. Most Linux architectures use the same prpsinfo32 or - prpsinfo64 layouts, and so won't need to provide this hook, as we - call the Linux generic routines in bfd to write prpsinfo notes by +/* The elfcore writer hooks to use to write Linux notes to core files. + Most Linux architectures use the same prpsinfo{32,64} and + prstatus{32,64} layouts, and so won't need to provide these hooks, + as we call the Linux generic routines in bfd to write notes by default. */ extern int gdbarch_elfcore_write_linux_prpsinfo_p (struct gdbarch *gdbarch); @@ -830,6 +831,12 @@ typedef char * (gdbarch_elfcore_write_linux_prpsinfo_ftype) (bfd *obfd, char *no extern char * gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info); extern void set_gdbarch_elfcore_write_linux_prpsinfo (struct gdbarch *gdbarch, gdbarch_elfcore_write_linux_prpsinfo_ftype *elfcore_write_linux_prpsinfo); +extern int gdbarch_elfcore_write_linux_prstatus_p (struct gdbarch *gdbarch); + +typedef char * (gdbarch_elfcore_write_linux_prstatus_ftype) (bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prstatus *info); +extern char * gdbarch_elfcore_write_linux_prstatus (struct gdbarch *gdbarch, bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prstatus *info); +extern void set_gdbarch_elfcore_write_linux_prstatus (struct gdbarch *gdbarch, gdbarch_elfcore_write_linux_prstatus_ftype *elfcore_write_linux_prstatus); + /* Find core file memory regions */ extern int gdbarch_find_memory_regions_p (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 4ac6b90fd12..71e3e8c580f 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -697,12 +697,13 @@ M:void:iterate_over_regset_sections:iterate_over_regset_sections_cb *cb, void *c # Create core file notes M:char *:make_corefile_notes:bfd *obfd, int *note_size:obfd, note_size -# The elfcore writer hook to use to write Linux prpsinfo notes to core -# files. Most Linux architectures use the same prpsinfo32 or -# prpsinfo64 layouts, and so won't need to provide this hook, as we -# call the Linux generic routines in bfd to write prpsinfo notes by +# The elfcore writer hooks to use to write Linux notes to core files. +# Most Linux architectures use the same prpsinfo{32,64} and +# prstatus{32,64} layouts, and so won't need to provide these hooks, +# as we call the Linux generic routines in bfd to write notes by # default. F:char *:elfcore_write_linux_prpsinfo:bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prpsinfo *info:obfd, note_data, note_size, info +F:char *:elfcore_write_linux_prstatus:bfd *obfd, char *note_data, int *note_size, const struct elf_internal_linux_prstatus *info:obfd, note_data, note_size, info # Find core file memory regions M:int:find_memory_regions:find_memory_region_ftype func, void *data:func, data @@ -1248,6 +1249,7 @@ struct stap_parse_info; struct parser_state; struct ravenscar_arch_ops; struct elf_internal_linux_prpsinfo; +struct elf_internal_linux_prstatus; struct mem_range; struct syscalls_info; struct thread_info; diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 29f5f3c003e..d432c471438 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -1526,6 +1526,21 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, return note_data; } +/* See linux-tdep.h. + + FIXME: This should be reimplemented on the BFD side along the lines + of elfcore_write_linux_prstatus{32,64}, instead of relying on + elfcore_write_prstatus. */ + +char * +gdb_deprecated_elfcore_write_linux_prstatus + (bfd *obfd, char *note_data, int *note_size, + const struct elf_internal_linux_prstatus *info) +{ + return elfcore_write_prstatus (obfd, note_data, note_size, info->pr_pid, + info->pr_cursig, info->pr_reg); +} + /* Structure for passing information from linux_collect_thread_registers via an iterator to linux_collect_regset_section_cb. */ @@ -1564,9 +1579,31 @@ linux_collect_regset_section_cb (const char *sect_name, int size, /* PRSTATUS still needs to be treated specially. */ if (strcmp (sect_name, ".reg") == 0) - data->note_data = (char *) elfcore_write_prstatus - (data->obfd, data->note_data, data->note_size, data->lwp, - gdb_signal_to_host (data->stop_signal), buf); + { + struct elf_internal_linux_prstatus prstatus; + + memset (&prstatus, 0, sizeof (prstatus)); + prstatus.pr_reg = buf; + prstatus.pr_reg_size = size; + prstatus.pr_pid = data->lwp; + prstatus.pr_cursig = gdb_signal_to_host (data->stop_signal); + if (gdbarch_elfcore_write_linux_prstatus_p (data->gdbarch)) + data->note_data = gdbarch_elfcore_write_linux_prstatus (data->gdbarch, + data->obfd, + data->note_data, + data->note_size, + &prstatus); + else if (gdbarch_ptr_bit (data->gdbarch) == 64) + data->note_data = elfcore_write_linux_prstatus64 (data->obfd, + data->note_data, + data->note_size, + &prstatus); + else + data->note_data = elfcore_write_linux_prstatus32 (data->obfd, + data->note_data, + data->note_size, + &prstatus); + } else data->note_data = (char *) elfcore_write_register_note (data->obfd, data->note_data, data->note_size, diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h index 328c7f09b04..ae50b14c358 100644 --- a/gdb/linux-tdep.h +++ b/gdb/linux-tdep.h @@ -44,4 +44,12 @@ extern void linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch); extern int linux_is_uclinux (void); +/* Stop-gap gdbarch_elfcore_write_linux_prstatus implementation for + architectures whose prstatus{32,64} layout differs from the + standard one, and for which BFD doesn't provide a custom writer + yet. */ +extern char *gdb_deprecated_elfcore_write_linux_prstatus + (bfd *obfd, char *note_data, int *note_size, + const struct elf_internal_linux_prstatus *info); + #endif /* linux-tdep.h */ diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 8dc0566dba5..b2fcf235971 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1683,6 +1683,11 @@ mips_linux_init_abi (struct gdbarch_info info, µmips_linux_n32_rt_sigframe); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe); set_xml_syscall_file_name (gdbarch, "syscalls/mips-n32-linux.xml"); + + /* N32 uses a different prstatus compared to most other Linux + archs. */ + set_gdbarch_elfcore_write_linux_prstatus + (gdbarch, gdb_deprecated_elfcore_write_linux_prstatus); break; case MIPS_ABI_N64: set_gdbarch_get_longjmp_target (gdbarch, diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c index 1336d73b3ac..3a50900ecd0 100644 --- a/gdb/sparc64-linux-tdep.c +++ b/gdb/sparc64-linux-tdep.c @@ -307,6 +307,11 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->fpregset = &sparc64_linux_fpregset; tdep->sizeof_fpregset = 280; + /* Sparc64 uses a different prstatus compared to most other Linux + archs. */ + set_gdbarch_elfcore_write_linux_prstatus + (gdbarch, gdb_deprecated_elfcore_write_linux_prstatus); + tramp_frame_prepend_unwinder (gdbarch, &sparc64_linux_rt_sigframe); /* Hook in the DWARF CFI frame unwinder. */