2008-04-23 Maxim Grigoriev <maxim2405@gmail.com>
authorMaxim Grigoriev <maxim2405@gmail.com>
Wed, 23 Apr 2008 21:17:05 +0000 (21:17 +0000)
committerMaxim Grigoriev <maxim2405@gmail.com>
Wed, 23 Apr 2008 21:17:05 +0000 (21:17 +0000)
* Makefile.in (xtensa-tdep.o): Update dependencies.
* configure.tgt (xtensa*): Update dependencies.
* xtensa-tdep.c (arreg_number): Renamed from areg_number.
Local variable areg renamed to arreg.
(areg_number): New function.
(xtensa_pseudo_register_read, xtensa_pseudo_register_write)
(xtensa_extract_return_value, xtensa_store_return_value): areg_number
replaced by arreg_number.
(xtensa_windowed_frame_cache, struct xtensa_frame_cache): New comments.
(xtensa_alloc_frame_cache): Initialize cache->wd.ws.
(xtensa_scan_prologue): New function.
(xtensa_frame_cache): New local fp_regnum. Handle separately the case,
when ENTRY instraction hasn't been executed yet. Get the frame pointer
value based on prologue analysis. Fix the bugs preventing WS and
AR4-AR7/A11 registers from getting right values for intermediate frames,
whose registers have been already spilled.
(xtensa_frame_prev_register): Fix WS register value. Use are_number
and arreg_number appropriately.
(xtensa_gdbarch_init): Set solib_svr4_fetch_link_map_offsets to
svr4_ilp32_fetch_link_map_offsets.

gdb/ChangeLog
gdb/Makefile.in
gdb/configure.tgt
gdb/xtensa-tdep.c

index ed16e47..5d03f7f 100644 (file)
@@ -1,3 +1,26 @@
+2008-04-23  Maxim Grigoriev  <maxim2405@gmail.com>
+
+       * Makefile.in (xtensa-tdep.o): Update dependencies.
+       * configure.tgt (xtensa*): Update dependencies.
+       * xtensa-tdep.c (arreg_number): Renamed from areg_number.
+       Local variable areg renamed to arreg.
+       (areg_number): New function.
+       (xtensa_pseudo_register_read, xtensa_pseudo_register_write)
+       (xtensa_extract_return_value, xtensa_store_return_value): areg_number
+       replaced by arreg_number.
+       (xtensa_windowed_frame_cache, struct xtensa_frame_cache): New comments.
+       (xtensa_alloc_frame_cache): Initialize cache->wd.ws.
+       (xtensa_scan_prologue): New function.
+       (xtensa_frame_cache): New local fp_regnum. Handle separately the case,
+       when ENTRY instraction hasn't been executed yet. Get the frame pointer
+       value based on prologue analysis. Fix the bugs preventing WS and
+       AR4-AR7/A11 registers from getting right values for intermediate frames,
+       whose registers have been already spilled.
+       (xtensa_frame_prev_register): Fix WS register value. Use are_number
+       and arreg_number appropriately.
+       (xtensa_gdbarch_init): Set solib_svr4_fetch_link_map_offsets to
+       svr4_ilp32_fetch_link_map_offsets.
+
 2008-04-23  Andrew Stubbs  <andrew.stubbs@st.com>
 
        * printcmd.c: Define USE_PRINTF_I64 and PRINTF_HAS_LONG_LONG on MinGW.
index 86c4423..ba5f6ac 100644 (file)
@@ -3016,7 +3016,7 @@ xtensa-tdep.o: xtensa-tdep.c $(defs_h) $(doublest_h) $(frame_h) \
        $(value_h) $(gdbcmd_h) $(gdbcore_h) $(dis_asm_h) $(symfile_h) \
        $(objfiles_h) $(gdb_string_h) $(linespec_h) $(regcache_h) \
        $(reggroups_h) $(arch_utils_h) $(osabi_h) $(block_h) $(gdb_assert_h) \
-       $(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h)
+       $(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h) $(solib_svr4_h)
 xtensa-config.o: $(defs_h) $(xtensa_tdep_h)
 
 #
index b4e91f4..36ac71e 100644 (file)
@@ -523,7 +523,7 @@ xtensa*-*-linux*)   gdb_target=linux
        ;;
 xtensa*)
        # Target: Tensilica Xtensa processors
-       gdb_target_obs="xtensa-tdep.o xtensa-config.o"
+       gdb_target_obs="xtensa-tdep.o xtensa-config.o solib.o solib-svr4.o"
        ;;
 
 esac
index 0ed254f..200ad26 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "defs.h"
 #include "frame.h"
+#include "solib-svr4.h"
 #include "symtab.h"
 #include "symfile.h"
 #include "objfiles.h"
@@ -114,18 +115,33 @@ static int xtensa_debug_level = 0;
 #define PS_WOE                 (1<<18)
 #define PS_EXC                 (1<<4)
 
-/* Convert a live Ax register number to the corresponding Areg number.  */
+/* Convert a live A-register number to the corresponding AR-register number.  */
 static int
-areg_number (struct gdbarch *gdbarch, int regnum, ULONGEST wb)
+arreg_number (struct gdbarch *gdbarch, int a_regnum, ULONGEST wb)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int areg;
+  int arreg;
 
-  areg = regnum - tdep->a0_base;
-  areg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT;
-  areg &= tdep->num_aregs - 1;
+  arreg = a_regnum - tdep->a0_base;
+  arreg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT;
+  arreg &= tdep->num_aregs - 1;
 
-  return areg + tdep->ar_base;
+  return arreg + tdep->ar_base;
+}
+
+/* Convert a live AR-register number to the corresponding A-register order
+   number in a range [0..15].  Return -1, if AR_REGNUM is out of WB window.  */
+static int
+areg_number (struct gdbarch *gdbarch, int ar_regnum, unsigned int wb)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int areg;
+
+  areg = ar_regnum - tdep->ar_base;
+  if (areg < 0 || areg >= tdep->num_aregs)
+    return -1;
+  areg = (areg - wb * 4) & (tdep->num_aregs - 1);
+  return (areg > 15) ? -1 : areg;
 }
 
 static inline int
@@ -516,7 +532,8 @@ xtensa_pseudo_register_read (struct gdbarch *gdbarch,
       gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
 
       regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
-      regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4));
+      regnum = arreg_number (gdbarch, regnum,
+                            extract_unsigned_integer (buf, 4));
     }
 
   /* We can always read non-pseudo registers.  */
@@ -613,7 +630,8 @@ xtensa_pseudo_register_write (struct gdbarch *gdbarch,
 
       regcache_raw_read (regcache,
                         gdbarch_tdep (gdbarch)->wb_regnum, buf);
-      regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4));
+      regnum = arreg_number (gdbarch, regnum,
+                            extract_unsigned_integer (buf, 4));
     }
 
   /* We can always write 'core' registers.
@@ -880,9 +898,15 @@ xtensa_regset_from_core_section (struct gdbarch *core_arch,
 /* Frame cache part for Windowed ABI.  */
 typedef struct xtensa_windowed_frame_cache
 {
-  int wb;              /* Base for this frame; -1 if not in regfile.  */
-  int callsize;                /* Call size to next frame.  */
-  int ws;
+  int wb;              /* WINDOWBASE of the previous frame.  */
+  int callsize;                /* Call size of this frame.  */
+  int ws;              /* WINDOWSTART of the previous frame.  It keeps track of
+                          life windows only.  If there is no bit set for the
+                          window, that means it had been already spilled
+                          because of window overflow.  */
+
+  /* Spilled A-registers from the previous frame.
+     AREGS[i] == -1, if corresponding AR is alive.  */
   CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS];
 } xtensa_windowed_frame_cache_t;
 
@@ -932,11 +956,11 @@ typedef struct xtensa_call0_frame_cache
 
 typedef struct xtensa_frame_cache
 {
-  CORE_ADDR base;      /* Stack pointer of the next frame.  */
+  CORE_ADDR base;      /* Stack pointer of this frame.  */
   CORE_ADDR pc;                /* PC at the entry point to the function.  */
-  CORE_ADDR ra;                /* The raw return address.  */
-  CORE_ADDR ps;                /* The PS register of the frame.  */
-  CORE_ADDR prev_sp;   /* Stack Pointer of the frame.  */
+  CORE_ADDR ra;                /* The raw return address (without CALLINC).  */
+  CORE_ADDR ps;                /* The PS register of the previous frame.  */
+  CORE_ADDR prev_sp;   /* Stack Pointer of the previous frame.  */
   int call0;           /* It's a call0 framework (else windowed).  */
   union
     {
@@ -979,6 +1003,7 @@ xtensa_alloc_frame_cache (int windowed)
   else
     {
       cache->wd.wb = 0;
+      cache->wd.ws = 0;
       cache->wd.callsize = -1;
 
       for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++)
@@ -1028,9 +1053,126 @@ xtensa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
   return frame_id_build (fp + SP_ALIGNMENT, pc);
 }
 
+/* Returns the best guess about which register is a frame pointer
+   for the function containing CURRENT_PC.  */
+
+#define XTENSA_ISA_BSZ 32          /* Instruction buffer size.  */
+
+static unsigned int
+xtensa_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR current_pc)
+{
+#define RETURN_FP goto done
+
+  unsigned int fp_regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
+  CORE_ADDR start_addr;
+  xtensa_isa isa;
+  xtensa_insnbuf ins, slot;
+  char ibuf[XTENSA_ISA_BSZ];
+  CORE_ADDR ia, bt, ba;
+  xtensa_format ifmt;
+  int ilen, islots, is;
+  xtensa_opcode opc;
+  const char *opcname;
+
+  find_pc_partial_function (current_pc, NULL, &start_addr, NULL);
+  if (start_addr == 0)
+    return fp_regnum;
+
+  if (!xtensa_default_isa)
+    xtensa_default_isa = xtensa_isa_init (0, 0);
+  isa = xtensa_default_isa;
+  gdb_assert (XTENSA_ISA_BSZ >= xtensa_isa_maxlength (isa));
+  ins = xtensa_insnbuf_alloc (isa);
+  slot = xtensa_insnbuf_alloc (isa);
+  ba = 0;
+
+  for (ia = start_addr, bt = ia; ia < current_pc ; ia += ilen)
+    {
+      if (ia + xtensa_isa_maxlength (isa) > bt)
+        {
+         ba = ia;
+         bt = (ba + XTENSA_ISA_BSZ) < current_pc
+           ? ba + XTENSA_ISA_BSZ : current_pc;
+         read_memory (ba, ibuf, bt - ba);
+       }
+
+      xtensa_insnbuf_from_chars (isa, ins, &ibuf[ia-ba], 0);
+      ifmt = xtensa_format_decode (isa, ins);
+      if (ifmt == XTENSA_UNDEFINED)
+       RETURN_FP;
+      ilen = xtensa_format_length (isa, ifmt);
+      if (ilen == XTENSA_UNDEFINED)
+       RETURN_FP;
+      islots = xtensa_format_num_slots (isa, ifmt);
+      if (islots == XTENSA_UNDEFINED)
+       RETURN_FP;
+      
+      for (is = 0; is < islots; ++is)
+       {
+         if (xtensa_format_get_slot (isa, ifmt, is, ins, slot))
+           RETURN_FP;
+         
+         opc = xtensa_opcode_decode (isa, ifmt, is, slot);
+         if (opc == XTENSA_UNDEFINED) 
+           RETURN_FP;
+         
+         opcname = xtensa_opcode_name (isa, opc);
+
+         if (strcasecmp (opcname, "mov.n") == 0
+             || strcasecmp (opcname, "or") == 0)
+           {
+             unsigned int register_operand;
+
+             /* Possible candidate for setting frame pointer
+                from A1. This is what we are looking for.  */
+
+             if (xtensa_operand_get_field (isa, opc, 1, ifmt, 
+                                           is, slot, &register_operand) != 0)
+               RETURN_FP;
+             if (xtensa_operand_decode (isa, opc, 1, &register_operand) != 0)
+               RETURN_FP;
+             if (register_operand == 1)  /* Mov{.n} FP A1.  */
+               {
+                 if (xtensa_operand_get_field (isa, opc, 0, ifmt, is, slot, 
+                                               &register_operand) != 0)
+                   RETURN_FP;
+                 if (xtensa_operand_decode (isa, opc, 0,
+                                            &register_operand) != 0)
+                   RETURN_FP;
+
+                 fp_regnum = gdbarch_tdep (gdbarch)->a0_base + register_operand;
+                 RETURN_FP;
+               }
+           }
+
+         if (
+             /* We have problems decoding the memory.  */
+             opcname == NULL 
+             || strcasecmp (opcname, "ill") == 0
+             || strcasecmp (opcname, "ill.n") == 0
+             /* Hit planted breakpoint.  */
+             || strcasecmp (opcname, "break") == 0
+             || strcasecmp (opcname, "break.n") == 0
+             /* Flow control instructions finish prologue.  */
+             || xtensa_opcode_is_branch (isa, opc) > 0
+             || xtensa_opcode_is_jump   (isa, opc) > 0
+             || xtensa_opcode_is_loop   (isa, opc) > 0
+             || xtensa_opcode_is_call   (isa, opc) > 0
+             || strcasecmp (opcname, "simcall") == 0
+             || strcasecmp (opcname, "syscall") == 0)
+           /* Can not continue analysis.  */
+           RETURN_FP;
+       }
+    }
+done:
+  xtensa_insnbuf_free(isa, slot);
+  xtensa_insnbuf_free(isa, ins);
+  return fp_regnum;
+}
+
 /* The key values to identify the frame using "cache" are 
 
-       cache->base    = SP of this frame;
+       cache->base    = SP (or best guess about FP) of this frame;
        cache->pc      = entry-PC (entry point of the frame function);
        cache->prev_sp = SP of the previous frame.
 */
@@ -1047,6 +1189,7 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
   CORE_ADDR ra, wb, ws, pc, sp, ps;
   struct gdbarch *gdbarch = get_frame_arch (next_frame);
   unsigned int ps_regnum = gdbarch_ps_regnum (gdbarch);
+  unsigned int fp_regnum;
   char op1;
   int  windowed;
 
@@ -1090,21 +1233,35 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
          cache->wd.ws = ws;
          cache->prev_sp = frame_unwind_register_unsigned
                             (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+
+         /* This only can be the outermost frame since we are
+            just about to execute ENTRY.  SP hasn't been set yet.
+            We can assume any frame size, because it does not
+            matter, and, let's fake frame base in cache.  */
+         cache->base = cache->prev_sp + 16;
+
+         cache->pc = pc;
+         cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
+         cache->ps = (ps & ~PS_CALLINC_MASK)
+           | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+
+         return cache;
        }
       else
        {
+         fp_regnum = xtensa_scan_prologue (gdbarch, pc);
          ra = frame_unwind_register_unsigned
                 (next_frame, gdbarch_tdep (gdbarch)->a0_base);
          cache->wd.callsize = WINSIZE (ra);
          cache->wd.wb = (wb - cache->wd.callsize / 4)
                          & (gdbarch_tdep (gdbarch)->num_aregs / 4 - 1);
          cache->wd.ws = ws & ~(1 << wb);
-       }
 
-      cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
-      cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
-      cache->ps = (ps & ~PS_CALLINC_MASK)
-       | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+         cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+         cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
+         cache->ps = (ps & ~PS_CALLINC_MASK)
+           | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+       }
 
       if (cache->wd.ws == 0)
        {
@@ -1122,12 +1279,13 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
          if (cache->wd.callsize > 4)
            {
              /* Set A4...A7/A11.  */
-             /* Read an SP of the previous frame.  */
+             /* Get the SP of the frame previous to the previous one.
+                To achieve this, we have to dereference SP twice.  */
              sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
              sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
              sp -= cache->wd.callsize * 4;
 
-             for ( /* i=4  */ ; i < cache->wd.callsize; i++, sp += 4)
+             for ( i = 4; i < cache->wd.callsize; i++, sp += 4)
                {
                  cache->wd.aregs[i] = sp;
                }
@@ -1138,19 +1296,18 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
        /* If RA is equal to 0 this frame is an outermost frame.  Leave
           cache->prev_sp unchanged marking the boundary of the frame stack.  */
        {
-         if (cache->wd.ws == 0)
+         if ((cache->wd.ws & (1 << cache->wd.wb)) == 0)
            {
              /* Register window overflow already happened.
                 We can read caller's SP from the proper spill loction.  */
-             cache->prev_sp =
-               read_memory_integer (cache->wd.aregs[1],
-                                    register_size (gdbarch,
-                                      gdbarch_tdep (gdbarch)->a0_base + 1));
+             sp = frame_unwind_register_unsigned (next_frame,
+                    gdbarch_tdep (gdbarch)->a0_base + 1);
+             cache->prev_sp = read_memory_integer (sp - 12, 4); 
            }
          else
            {
              /* Read caller's frame SP directly from the previous window.  */
-             int regnum = areg_number
+             int regnum = arreg_number
                             (gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1,
                              cache->wd.wb);
 
@@ -1161,10 +1318,10 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
   else /* Call0 framework.  */
     {
       call0_frame_cache (next_frame, cache, pc);
+      fp_regnum = cache->c0.fp_regnum;
     }
 
-  cache->base = frame_unwind_register_unsigned
-                 (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+  cache->base = frame_unwind_register_unsigned (next_frame, fp_regnum);
 
   return cache;
 }
@@ -1272,12 +1429,7 @@ xtensa_frame_prev_register (struct frame_info *next_frame,
   else if (!cache->call0)
     {
       if (regnum == gdbarch_tdep (gdbarch)->ws_regnum)
-       {
-         if (cache->wd.ws != 0)
-           saved_reg = cache->wd.ws;
-         else
-           saved_reg = 1 << cache->wd.wb;
-       }
+       saved_reg = cache->wd.ws;
       else if (regnum == gdbarch_tdep (gdbarch)->wb_regnum)
        saved_reg = cache->wd.wb;
       else if (regnum == gdbarch_ps_regnum (gdbarch))
@@ -1302,18 +1454,18 @@ xtensa_frame_prev_register (struct frame_info *next_frame,
 
   if (!cache->call0) /* Windowed ABI.  */
     {
-      /* Convert A-register numbers to AR-register numbers.  */
+      /* Convert A-register numbers to AR-register numbers,
+        if we deal with A-register.  */
       if (regnum >= gdbarch_tdep (gdbarch)->a0_base
           && regnum <= gdbarch_tdep (gdbarch)->a0_base + 15)
-       regnum = areg_number (gdbarch, regnum, cache->wd.wb);
+       regnum = arreg_number (gdbarch, regnum, cache->wd.wb);
 
-      /* Check if AR-register has been saved to stack.  */
+      /* Check, if we deal with AR-register saved on stack.  */
       if (regnum >= gdbarch_tdep (gdbarch)->ar_base
          && regnum <= (gdbarch_tdep (gdbarch)->ar_base
                         + gdbarch_tdep (gdbarch)->num_aregs))
        {
-         int areg = regnum - gdbarch_tdep (gdbarch)->ar_base
-                      - (cache->wd.wb * 4);
+         int areg = areg_number (gdbarch, regnum, cache->wd.wb);
 
          if (areg >= 0
              && areg < XTENSA_NUM_SAVED_AREGS
@@ -1443,7 +1595,7 @@ xtensa_extract_return_value (struct type *type,
         register (A2) in the caller window.  */
       regcache_raw_read_unsigned
        (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
-      areg = areg_number (gdbarch,
+      areg = arreg_number (gdbarch,
                          gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
     }
   else
@@ -1493,8 +1645,8 @@ xtensa_store_return_value (struct type *type,
        internal_error (__FILE__, __LINE__,
                        _("unimplemented for this length: %d"),
                        TYPE_LENGTH (type));
-      areg = areg_number (gdbarch,
-                         gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
+      areg = arreg_number (gdbarch,
+                          gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
 
       DEBUGTRACE ("[xtensa_store_return_value] callsize %d wb %d\n",
               callsize, (int) wb);
@@ -2666,6 +2818,9 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_regset_from_core_section (gdbarch,
                                        xtensa_regset_from_core_section);
 
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
   return gdbarch;
 }