This is the mail archive of the gdb-patches@sources.redhat.com 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]

[RFA/ARM] Framificate the ARM port [3/3]


Here we are.  This patch converts the ARM from a legacy frame target to a
modern frame target.  Unlike my previous patches, it does include functional
changes - quite a few of them.  I believe they are all improvements.  For
instance, previously, backtracing from a Thumb function, to an ARM caller,
to that function's caller, did not work - GDB would stop at the first ARM
function.  I've verified that we now get a correct backtrace with these
changes.

Another change of note is in arm_scan_prologue, in the case where
find_pc_partial_function fails (no symbols).  We used to go through some
extreme contortions in order to find a stack pointer value, which we
expected to have the saved PC from this function's prologue stored in it. 
With proper unwinding, all we need to do is ask the previous function for
our frame pointer.  This requires making the assumption (since we haven't
found, let alone analyzed, our prologue yet) that we have the normal frame
pointer - a better assumption than that we have the same frame pointer as
our caller, which is obviously wrong sometimes.  I've verified that this
works for normal code.

The trickery in arm_init_extra_frame_info where we scanned the caller's
prologue (according to the comments; but it was actually the callee)
to find its frame register.  It became unnecessary, and I'm pretty sure it
was wrong to begin with - the same off-by-one-frame headache I've been
fighting all week is creeping up behind my eyeballs again.

This includes the small varobj change I mentioned earlier today on gdb@:
call get_frame_base_address instead of get_frame_base.  It's a monotonic
improvement, but leaving it out should hurt nothing but the MI testsuite for
finding variables in different frames.

This patch was tested only for xscale-elf, on the simulator.  I'm going to
be pulling out an arm-linux target to test it on tomorrow, and will report
results.  No new regressions, no fixed regressions.  I get 49 failures, from
fileio.exp, huge.exp, store.exp, mi-var-display.exp/mi1-var-display.exp (the
compiler bug relating to "weird"), args.exp, bang.exp, and templates.exp. 
And some compile errors from shreloc.exp.

Is this series of patches OK?  Next will be tracking down store.exp issues
and then enabling the DWARF-2 unwinder, which is what I was actually trying
to get at.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-06-30  Daniel Jacobowitz  <drow@mvista.com>

	* arm-tdep.c: Include frame-unwind.h, frame-base.h, and
	trad-frame.h.
	(arm_get_cache): Delete macro.
	(struct arm_prologue_cache): Update comments.  Make saved_regs into
	a trad_frame_saved_reg pointer.
	(thumb_scan_prologue): Update for saved_regs change.
	(arm_scan_prologue): Likewise.  Take NEXT_FRAME argument and use it
	in desperation search for our prologue.
	(arm_make_prologue_cache): Simplify.

	(arm_prologue_this_id, arm_prologue_prev_register)
	(arm_prologue_unwind, arm_prologue_unwind_p, arm_normal_frame_base)
	(arm_normal_base, arm_make_sigtramp_cache, arm_sigtramp_this_id)
	(arm_sigtramp_prev_register, arm_sigtramp_unwind)
	(arm_sigtramp_unwind_p, arm_unwind_dummy_id)
	(arm_unwind_pc, arm_unwind_sp): New.

	(arm_frame_chain_valid, arm_find_callers_reg)
	(arm_frame_saved_pc, arm_read_fp, arm_frame_init_saved_regs)
	(arm_pop_frame): Delete obsolete methods.
	(arm_minimal_frame_chain, arm_minimal_frame_info): Delete.

	(arm_gdbarch_init): Update for new frame methods.  Register prologue
	and sigtramp unwinders.  Set the default frame base method.

	* Makefile.in (arm-tdep.o): Update dependencies.
	* varobj.c (find_frame_addr_in_frame_chain): Call
	get_frame_base_address.

Index: gdb/arm-tdep.c
===================================================================
--- gdb.orig/arm-tdep.c	2003-06-30 18:28:56.000000000 -0400
+++ gdb/arm-tdep.c	2003-06-30 18:28:57.000000000 -0400
@@ -34,6 +34,9 @@
 #include "value.h"
 #include "arch-utils.h"
 #include "osabi.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -155,21 +158,31 @@ static void convert_from_extended (const
 static void convert_to_extended (const struct floatformat *, void *,
 				 const void *);
 
-/* Define other aspects of the stack frame.  We keep the offsets of
-   all saved registers, 'cause we need 'em a lot!  We also keep the
-   current size of the stack frame, and the offset of the frame
-   pointer from the stack pointer (for frameless functions, and when
-   we're still in the prologue of a function with a frame).  */
-
-#define arm_get_cache(fi) ((struct arm_prologue_cache *) get_frame_extra_info (fi))
-
 struct arm_prologue_cache
 {
-  CORE_ADDR unwound_sp, unwound_pc;
+  /* The stack pointer at the time this frame was created; i.e. our caller's
+     stack pointer when we were called.  We use this to identify the frame.  */
+  CORE_ADDR unwound_sp;
+
+  /* The current PC in this frame; i.e. our callee's resume address, if we are
+     not the innermost frame.  This is not constant throughout the lifetime
+     of this frame, so we don't use it to identify the frame, just to find
+     the function.  */
+  CORE_ADDR unwound_pc;
+
+  /* The frame base for this frame is just unwound_sp + frame offset - frame
+     size.  FRAMESIZE is the size of the stack frame, and FRAMEOFFSET
+     if the initial offset from the stack pointer (our stack pointer, not
+     UNWOUND_SP) to the frame base.  */
+
   int framesize;
   int frameoffset;
+
+  /* The register used to hold the frame pointer for this frame.  */
   int framereg;
-  CORE_ADDR saved_regs[1];
+
+  /* Saved register offsets.  */
+  struct trad_frame_saved_reg *saved_regs;
 };
 
 /* Addresses for calling Thumb functions have the bit 0 set.
@@ -178,12 +191,6 @@ struct arm_prologue_cache
 #define MAKE_THUMB_ADDR(addr)	((addr) | 1)
 #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
 
-static int
-arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
-{
-  return (DEPRECATED_FRAME_SAVED_PC (thisframe) >= LOWEST_PC);
-}
-
 /* Set to true if the 32-bit mode is in use.  */
 
 int arm_apcs_32 = 1;
@@ -591,7 +598,7 @@ thumb_scan_prologue (struct arm_prologue
 	    if (mask & (1 << regno))
 	      {
 		cache->framesize += 4;
-		cache->saved_regs[saved_reg[regno]] = -cache->framesize;
+		cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
 		/* Reset saved register map.  */
 		saved_reg[regno] = regno;
 	      }
@@ -708,10 +715,9 @@ thumb_scan_prologue (struct arm_prologue
  */
 
 static void
-arm_scan_prologue (struct arm_prologue_cache *cache)
+arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
 {
   int regno, sp_offset, fp_offset;
-  LONGEST return_value;
   CORE_ADDR prologue_start, prologue_end, current_pc;
 
   /* Assume there is no frame until proven otherwise.  */
@@ -769,9 +775,16 @@ arm_scan_prologue (struct arm_prologue_c
     }
   else
     {
-      /* Get address of the stmfd in the prologue of the callee; 
-         the saved PC is the address of the stmfd + 8.  */
-      if (!safe_read_memory_integer (cache->unwound_sp, 4,  &return_value))
+      /* We have no symbol information.  Our only option is to assume this
+	 function has a standard stack frame and the normal frame register.
+	 Then, we can find the value of our frame pointer on entrance to
+	 the callee (or at the present moment if this is the innermost frame).
+	 The value stored there should be the address of the stmfd + 8.  */
+      CORE_ADDR frame_loc;
+      LONGEST return_value;
+
+      frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
+      if (!safe_read_memory_integer (frame_loc, 4, &return_value))
         return;
       else
         {
@@ -830,7 +843,7 @@ arm_scan_prologue (struct arm_prologue_c
 	    if (mask & (1 << regno))
 	      {
 		sp_offset -= 4;
-		cache->saved_regs[regno] = sp_offset;
+		cache->saved_regs[regno].addr = sp_offset;
 	      }
 	}
       else if ((insn & 0xffffc000) == 0xe54b0000 ||	/* strb rx,[r11,#-n] */
@@ -866,7 +879,7 @@ arm_scan_prologue (struct arm_prologue_c
 	{
 	  sp_offset -= 12;
 	  regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
-	  cache->saved_regs[regno] = sp_offset;
+	  cache->saved_regs[regno].addr = sp_offset;
 	}
       else if ((insn & 0xffbf0fff) == 0xec2d0200)	/* sfmfd f0, 4, [sp!] */
 	{
@@ -893,7 +906,7 @@ arm_scan_prologue (struct arm_prologue_c
 	  for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
 	    {
 	      sp_offset -= 12;
-	      cache->saved_regs[fp_start_reg++] = sp_offset;
+	      cache->saved_regs[fp_start_reg++].addr = sp_offset;
 	    }
 	}
       else if ((insn & 0xf0000000) != 0xe0000000)
@@ -916,305 +929,248 @@ arm_scan_prologue (struct arm_prologue_c
     cache->frameoffset = 0;
 }
 
-/* Find REGNUM on the stack.  Otherwise, it's in an active register.
-   One thing we might want to do here is to check REGNUM against the
-   clobber mask, and somehow flag it as invalid if it isn't saved on
-   the stack somewhere.  This would provide a graceful failure mode
-   when trying to get the value of caller-saves registers for an inner
-   frame.  */
-
-static CORE_ADDR
-arm_find_callers_reg (struct frame_info *fi, int regnum)
+static struct arm_prologue_cache *
+arm_make_prologue_cache (struct frame_info *next_frame)
 {
-  /* NOTE: cagney/2002-05-03: This function really shouldn't be
-     needed.  Instead the (still being written) register unwind
-     function could be called directly.  */
-  for (; fi; fi = get_next_frame (fi))
-    {
-      if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
-	{
-	  return deprecated_read_register_dummy (get_frame_pc (fi),
-						 get_frame_base (fi), regnum);
-	}
-      else if (get_frame_saved_regs (fi)[regnum] != 0)
-	{
-	  /* NOTE: cagney/2002-05-03: This would normally need to
-             handle ARM_SP_REGNUM as a special case as, according to
-             the frame.h comments, saved_regs[SP_REGNUM] contains the
-             SP value not its address.  It appears that the ARM isn't
-             doing this though.  */
-	  return read_memory_integer (get_frame_saved_regs (fi)[regnum],
-				      REGISTER_RAW_SIZE (regnum));
-	}
-    }
-  return read_register (regnum);
+  int reg;
+  struct arm_prologue_cache *cache;
+  CORE_ADDR unwound_fp;
+
+  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  cache->unwound_pc = frame_pc_unwind (next_frame);
+  arm_scan_prologue (next_frame, cache);
+
+  unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+  if (unwound_fp == 0)
+    return cache;
+
+  cache->unwound_sp = unwound_fp + cache->framesize - cache->frameoffset;
+
+  /* Calculate actual addresses of saved registers using offsets
+     determined by arm_scan_prologue.  */
+  for (reg = 0; reg < NUM_REGS; reg++)
+    if (cache->saved_regs[reg].addr != 0)
+      cache->saved_regs[reg].addr += cache->unwound_sp;
+
+  return cache;
 }
-/* Function: frame_chain Given a GDB frame, determine the address of
-   the calling function's frame.  This will be used to create a new
-   GDB frame struct, and then DEPRECATED_INIT_EXTRA_FRAME_INFO and
-   DEPRECATED_INIT_FRAME_PC will be called for the new frame.  For
-   ARM, we save the frame size when we initialize the frame_info.  */
 
-CORE_ADDR
-arm_minimal_frame_chain (struct frame_info *next_frame, struct arm_prologue_cache *cache)
+/* Our frame ID for a normal frame is the current function's starting PC
+   and the caller's SP when we were called.  */
+
+static void
+arm_prologue_this_id (struct frame_info *next_frame,
+		      void **this_cache,
+		      struct frame_id *this_id)
 {
-  CORE_ADDR caller_pc;
-  int framereg = arm_get_cache (next_frame)->framereg;
+  struct arm_prologue_cache *cache;
+  struct frame_id id;
+  CORE_ADDR func;
 
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-    return get_frame_base (next_frame);
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
+
+  func = frame_func_unwind (next_frame);
+
+  /* This is meant to halt the backtrace at "_start".  Make sure we
+     don't halt it at a generic dummy frame. */
+  if (func <= LOWEST_PC || inside_entry_file (func))
+    return;
 
-  if (get_frame_pc (next_frame) < LOWEST_PC)
-    return 0;
+  /* If we've hit a wall, stop.  */
+  if (cache->unwound_sp == 0)
+    return;
+
+  id = frame_id_build (cache->unwound_sp, func);
 
-  caller_pc = cache->unwound_pc;
+  /* Check that we're not going round in circles with the same frame
+     ID (but avoid applying the test to sentinel frames which do go
+     round in circles).  */
+  if (frame_relative_level (next_frame) >= 0
+      && get_frame_type (next_frame) == NORMAL_FRAME
+      && frame_id_eq (get_frame_id (next_frame), id))
+    return;
 
-  /* If the caller is Thumb and the caller is ARM, or vice versa,
-     the frame register of the caller is different from ours.
-     So we must scan the prologue of the caller to determine its
-     frame register number.  */
-  /* XXX Fixme, we should try to do this without creating a temporary
-     cache!  */
-  /* NOTE drow/2003-06-26: I'm quite suspicious of this code... what is it
-     really doing?  I have the feeling that it's trying to handle the case
-     where my framereg is ARM_FP_REGNUM, and my (Thumb) caller's framereg is
-     THUMB_FP_REGNUM, and switching between the two.  But the unwinder should
-     be taking care of that.  */
-  if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (get_frame_pc (next_frame)))
-    {
-      struct arm_prologue_cache *cache
-	= xcalloc (1, sizeof (struct arm_prologue_cache)
-		   + (NUM_REGS + NUM_PSEUDO_REGS - 1) * sizeof (CORE_ADDR));
-      struct cleanup *old_chain = make_cleanup (xfree, cache);
-
-      /* Now, scan the prologue and obtain the frame register.  */
-      cache->unwound_pc = caller_pc;
-      arm_scan_prologue (cache);
-      framereg = cache->framereg;
-
-      /* Deallocate the storage associated with the temporary frame
-	 created above.  */
-      do_cleanups (old_chain);
-    }
-
-  /* If the caller used a frame register, return its value.
-     Otherwise, return the caller's stack pointer.  */
-  if (framereg == ARM_FP_REGNUM || framereg == THUMB_FP_REGNUM)
-    return arm_find_callers_reg (next_frame, framereg);
-  else
-    /* FIXME drow/2003-06-26: The next frame is an opaque thing at this point,
-       we should only be using frame methods on it.  What if it's a dummy
-       frame, calling a frameless function (framereg == ARM_SP_REGNUM)?  Test
-       it.  */
-    return get_frame_base (next_frame) + arm_get_cache (next_frame)->framesize;
-}
-
-/* This function actually figures out the frame address for a given pc
-   and sp.  This is tricky because we sometimes don't use an explicit
-   frame pointer, and the previous stack pointer isn't necessarily
-   recorded on the stack.  The only reliable way to get this info is
-   to examine the prologue.  */
+  *this_id = id;
+}
 
 static void
-arm_minimal_frame_info (struct frame_info *next_frame,
-			struct arm_prologue_cache *cache)
+arm_prologue_prev_register (struct frame_info *next_frame,
+			    void **this_cache,
+			    int prev_regnum,
+			    int *optimized,
+			    enum lval_type *lvalp,
+			    CORE_ADDR *addrp,
+			    int *realnump,
+			    void *valuep)
 {
-  int reg;
-  CORE_ADDR sp;
+  struct arm_prologue_cache *cache;
 
-  memset (cache->saved_regs, '\000', sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS));
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
+
+  /* If we are asked to unwind the PC, then we need to return the LR instead.
+     The saved value of PC points into this frame's prologue, not the
+     next frame's resume location.  */
+  if (prev_regnum == ARM_PC_REGNUM)
+    prev_regnum = ARM_LR_REGNUM;
+
+  /* If someone asks for the stack pointer, then they want unwound_sp,
+     which was our stack pointer at the time of the call.  SP is not
+     generally saved to the stack.  */
+  if (prev_regnum == ARM_SP_REGNUM)
+    {
+      *lvalp = not_lval;
+      if (valuep)
+	store_unsigned_integer (valuep, 4, cache->unwound_sp);
+      return;
+    }
 
-  /* Compute stack pointer for this frame.  We use this value for both
-     the sigtramp and call dummy cases.  */
+  trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+			    optimized, lvalp, addrp, realnump, valuep);
+}
 
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-    /* For generic dummy frames, pull the value direct from the frame.
-       Having an unwind function to do this would be nice.  */
-    sp = deprecated_read_register_dummy (get_frame_pc (next_frame),
-					 get_frame_base (next_frame),
-					 ARM_SP_REGNUM);
-  else if (arm_get_cache (next_frame))
-    sp = (get_frame_base (next_frame)
-	  - arm_get_cache (next_frame)->frameoffset
-	  + arm_get_cache (next_frame)->framesize);
-  else
-    sp = read_sp ();  /* FIXME remove case */
-
-  /* Determine whether or not we're in a sigtramp frame.
-     Unfortunately, it isn't sufficient to test (get_frame_type (fi)
-     == SIGTRAMP_FRAME) because this value is sometimes set after
-     invoking DEPRECATED_INIT_EXTRA_FRAME_INFO.  So we test *both*
-     (get_frame_type (fi) == SIGTRAMP_FRAME) and PC_IN_SIGTRAMP to
-     determine if we need to use the sigcontext addresses for the
-     saved registers.
+struct frame_unwind arm_prologue_unwind = {
+  NORMAL_FRAME,
+  arm_prologue_this_id,
+  arm_prologue_prev_register
+};
 
-     Note: If an ARM PC_IN_SIGTRAMP method ever needs to compare
-     against the name of the function, the code below will have to be
-     changed to first fetch the name of the function and then pass
-     this name to PC_IN_SIGTRAMP.  */
+static const struct frame_unwind *
+arm_prologue_unwind_p (CORE_ADDR pc)
+{
+  return &arm_prologue_unwind;
+}
 
-  /* FIXME: cagney/2002-11-18: This problem will go away once
-     frame.c:get_prev_frame() is modified to set the frame's type
-     before calling functions like this.  */
-
-  /* NOTE drow/2003-06-26: This will move to a predicate for a different unwinder shortly.  */
-
-  if (SIGCONTEXT_REGISTER_ADDRESS_P () 
-      && PC_IN_SIGTRAMP (cache->unwound_pc, (char *)0))
-    {
-      for (reg = 0; reg < NUM_REGS; reg++)
-	cache->saved_regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, cache->unwound_pc, reg);
-
-      /* FIXME: What about thumb mode?  */
-      cache->framereg = ARM_SP_REGNUM;
-      cache->unwound_sp = read_memory_integer (cache->saved_regs[cache->framereg], REGISTER_RAW_SIZE (cache->framereg));
-      cache->framesize = 0;
-      cache->frameoffset = 0;
-    }
-  else
-    {
-      /* At this point, the unwound sp is just the result of frame_chain.
-	 Then it gets changed below.  */
-
-      arm_scan_prologue (cache);
-
-      if (!next_frame)
-	/* This is the innermost frame?  */
-	cache->unwound_sp = read_register (cache->framereg);
-      else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-	/* Next inner most frame is a dummy, just grab its frame.
-           Dummy frames always have the same FP as their caller.  */
-	cache->unwound_sp = get_frame_base (next_frame);
-      else if (cache->framereg == ARM_FP_REGNUM
-	       || cache->framereg == THUMB_FP_REGNUM)
-	{
-	  /* not the innermost frame */
-	  /* If we have an FP, the callee saved it.  */
-	  if (get_frame_saved_regs (next_frame) /**/ && get_frame_saved_regs (next_frame)[cache->framereg] != 0)
-	    cache->unwound_sp = read_memory_integer (get_frame_saved_regs (next_frame)[cache->framereg], 4);
-	  else if (frame_relative_level (next_frame) == 0
-		   && FRAMELESS_FUNCTION_INVOCATION (next_frame))
-	    /* If we were called by a frameless fn.  then our frame is
-	       still in the frame pointer register on the board...  */
-	    cache->unwound_sp = deprecated_read_fp ();
-	}
-
-      /* Calculate actual addresses of saved registers using offsets
-         determined by arm_scan_prologue.  */
-      for (reg = 0; reg < NUM_REGS; reg++)
-	if (cache->saved_regs[reg] != 0)
-	  cache->saved_regs[reg] = (cache->saved_regs[reg]
-				    + cache->unwound_sp
-				    + cache->framesize
-				    - cache->frameoffset);
-    }
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+{
+  struct arm_prologue_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
+
+  return cache->unwound_sp + cache->frameoffset - cache->framesize;
 }
 
+struct frame_base arm_normal_base = {
+  &arm_prologue_unwind,
+  arm_normal_frame_base,
+  arm_normal_frame_base,
+  arm_normal_frame_base
+};
+
 static struct arm_prologue_cache *
-arm_make_prologue_cache (struct frame_info *next_frame)
+arm_make_sigtramp_cache (struct frame_info *next_frame)
 {
   struct arm_prologue_cache *cache;
+  int reg;
 
-  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)
-				+ sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS - 1));
+  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
 
   cache->unwound_pc = frame_pc_unwind (next_frame);
-  if (frame_relative_level (next_frame) < 0)
-    cache->unwound_sp = deprecated_read_fp ();
-  else
-    cache->unwound_sp = arm_minimal_frame_chain (next_frame, cache);
-  arm_minimal_frame_info (next_frame, cache);
+  cache->unwound_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
+
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  for (reg = 0; reg < NUM_REGS; reg++)
+    cache->saved_regs[reg].addr
+      = SIGCONTEXT_REGISTER_ADDRESS (cache->unwound_sp, cache->unwound_pc,
+				     reg);
+
+  /* FIXME: What about thumb mode?  */
+  cache->framereg = ARM_SP_REGNUM;
+  cache->unwound_sp = read_memory_integer (cache->saved_regs[cache->framereg].addr, REGISTER_RAW_SIZE (cache->framereg));
 
   return cache;
 }
 
-static CORE_ADDR
-arm_frame_chain (struct frame_info *next_frame)
+static void
+arm_sigtramp_this_id (struct frame_info *next_frame,
+		      void **this_cache,
+		      struct frame_id *this_id)
 {
   struct arm_prologue_cache *cache;
 
-  cache = arm_make_prologue_cache (next_frame);
-  return cache->unwound_sp;
+  if (*this_cache == NULL)
+    *this_cache = arm_make_sigtramp_cache (next_frame);
+  cache = *this_cache;
+
+  *this_id = frame_id_build (cache->unwound_sp, cache->unwound_pc);
 }
 
 static void
-arm_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+arm_sigtramp_prev_register (struct frame_info *next_frame,
+			    void **this_cache,
+			    int prev_regnum,
+			    int *optimized,
+			    enum lval_type *lvalp,
+			    CORE_ADDR *addrp,
+			    int *realnump,
+			    void *valuep)
 {
   struct arm_prologue_cache *cache;
 
-  cache = arm_make_prologue_cache (deprecated_get_next_frame_hack (fi));
+  if (*this_cache == NULL)
+    *this_cache = arm_make_sigtramp_cache (next_frame);
+  cache = *this_cache;
+
+  trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+			    optimized, lvalp, addrp, realnump, valuep);
+}
 
-  if (get_frame_saved_regs (fi) == NULL)
-    frame_saved_regs_zalloc (fi);
+struct frame_unwind arm_sigtramp_unwind = {
+  NORMAL_FRAME,
+  arm_sigtramp_this_id,
+  arm_sigtramp_prev_register
+};
 
-  frame_extra_info_zalloc (fi, (sizeof (struct arm_prologue_cache)
-				+ ((NUM_REGS + NUM_PSEUDO_REGS - 1)
-				   * sizeof (CORE_ADDR))));
+static const struct frame_unwind *
+arm_sigtramp_unwind_p (CORE_ADDR pc)
+{
+  /* Note: If an ARM PC_IN_SIGTRAMP method ever needs to compare
+     against the name of the function, the code below will have to be
+     changed to first fetch the name of the function and then pass
+     this name to PC_IN_SIGTRAMP.  */
 
-  memcpy (get_frame_extra_info (fi), cache,  (sizeof (struct arm_prologue_cache)
-					      + ((NUM_REGS + NUM_PSEUDO_REGS - 1)
-						 * sizeof (CORE_ADDR))));
-  memcpy (get_frame_saved_regs (fi), cache->saved_regs,
-	  (NUM_REGS + NUM_PSEUDO_REGS - 1) * sizeof (CORE_ADDR));
-}
+  if (SIGCONTEXT_REGISTER_ADDRESS_P () && PC_IN_SIGTRAMP (pc, (char *) 0))
+    return &arm_sigtramp_unwind;
 
-/* Find the caller of this frame.  We do this by seeing if ARM_LR_REGNUM
-   is saved in the stack anywhere, otherwise we get it from the
-   registers.
+  return NULL;
+}
 
-   The old definition of this function was a macro:
-   #define FRAME_SAVED_PC(FRAME) \
-   ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+   dummy frame.  The frame ID's base needs to match the TOS value
+   saved by save_dummy_frame_tos(), and the PC match the dummy frame's
+   breakpoint.  */
 
-static CORE_ADDR
-arm_frame_saved_pc (struct frame_info *fi)
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  /* If a dummy frame, pull the PC out of the frame's register buffer.  */
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
-    return deprecated_read_register_dummy (get_frame_pc (fi),
-					   get_frame_base (fi), ARM_PC_REGNUM);
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi),
-				   (get_frame_base (fi)
-				    - arm_get_cache (fi)->frameoffset),
-				   get_frame_base (fi)))
-    {
-      return read_memory_integer (get_frame_saved_regs (fi)[ARM_PC_REGNUM],
-				  REGISTER_RAW_SIZE (ARM_PC_REGNUM));
-    }
-  else
-    {
-      CORE_ADDR pc = arm_find_callers_reg (fi, ARM_LR_REGNUM);
-      return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
-    }
+  return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+			 frame_pc_unwind (next_frame));
 }
 
-/* Return the frame address.  On ARM, it is R11; on Thumb it is R7.
-   Examine the Program Status Register to decide which state we're in.  */
+/* Given THIS_FRAME, find the frame's resume PC (which will be part of the
+   frame ID for THIS_FRAME's caller's frame).  */
 
 static CORE_ADDR
-arm_read_fp (void)
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
-  if (read_register (ARM_PS_REGNUM) & 0x20)	/* Bit 5 is Thumb state bit */
-    return read_register (THUMB_FP_REGNUM);	/* R7 if Thumb */
-  else
-    return read_register (ARM_FP_REGNUM);	/* R11 if ARM */
+  CORE_ADDR pc;
+  pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+  return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
 }
 
-/* Store into a struct frame_saved_regs the addresses of the saved
-   registers of frame described by FRAME_INFO.  This includes special
-   registers such as PC and FP saved in special ways in the stack
-   frame.  SP is even more special: the address we return for it IS
-   the sp for the next frame.  */
-
-static void
-arm_frame_init_saved_regs (struct frame_info *fip)
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
-
-  if (get_frame_saved_regs (fip))
-    return;
-
-  arm_init_extra_frame_info (0, fip);
+  return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
 }
 
 /* Set the return address for a generic dummy frame.  ARM uses the
@@ -1359,40 +1315,6 @@ arm_fix_call_dummy (char *dummy, CORE_AD
   write_register (4, fun);
 }
 
-/* Pop the current frame.  So long as the frame info has been
-   initialized properly (see arm_init_extra_frame_info), this code
-   works for dummy frames as well as regular frames.  I.e, there's no
-   need to have a special case for dummy frames.  */
-static void
-arm_pop_frame (void)
-{
-  int regnum;
-  struct frame_info *frame = get_current_frame ();
-  CORE_ADDR old_SP = (get_frame_base (frame)
-		      - arm_get_cache (frame)->frameoffset
-		      + arm_get_cache (frame)->framesize);
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
-				   get_frame_base (frame),
-				   get_frame_base (frame)))
-    {
-      generic_pop_dummy_frame ();
-      flush_cached_frames ();
-      return;
-    }
-
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
-    if (get_frame_saved_regs (frame)[regnum] != 0)
-      write_register (regnum,
-		  read_memory_integer (get_frame_saved_regs (frame)[regnum],
-				       REGISTER_RAW_SIZE (regnum)));
-
-  write_register (ARM_PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame));
-  write_register (ARM_SP_REGNUM, old_SP);
-
-  flush_cached_frames ();
-}
-
 /* When arguments must be pushed onto the stack, they go on in reverse
    order.  The code below implements a FILO (stack) to do this.  */
 
@@ -2873,10 +2795,6 @@ arm_gdbarch_init (struct gdbarch_info in
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
-     ready to unwind the PC first (see frame.c:get_prev_frame()).  */
-  set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
   /* We used to default to FPA for generic ARM, but almost nobody uses that
      now, and we now provide a way for the user to force the model.  So 
      default to the most useful variant.  */
@@ -2919,16 +2837,15 @@ arm_gdbarch_init (struct gdbarch_info in
   set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
 
   /* Frame handling.  */
-  set_gdbarch_deprecated_frame_chain_valid (gdbarch, arm_frame_chain_valid);
-  set_gdbarch_deprecated_init_extra_frame_info (gdbarch, arm_init_extra_frame_info);
-  set_gdbarch_deprecated_target_read_fp (gdbarch, arm_read_fp);
-  set_gdbarch_deprecated_frame_chain (gdbarch, arm_frame_chain);
+  set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+  set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
+
   set_gdbarch_frameless_function_invocation
     (gdbarch, arm_frameless_function_invocation);
-  set_gdbarch_deprecated_frame_saved_pc (gdbarch, arm_frame_saved_pc);
   set_gdbarch_frame_args_skip (gdbarch, 0);
-  set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs);
-  set_gdbarch_deprecated_pop_frame (gdbarch, arm_pop_frame);
+
+  frame_base_set_default (gdbarch, &arm_normal_base);
 
   /* Address manipulation.  */
   set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
@@ -2996,6 +2913,10 @@ arm_gdbarch_init (struct gdbarch_info in
   /* Hook in the ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
+  /* Add some default predicates.  */
+  frame_unwind_append_predicate (gdbarch, arm_sigtramp_unwind_p);
+  frame_unwind_append_predicate (gdbarch, arm_prologue_unwind_p);
+
   /* Now we have tuned the configuration, set a few final things,
      based on what the OS ABI has told us.  */
 
Index: gdb/Makefile.in
===================================================================
--- gdb.orig/Makefile.in	2003-06-30 18:28:17.000000000 -0400
+++ gdb/Makefile.in	2003-06-30 18:28:57.000000000 -0400
@@ -1566,7 +1566,8 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame
 	$(gdbcore_h) $(symfile_h) $(gdb_string_h) $(dis_asm_h) $(regcache_h) \
 	$(doublest_h) $(value_h) $(arch_utils_h) $(osabi_h) \
 	$(arm_tdep_h) $(sim_arm_h) $(elf_bfd_h) $(coff_internal_h) \
-	$(elf_arm_h) $(gdb_assert_h)
+	$(elf_arm_h) $(gdb_assert_h) $(frame_unwind_h) $(trad_frame_h) \
+	$(frame_base_h)
 armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(arm_tdep_h) $(inferior_h) \
 	$(regcache_h) $(gdbcore_h)
 armnbsd-tdep.o: armnbsd-tdep.c $(defs_h) $(arm_tdep_h) $(nbsd_tdep_h) \
Index: gdb/varobj.c
===================================================================
--- gdb.orig/varobj.c	2003-06-30 18:28:07.000000000 -0400
+++ gdb/varobj.c	2003-06-30 18:28:57.000000000 -0400
@@ -412,7 +412,7 @@ find_frame_addr_in_frame_chain (CORE_ADD
       frame = get_prev_frame (frame);
       if (frame == NULL)
 	return NULL;
-      if (get_frame_base (frame) == frame_addr)
+      if (get_frame_base_address (frame) == frame_addr)
 	return frame;
     }
 }


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