This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] ARM mapping symbol support for GDB


The ARM EABI defined "mapping symbols", which indicate with more
granularity than function symbols whether a given instruction is
ARM or Thumb (or non-executable data).  We already handle the
marker bit on Thumb function symbols; this patch extends GDB
to also handle mapping symbols.

You won't see a difference with this in most cases.  It's useful for
hand-written code which mixes ARM and Thumb in a single executable,
and for some linker-generated sections like the PLT.

Tested on arm-symbianelf and arm-eabi, checked in.

-- 
Daniel Jacobowitz
CodeSourcery

2008-05-02  Daniel Jacobowitz  <dan@codesourcery.com>

	* 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.

Index: gdb/objfiles.h
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.h,v
retrieving revision 1.49
diff -u -p -r1.49 objfiles.h
--- gdb/objfiles.h	26 Mar 2008 14:53:28 -0000	1.49
+++ gdb/objfiles.h	2 May 2008 18:22:54 -0000
@@ -527,6 +527,8 @@ extern int in_plt_section (CORE_ADDR, ch
    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);
Index: gdb/elfread.c
===================================================================
RCS file: /cvs/src/src/gdb/elfread.c,v
retrieving revision 1.70
diff -u -p -r1.70 elfread.c
--- gdb/elfread.c	26 Mar 2008 14:53:28 -0000	1.70
+++ gdb/elfread.c	2 May 2008 18:22:54 -0000
@@ -240,7 +240,11 @@ elf_symtab_read (struct objfile *objfile
 	 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
Index: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.425
diff -u -p -r1.425 gdbarch.c
--- gdb/gdbarch.c	2 May 2008 16:49:53 -0000	1.425
+++ gdb/gdbarch.c	2 May 2008 18:22:54 -0000
@@ -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, s
                       "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 (struc
   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. */
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.380
diff -u -p -r1.380 gdbarch.h
--- gdb/gdbarch.h	2 May 2008 16:49:53 -0000	1.380
+++ gdb/gdbarch.h	2 May 2008 18:22:54 -0000
@@ -794,6 +794,14 @@ typedef int (gdbarch_target_signal_to_ho
 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);
 
 
Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.263
diff -u -p -r1.263 arm-tdep.c
--- gdb/arm-tdep.c	2 May 2008 17:24:50 -0000	1.263
+++ gdb/arm-tdep.c	2 May 2008 18:22:54 -0000
@@ -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 *f
   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 *f
 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, s
 }
 
 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 in
   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,
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1010
diff -u -p -r1.1010 Makefile.in
--- gdb/Makefile.in	2 May 2008 16:49:53 -0000	1.1010
+++ gdb/Makefile.in	2 May 2008 18:22:55 -0000
@@ -1943,7 +1943,7 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame
 	$(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)
Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.466
diff -u -p -r1.466 gdbarch.sh
--- gdb/gdbarch.sh	2 May 2008 16:49:53 -0000	1.466
+++ gdb/gdbarch.sh	2 May 2008 18:22:55 -0000
@@ -701,6 +701,9 @@ m:enum target_signal:target_signal_from_
 # 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
 }
 
Index: gdb/objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.71
diff -u -p -r1.71 objfiles.c
--- gdb/objfiles.c	26 Mar 2008 14:53:28 -0000	1.71
+++ gdb/objfiles.c	2 May 2008 18:22:55 -0000
@@ -815,6 +815,7 @@ in_plt_section (CORE_ADDR pc, char *name
 struct objfile_data
 {
   unsigned index;
+  void (*cleanup) (struct objfile *, void *);
 };
 
 struct objfile_data_registration
@@ -832,7 +833,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;
 
@@ -844,10 +845,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)
 {
@@ -860,6 +868,7 @@ static void
 objfile_free_data (struct objfile *objfile)
 {
   gdb_assert (objfile->data != NULL);
+  clear_objfile_data (objfile);
   xfree (objfile->data);
   objfile->data = NULL;
 }
@@ -867,7 +876,17 @@ objfile_free_data (struct objfile *objfi
 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 *));
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]