[rfc] [2/4] SPU overlay support: The SPU target part

Ulrich Weigand uweigand@de.ibm.com
Tue May 8 12:40:00 GMT 2007


Emi Suzuki wrote:

> I know that the duscussion about the corresponding gdbarch changes is
> going on (and I unfortunately have no alternative idea about it), but
> just want to notice you something that I came across.  
> 
> > +static void
> > +spu_overlay_new_objfile (struct objfile *objfile)
> > +{
> > +  struct spu_overlay_table *ovly_table;
> > +  bfd *obfd = objfile->obfd;
> > +  struct obj_section *osect;
> 
> It will cause SEGV if objfile is NULL.  
> That code seems to be optimized out by `-O2' option of GCC, though.  

Ah, thanks for catching this!  An updated patch is attached.

Bye,
Ulrich


ChangeLog:

	* spu-tdep.c: Include "observer.h".
	(spu_frame_unwind_cache): Unwind PC through overlay return stubs.
	(spu_overlay_data): New variable.
	(struct spu_overlay_table): New type.
	(spu_get_overlay_table, spu_overlay_update_osect, spu_overlay_update,
	spu_overlay_new_objfile): New functions.
	(spu_gdbarch_init): Install spu_overlay_update.
	(_initialize_spu_tdep): Register spu_overlay_new_objfile, 
	allocate spu_overlay_data objfile data.


diff -urNp gdb-orig/gdb/Makefile.in gdb-head/gdb/Makefile.in
--- gdb-orig/gdb/Makefile.in	2007-05-08 14:19:05.149146119 +0200
+++ gdb-head/gdb/Makefile.in	2007-05-07 23:18:00.000000000 +0200
@@ -2681,7 +2681,7 @@ spu-tdep.o: spu-tdep.c $(defs_h) $(arch_
 	$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(symtab_h) \
 	$(symfile_h) $(value_h) $(inferior_h) $(dis_asm_h) $(objfiles_h) \
 	$(language_h) $(regcache_h) $(reggroups_h) $(floatformat_h) \
-	$(spu_tdep_h)
+	$(observer_h) $(spu_tdep_h)
 stabsread.o: stabsread.c $(defs_h) $(gdb_string_h) $(bfd_h) $(gdb_obstack_h) \
 	$(symtab_h) $(gdbtypes_h) $(expression_h) $(symfile_h) $(objfiles_h) \
 	$(aout_stab_gnu_h) $(libaout_h) $(aout_aout64_h) $(gdb_stabs_h) \
diff -urNp gdb-orig/gdb/spu-tdep.c gdb-head/gdb/spu-tdep.c
--- gdb-orig/gdb/spu-tdep.c	2007-05-08 14:19:05.187140671 +0200
+++ gdb-head/gdb/spu-tdep.c	2007-05-08 14:21:11.400194338 +0200
@@ -42,6 +42,7 @@
 #include "regcache.h"
 #include "reggroups.h"
 #include "floatformat.h"
+#include "observer.h"
 
 #include "spu-tdep.h"
 
@@ -671,6 +672,7 @@ spu_frame_unwind_cache (struct frame_inf
 {
   struct spu_unwind_cache *info;
   struct spu_prologue_data data;
+  gdb_byte buf[16];
 
   if (*this_prologue_cache)
     return *this_prologue_cache;
@@ -698,7 +700,6 @@ spu_frame_unwind_cache (struct frame_inf
     {
       CORE_ADDR cfa;
       int i;
-      gdb_byte buf[16];
 
       /* Determine CFA via unwound CFA_REG plus CFA_OFFSET.  */
       frame_unwind_register (next_frame, data.cfa_reg, buf);
@@ -711,15 +712,6 @@ spu_frame_unwind_cache (struct frame_inf
 	  if (data.reg_offset[i] != -1)
 	    info->saved_regs[i].addr = cfa - data.reg_offset[i];
 
-      /* The previous PC comes from the link register.  */
-      if (trad_frame_addr_p (info->saved_regs, SPU_LR_REGNUM))
-	info->saved_regs[SPU_PC_REGNUM] = info->saved_regs[SPU_LR_REGNUM];
-      else
-	info->saved_regs[SPU_PC_REGNUM].realreg = SPU_LR_REGNUM;
-
-      /* The previous SP is equal to the CFA.  */
-      trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, cfa);
-
       /* Frame bases.  */
       info->frame_base = cfa;
       info->local_base = cfa - data.size;
@@ -742,20 +734,28 @@ spu_frame_unwind_cache (struct frame_inf
 	  if (backchain + 16 < SPU_LS_SIZE)
 	    info->saved_regs[SPU_LR_REGNUM].addr = backchain + 16;
 
-	  /* This will also be the previous PC.  */
-	  if (trad_frame_addr_p (info->saved_regs, SPU_LR_REGNUM))
-	    info->saved_regs[SPU_PC_REGNUM] = info->saved_regs[SPU_LR_REGNUM];
-	  else
-	    info->saved_regs[SPU_PC_REGNUM].realreg = SPU_LR_REGNUM;
-
-	  /* The previous SP will equal the backchain value.  */
-	  trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, backchain);
-
           /* Frame bases.  */
 	  info->frame_base = backchain;
 	  info->local_base = reg;
 	}
     }
+
+  /* The previous SP is equal to the CFA.  */
+  trad_frame_set_value (info->saved_regs, SPU_SP_REGNUM, info->frame_base);
+
+  /* The previous PC comes from the link register.  In the case
+     of overlay return stubs, we unwind to the real return address.  */
+  if (trad_frame_addr_p (info->saved_regs, SPU_LR_REGNUM))
+    target_read_memory (info->saved_regs[SPU_LR_REGNUM].addr, buf, 16);
+  else
+    frame_unwind_register (next_frame, SPU_LR_REGNUM, buf);
+
+  if (extract_unsigned_integer (buf + 8, 4) != 0)
+    trad_frame_set_value (info->saved_regs, SPU_PC_REGNUM,
+			  extract_unsigned_integer (buf + 8, 4));
+  else
+    trad_frame_set_value (info->saved_regs, SPU_PC_REGNUM,
+			  extract_unsigned_integer (buf, 4));
  
   return info;
 }
@@ -1124,6 +1124,189 @@ spu_software_single_step (struct regcach
   return 1;
 }
 
+/* Target overlays for the SPU overlay manager.
+
+   See the documentation of simple_overlay_update for how the
+   interface is supposed to work.
+
+   Data structures used by the overlay manager:
+
+   struct ovly_table
+     {
+        u32 vma;
+        u32 size;
+        u32 pos;
+        u32 buf;
+     } _ovly_table[];   -- one entry per overlay section
+
+   struct ovly_buf_table
+     {
+        u32 mapped;
+     } _ovly_buf_table[];  -- one entry per overlay buffer
+
+   _ovly_table should never change.
+
+   Both tables are aligned to a 16-byte boundary, the symbols _ovly_table
+   and _ovly_buf_table are of type STT_OBJECT and their size set to the size
+   of the respective array. buf in _ovly_table is an index into _ovly_buf_table.
+
+   mapped is an index into _ovly_table. Both the mapped and buf indices start
+   from one to reference the first entry in their respective tables.  */
+
+/* Using the per-objfile private data mechanism, we store for each
+   objfile an array of "struct spu_overlay_table" structures, one
+   for each obj_section of the objfile.  This structure holds two
+   fields, MAPPED_PTR and MAPPED_VAL.  If MAPPED_PTR is zero, this
+   is *not* an overlay section.  If it is non-zero, it represents
+   a target address.  The overlay section is mapped iff the target
+   integer at this location equals MAPPED_VAL.  */
+
+static const struct objfile_data *spu_overlay_data;
+
+struct spu_overlay_table
+  {
+    CORE_ADDR mapped_ptr;
+    CORE_ADDR mapped_val;
+  };
+
+/* Retrieve the overlay table for OBJFILE.  If not already cached, read
+   the _ovly_table data structure from the target and initialize the
+   spu_overlay_table data structure from it.  */
+static struct spu_overlay_table *
+spu_get_overlay_table (struct objfile *objfile)
+{
+  struct minimal_symbol *ovly_table_msym, *ovly_buf_table_msym;
+  CORE_ADDR ovly_table_base, ovly_buf_table_base;
+  unsigned ovly_table_size, ovly_buf_table_size;
+  struct spu_overlay_table *tbl;
+  struct obj_section *osect;
+  char *ovly_table;
+  int i;
+
+  tbl = objfile_data (objfile, spu_overlay_data);
+  if (tbl)
+    return tbl;
+
+  ovly_table_msym = lookup_minimal_symbol ("_ovly_table", NULL, objfile);
+  if (!ovly_table_msym)
+    return NULL;
+
+  ovly_buf_table_msym = lookup_minimal_symbol ("_ovly_buf_table", NULL, objfile);
+  if (!ovly_buf_table_msym)
+    return NULL;
+
+  ovly_table_base = SYMBOL_VALUE_ADDRESS (ovly_table_msym);
+  ovly_table_size = MSYMBOL_SIZE (ovly_table_msym);
+
+  ovly_buf_table_base = SYMBOL_VALUE_ADDRESS (ovly_buf_table_msym);
+  ovly_buf_table_size = MSYMBOL_SIZE (ovly_buf_table_msym);
+
+  ovly_table = xmalloc (ovly_table_size);
+  read_memory (ovly_table_base, ovly_table, ovly_table_size);
+
+  tbl = OBSTACK_CALLOC (&objfile->objfile_obstack,
+			objfile->sections_end - objfile->sections,
+			struct spu_overlay_table);
+
+  for (i = 0; i < ovly_table_size / 16; i++)
+    {
+      CORE_ADDR vma  = extract_unsigned_integer (ovly_table + 16*i + 0, 4);
+      CORE_ADDR size = extract_unsigned_integer (ovly_table + 16*i + 4, 4);
+      CORE_ADDR pos  = extract_unsigned_integer (ovly_table + 16*i + 8, 4);
+      CORE_ADDR buf  = extract_unsigned_integer (ovly_table + 16*i + 12, 4);
+
+      if (buf == 0 || (buf - 1) * 4 >= ovly_buf_table_size)
+	continue;
+
+      ALL_OBJFILE_OSECTIONS (objfile, osect)
+	if (vma == bfd_section_vma (objfile->obfd, osect->the_bfd_section)
+	    && pos == osect->the_bfd_section->filepos)
+	  {
+	    int ndx = osect - objfile->sections;
+	    tbl[ndx].mapped_ptr = ovly_buf_table_base + (buf - 1) * 4;
+	    tbl[ndx].mapped_val = i + 1;
+	    break;
+	  }
+    }
+
+  xfree (ovly_table);
+  set_objfile_data (objfile, spu_overlay_data, tbl);
+  return tbl;
+}
+
+/* Read _ovly_buf_table entry from the target to dermine whether
+   OSECT is currently mapped, and update the mapped state.  */
+static void
+spu_overlay_update_osect (struct obj_section *osect)
+{
+  struct spu_overlay_table *ovly_table;
+  CORE_ADDR val;
+
+  ovly_table = spu_get_overlay_table (osect->objfile);
+  if (!ovly_table)
+    return;
+
+  ovly_table += osect - osect->objfile->sections;
+  if (ovly_table->mapped_ptr == 0)
+    return;
+
+  val = read_memory_unsigned_integer (ovly_table->mapped_ptr, 4);
+  osect->ovly_mapped = (val == ovly_table->mapped_val);
+}
+
+/* If OSECT is NULL, then update all sections' mapped state.
+   If OSECT is non-NULL, then update only OSECT's mapped state.  */
+static void
+spu_overlay_update (struct obj_section *osect)
+{
+  /* Just one section.  */
+  if (osect)
+    spu_overlay_update_osect (osect);
+
+  /* All sections.  */
+  else
+    {
+      struct objfile *objfile;
+
+      ALL_OBJSECTIONS (objfile, osect)
+	if (section_is_overlay (osect->the_bfd_section))
+	  spu_overlay_update_osect (osect);
+    }
+}
+
+/* Whenever a new objfile is loaded, read the target's _ovly_table.
+   If there is one, go through all sections and make sure for non-
+   overlay sections LMA equals VMA, while for overlay sections LMA
+   is larger than local store size.  */
+static void
+spu_overlay_new_objfile (struct objfile *objfile)
+{
+  struct spu_overlay_table *ovly_table;
+  struct obj_section *osect;
+
+  /* If we've already touched this file, do nothing.  */
+  if (!objfile || objfile_data (objfile, spu_overlay_data) != NULL)
+    return;
+
+  /* Check if this objfile has overlays.  */
+  ovly_table = spu_get_overlay_table (objfile);
+  if (!ovly_table)
+    return;
+
+  /* Now go and fiddle with all the LMAs.  */
+  ALL_OBJFILE_OSECTIONS (objfile, osect)
+    {
+      bfd *obfd = objfile->obfd;
+      asection *bsect = osect->the_bfd_section;
+      int ndx = osect - objfile->sections;
+
+      if (ovly_table[ndx].mapped_ptr == 0)
+	bfd_section_lma (obfd, bsect) = bfd_section_vma (obfd, bsect);
+      else
+	bfd_section_lma (obfd, bsect) = bsect->filepos + SPU_LS_SIZE;
+    }
+}
+
 
 /* Set up gdbarch struct.  */
 
@@ -1200,6 +1383,9 @@ spu_gdbarch_init (struct gdbarch_info in
   set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
   set_gdbarch_software_single_step (gdbarch, spu_software_single_step);
 
+  /* Overlays.  */
+  set_gdbarch_overlay_update (gdbarch, spu_overlay_update);
+
   return gdbarch;
 }
 
@@ -1230,4 +1416,8 @@ _initialize_spu_tdep (void)
   register_gdbarch_init (bfd_arch_spu, spu_gdbarch_init);
 
   spu_init_vector_type ();
+
+  /* Add ourselves to objfile event chain.  */
+  observer_attach_new_objfile (spu_overlay_new_objfile);
+  spu_overlay_data = register_objfile_data ();
 }


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com



More information about the Gdb-patches mailing list