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] Updating Xtensa frame handling algorithms.


In Xtensa frame handling routines, several bugs have been fixed
and improvements have been added. Link map for shared libraries
is now set appropriately.


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.


Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1002
diff -u -r1.1002 Makefile.in
--- gdb/Makefile.in	19 Apr 2008 06:12:16 -0000	1.1002
+++ gdb/Makefile.in	23 Apr 2008 19:27:25 -0000
@@ -3016,7 +3016,7 @@
 	$(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: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.201
diff -u -r1.201 configure.tgt
--- gdb/configure.tgt	27 Feb 2008 01:06:21 -0000	1.201
+++ gdb/configure.tgt	23 Apr 2008 19:27:29 -0000
@@ -523,7 +523,7 @@
 	;;
 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: gdb/xtensa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/xtensa-tdep.c,v
retrieving revision 1.23
diff -u -r1.23 xtensa-tdep.c
--- gdb/xtensa-tdep.c	22 Apr 2008 11:03:42 -0000	1.23
+++ gdb/xtensa-tdep.c	23 Apr 2008 19:27:33 -0000
@@ -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 @@
 #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 @@
       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 @@
 
       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 @@
 /* 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_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 @@
   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 @@
   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 @@
   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 @@
 	  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 @@
 	  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 @@
 	/* 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 @@
   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 @@
   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 @@
 
   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 @@
 	 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 @@
 	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 @@
   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;
 }
 

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