* spu-tdep.c: Include "observer.h".
authorUlrich Weigand <uweigand@de.ibm.com>
Fri, 11 May 2007 19:58:38 +0000 (19:58 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Fri, 11 May 2007 19:58:38 +0000 (19:58 +0000)
(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.

gdb/ChangeLog
gdb/Makefile.in
gdb/spu-tdep.c

index 9ddbf86c8d37240172a023e7997bb94c21302ae0..be0bc8fe3f1b3e0e04e3f84a1a7ec873068deab2 100644 (file)
@@ -1,3 +1,15 @@
+2007-05-11  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * 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.
+
 2007-05-11  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * gdbarch.sh (overlay_update): New gdbarch function.
index 067b812f7d6f2f75cfe67f1a928e7728391395c7..24ed913ad15d74030cf38d83adffa14f046990de 100644 (file)
@@ -2681,7 +2681,7 @@ spu-tdep.o: spu-tdep.c $(defs_h) $(arch_utils_h) $(gdbtypes_h) $(gdbcmd_h) \
        $(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) \
index a45532bf8091a44e54e5c7f6c68140e113cd2878..e25d66ee54ac044df3f14a0f226231d94b000d3a 100644 (file)
@@ -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_info *next_frame,
 {
   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_info *next_frame,
     {
       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_info *next_frame,
          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_info *next_frame,
          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 regcache *regcache)
   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 info, struct gdbarch_list *arches)
   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 ();
 }