From 3f3cf9508a7807f1c94d3a47fb69431b7b3db305 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 2 May 2008 20:38:16 +0000 Subject: [PATCH] * Makefile.in (arm-tdep.o): Update. * arm-tdep.c (arm_objfile_data_key, struct arm_mapping_symbol) (struct arm_per_objfile, arm_compare_mapping_symbols): New. (arm_pc_is_thumb): Use mapping symbols. (arm_objfile_data_cleanup, arm_record_special_symbol): New. (arm_gdbarch_init): Call set_gdbarch_record_special_symbol. (_initialize_arm_tdep): Initialize arm_objfile_data_key. * elfread.c (elf_symtab_read): Use gdbarch_record_special_symbol. * gdbarch.sh: Add record_special_symbol. * gdbarch.c, gdbarch.h: Regenerated. * objfiles.c (struct objfile_data): Add cleanup member. (register_objfile_data_with_cleanup): New function, from register_objfile_data. (register_objfile_data): Use it. (objfile_free_data): Call clear_objfile_data. (clear_objfile_data): Call cleanup functions. * objfiles.h (register_objfile_data_with_cleanup): Declare. --- gdb/ChangeLog | 20 +++++++++ gdb/Makefile.in | 2 +- gdb/arm-tdep.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/elfread.c | 6 ++- gdb/gdbarch.c | 33 ++++++++++++++ gdb/gdbarch.h | 8 ++++ gdb/gdbarch.sh | 3 ++ gdb/objfiles.c | 21 ++++++++- gdb/objfiles.h | 2 + 9 files changed, 222 insertions(+), 3 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e349f77951..c7515cbfdb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,25 @@ 2008-05-02 Daniel Jacobowitz + * Makefile.in (arm-tdep.o): Update. + * arm-tdep.c (arm_objfile_data_key, struct arm_mapping_symbol) + (struct arm_per_objfile, arm_compare_mapping_symbols): New. + (arm_pc_is_thumb): Use mapping symbols. + (arm_objfile_data_cleanup, arm_record_special_symbol): New. + (arm_gdbarch_init): Call set_gdbarch_record_special_symbol. + (_initialize_arm_tdep): Initialize arm_objfile_data_key. + * elfread.c (elf_symtab_read): Use gdbarch_record_special_symbol. + * gdbarch.sh: Add record_special_symbol. + * gdbarch.c, gdbarch.h: Regenerated. + * objfiles.c (struct objfile_data): Add cleanup member. + (register_objfile_data_with_cleanup): New function, from + register_objfile_data. + (register_objfile_data): Use it. + (objfile_free_data): Call clear_objfile_data. + (clear_objfile_data): Call cleanup functions. + * objfiles.h (register_objfile_data_with_cleanup): Declare. + +2008-05-02 Daniel Jacobowitz + * objfiles.c (init_entry_point_info): Handle shared libraries. 2008-05-02 Daniel Jacobowitz diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 16dd2ee863..6afdeba305 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1943,7 +1943,7 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \ $(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \ $(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \ $(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) \ - $(target_descriptions_h) $(user_regs_h) + $(target_descriptions_h) $(user_regs_h) $(vec_h) arm-wince-tdep.o: arm-wince-tdep.c $(defs_h) $(osabi_h) \ $(gdbcore_h) $(target_h) $(solib_h) $(solib_target_h) \ $(gdb_string_h) $(arm_tdep_h) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index fa7a3e87d5..9fbd0fcb18 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -51,6 +51,7 @@ #include "elf/arm.h" #include "gdb_assert.h" +#include "vec.h" static int arm_debug; @@ -68,6 +69,22 @@ static int arm_debug; #define MSYMBOL_IS_SPECIAL(msym) \ (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0) +/* Per-objfile data used for mapping symbols. */ +static const struct objfile_data *arm_objfile_data_key; + +struct arm_mapping_symbol +{ + bfd_vma value; + char type; +}; +typedef struct arm_mapping_symbol arm_mapping_symbol_s; +DEF_VEC_O(arm_mapping_symbol_s); + +struct arm_per_objfile +{ + VEC(arm_mapping_symbol_s) **section_maps; +}; + /* The list of available "set arm ..." and "show arm ..." commands. */ static struct cmd_list_element *setarmcmdlist = NULL; static struct cmd_list_element *showarmcmdlist = NULL; @@ -238,6 +255,15 @@ arm_frame_is_thumb (struct frame_info *frame) return (cpsr & CPSR_T) != 0; } +/* Callback for VEC_lower_bound. */ + +static inline int +arm_compare_mapping_symbols (const struct arm_mapping_symbol *lhs, + const struct arm_mapping_symbol *rhs) +{ + return lhs->value < rhs->value; +} + /* Determine if the program counter specified in MEMADDR is in a Thumb function. This function should be called for addresses unrelated to any executing frame; otherwise, prefer arm_frame_is_thumb. */ @@ -245,6 +271,7 @@ arm_frame_is_thumb (struct frame_info *frame) static int arm_pc_is_thumb (CORE_ADDR memaddr) { + struct obj_section *sec; struct minimal_symbol *sym; /* If bit 0 of the address is set, assume this is a Thumb address. */ @@ -257,6 +284,46 @@ arm_pc_is_thumb (CORE_ADDR memaddr) if (strcmp (arm_force_mode_string, "thumb") == 0) return 1; + /* If there are mapping symbols, consult them. */ + sec = find_pc_section (memaddr); + if (sec != NULL) + { + struct arm_per_objfile *data; + VEC(arm_mapping_symbol_s) *map; + struct arm_mapping_symbol map_key = { memaddr - sec->addr, 0 }; + unsigned int idx; + + data = objfile_data (sec->objfile, arm_objfile_data_key); + if (data != NULL) + { + map = data->section_maps[sec->the_bfd_section->index]; + if (!VEC_empty (arm_mapping_symbol_s, map)) + { + struct arm_mapping_symbol *map_sym; + + idx = VEC_lower_bound (arm_mapping_symbol_s, map, &map_key, + arm_compare_mapping_symbols); + + /* VEC_lower_bound finds the earliest ordered insertion + point. If the following symbol starts at this exact + address, we use that; otherwise, the preceding + mapping symbol covers this address. */ + if (idx < VEC_length (arm_mapping_symbol_s, map)) + { + map_sym = VEC_index (arm_mapping_symbol_s, map, idx); + if (map_sym->value == map_key.value) + return map_sym->type == 't'; + } + + if (idx > 0) + { + map_sym = VEC_index (arm_mapping_symbol_s, map, idx - 1); + return map_sym->type == 't'; + } + } + } + } + /* Thumb functions have a "special" bit set in minimal symbols. */ sym = lookup_minimal_symbol_by_pc (memaddr); if (sym) @@ -2787,6 +2854,65 @@ arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym) } static void +arm_objfile_data_cleanup (struct objfile *objfile, void *arg) +{ + struct arm_per_objfile *data = arg; + unsigned int i; + + for (i = 0; i < objfile->obfd->section_count; i++) + VEC_free (arm_mapping_symbol_s, data->section_maps[i]); +} + +static void +arm_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, + asymbol *sym) +{ + const char *name = bfd_asymbol_name (sym); + struct arm_per_objfile *data; + VEC(arm_mapping_symbol_s) **map_p; + struct arm_mapping_symbol new_map_sym; + + gdb_assert (name[0] == '$'); + if (name[1] != 'a' && name[1] != 't' && name[1] != 'd') + return; + + data = objfile_data (objfile, arm_objfile_data_key); + if (data == NULL) + { + data = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct arm_per_objfile); + set_objfile_data (objfile, arm_objfile_data_key, data); + data->section_maps = OBSTACK_CALLOC (&objfile->objfile_obstack, + objfile->obfd->section_count, + VEC(arm_mapping_symbol_s) *); + } + map_p = &data->section_maps[bfd_get_section (sym)->index]; + + new_map_sym.value = sym->value; + new_map_sym.type = name[1]; + + /* Assume that most mapping symbols appear in order of increasing + value. If they were randomly distributed, it would be faster to + always push here and then sort at first use. */ + if (!VEC_empty (arm_mapping_symbol_s, *map_p)) + { + struct arm_mapping_symbol *prev_map_sym; + + prev_map_sym = VEC_last (arm_mapping_symbol_s, *map_p); + if (prev_map_sym->value >= sym->value) + { + unsigned int idx; + idx = VEC_lower_bound (arm_mapping_symbol_s, *map_p, &new_map_sym, + arm_compare_mapping_symbols); + VEC_safe_insert (arm_mapping_symbol_s, *map_p, idx, &new_map_sym); + return; + } + } + + VEC_safe_push (arm_mapping_symbol_s, *map_p, &new_map_sym); +} + +static void arm_write_pc (struct regcache *regcache, CORE_ADDR pc) { regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc); @@ -3157,6 +3283,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special); set_gdbarch_coff_make_msymbol_special (gdbarch, arm_coff_make_msymbol_special); + set_gdbarch_record_special_symbol (gdbarch, arm_record_special_symbol); /* Virtual tables. */ set_gdbarch_vbit_in_delta (gdbarch, 1); @@ -3246,6 +3373,9 @@ _initialize_arm_tdep (void) gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); + arm_objfile_data_key + = register_objfile_data_with_cleanup (arm_objfile_data_cleanup); + /* Register an ELF OS ABI sniffer for ARM binaries. */ gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_elf_flavour, diff --git a/gdb/elfread.c b/gdb/elfread.c index 88ea77b16c..76af9dcd7c 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -240,7 +240,11 @@ elf_symtab_read (struct objfile *objfile, int type, symbols which do not correspond to objects in the symbol table, but have some other target-specific meaning. */ if (bfd_is_target_special_symbol (objfile->obfd, sym)) - continue; + { + if (gdbarch_record_special_symbol_p (gdbarch)) + gdbarch_record_special_symbol (gdbarch, objfile, sym); + continue; + } offset = ANOFFSET (objfile->section_offsets, sym->section->index); if (type == ST_DYNAMIC diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 0449aaa20d..537da1861c 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -237,6 +237,7 @@ struct gdbarch int sofun_address_maybe_missing; gdbarch_target_signal_from_host_ftype *target_signal_from_host; gdbarch_target_signal_to_host_ftype *target_signal_to_host; + gdbarch_record_special_symbol_ftype *record_special_symbol; }; @@ -366,6 +367,7 @@ struct gdbarch startup_gdbarch = 0, /* sofun_address_maybe_missing */ default_target_signal_from_host, /* target_signal_from_host */ default_target_signal_to_host, /* target_signal_to_host */ + 0, /* record_special_symbol */ /* startup_gdbarch() */ }; @@ -618,6 +620,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of sofun_address_maybe_missing, invalid_p == 0 */ /* Skip verify of target_signal_from_host, invalid_p == 0 */ /* Skip verify of target_signal_to_host, invalid_p == 0 */ + /* Skip verify of record_special_symbol, has predicate */ buf = ui_file_xstrdup (log, &dummy); make_cleanup (xfree, buf); if (strlen (buf) > 0) @@ -947,6 +950,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: read_pc = <0x%lx>\n", (long) gdbarch->read_pc); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_record_special_symbol_p() = %d\n", + gdbarch_record_special_symbol_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: record_special_symbol = <0x%lx>\n", + (long) gdbarch->record_special_symbol); + fprintf_unfiltered (file, "gdbarch_dump: register_name = <0x%lx>\n", (long) gdbarch->register_name); fprintf_unfiltered (file, @@ -3181,6 +3190,30 @@ set_gdbarch_target_signal_to_host (struct gdbarch *gdbarch, gdbarch->target_signal_to_host = target_signal_to_host; } +int +gdbarch_record_special_symbol_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->record_special_symbol != NULL; +} + +void +gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->record_special_symbol != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_record_special_symbol called\n"); + gdbarch->record_special_symbol (gdbarch, objfile, sym); +} + +void +set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, + gdbarch_record_special_symbol_ftype record_special_symbol) +{ + gdbarch->record_special_symbol = record_special_symbol; +} + /* Keep a registry of per-architecture data-pointers required by GDB modules. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index e89bd46bd8..560b2efccc 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -794,6 +794,14 @@ typedef int (gdbarch_target_signal_to_host_ftype) (struct gdbarch *gdbarch, enum extern int gdbarch_target_signal_to_host (struct gdbarch *gdbarch, enum target_signal ts); extern void set_gdbarch_target_signal_to_host (struct gdbarch *gdbarch, gdbarch_target_signal_to_host_ftype *target_signal_to_host); +/* Record architecture-specific information from the symbol table. */ + +extern int gdbarch_record_special_symbol_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym); +extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym); +extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol); + extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 08e37418a9..aedd9e541b 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -701,6 +701,9 @@ m:enum target_signal:target_signal_from_host:int signo:signo::default_target_sig # Signal translation: translate GDB's signal number into inferior's host # signal number. m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_host::0 + +# Record architecture-specific information from the symbol table. +M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym EOF } diff --git a/gdb/objfiles.c b/gdb/objfiles.c index 0234dcec7d..38768ccedb 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -821,6 +821,7 @@ in_plt_section (CORE_ADDR pc, char *name) struct objfile_data { unsigned index; + void (*cleanup) (struct objfile *, void *); }; struct objfile_data_registration @@ -838,7 +839,7 @@ struct objfile_data_registry static struct objfile_data_registry objfile_data_registry = { NULL, 0 }; const struct objfile_data * -register_objfile_data (void) +register_objfile_data_with_cleanup (void (*cleanup) (struct objfile *, void *)) { struct objfile_data_registration **curr; @@ -850,10 +851,17 @@ register_objfile_data (void) (*curr)->next = NULL; (*curr)->data = XMALLOC (struct objfile_data); (*curr)->data->index = objfile_data_registry.num_registrations++; + (*curr)->data->cleanup = cleanup; return (*curr)->data; } +const struct objfile_data * +register_objfile_data (void) +{ + return register_objfile_data_with_cleanup (NULL); +} + static void objfile_alloc_data (struct objfile *objfile) { @@ -866,6 +874,7 @@ static void objfile_free_data (struct objfile *objfile) { gdb_assert (objfile->data != NULL); + clear_objfile_data (objfile); xfree (objfile->data); objfile->data = NULL; } @@ -873,7 +882,17 @@ objfile_free_data (struct objfile *objfile) void clear_objfile_data (struct objfile *objfile) { + struct objfile_data_registration *registration; + int i; + gdb_assert (objfile->data != NULL); + + for (registration = objfile_data_registry.registrations, i = 0; + i < objfile->num_data; + registration = registration->next, i++) + if (objfile->data[i] != NULL && registration->data->cleanup) + registration->data->cleanup (objfile, objfile->data[i]); + memset (objfile->data, 0, objfile->num_data * sizeof (void *)); } diff --git a/gdb/objfiles.h b/gdb/objfiles.h index 4f01f60f4e..c3ae954b5f 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -527,6 +527,8 @@ extern int in_plt_section (CORE_ADDR, char *); modules. */ extern const struct objfile_data *register_objfile_data (void); +extern const struct objfile_data *register_objfile_data_with_cleanup + (void (*cleanup) (struct objfile *, void *)); extern void clear_objfile_data (struct objfile *objfile); extern void set_objfile_data (struct objfile *objfile, const struct objfile_data *data, void *value); -- 2.11.0