This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFA/ARM] Framificate the ARM port [3/3]
- From: Daniel Jacobowitz <drow at mvista dot com>
- To: gdb-patches at sources dot redhat dot com, rearnsha at arm dot com
- Date: Mon, 7 Jul 2003 10:23:26 -0400
- Subject: Re: [RFA/ARM] Framificate the ARM port [3/3]
- References: <20030630225509.GA30844@nevyn.them.org>
On Mon, Jun 30, 2003 at 06:55:09PM -0400, Daniel Jacobowitz wrote:
> 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.
Here is an updated version of the patch. Changes:
- Comment updates, mostly suggested by Andrew
- Removal of the unwound_pc cache, also suggested by Andrew
- Renamed unwound_sp to prev_sp, also suggested by Andrew
- Fixed the type of sigtramp frames to be SIGTRAMP_FRAME.
- One important change to the ARM prologue analyzer:
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
i.e. do not scan past the PC value. Fixes several test failures
involving signals on arm-linux, when we get a signal during the
prologue. The Thumb prologue analyzer already did this and it
looks like the ARM one used to.
- Removed an excess DEPRECATED_PC_IN_CALL_DUMMY in the Thumb
unwinder.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer
2003-07-07 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. Remove unwound_pc; rename unwound_sp
to prev_sp.
(thumb_scan_prologue): Update for cache changes. Don't call
DEPRECATED_PC_IN_CALL_DUMMY.
(arm_scan_prologue): Update for cache changes. Take NEXT_FRAME
argument and use it in desperation search for our prologue. Do not
search past the specified PC.
(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.
* std-regs.c (value_of_builtin_frame_fp_reg): Likewise.
Index: gdb/arm-tdep.c
===================================================================
--- gdb.orig/arm-tdep.c 2003-07-07 09:15:38.000000000 -0400
+++ gdb/arm-tdep.c 2003-07-07 10:00:51.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,26 @@ 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. the
+ caller's stack pointer when this function was called. It is used
+ to identify this frame. */
+ CORE_ADDR prev_sp;
+
+ /* The frame base for this frame is just prev_sp + frame offset -
+ frame size. FRAMESIZE is the size of this stack frame, and
+ FRAMEOFFSET if the initial offset from the stack pointer (this
+ frame's stack pointer, not PREV_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 +186,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;
@@ -506,7 +508,6 @@ arm_skip_prologue (CORE_ADDR pc)
2) which registers are saved on it
3) the offsets of saved regs
4) the offset from the stack pointer to the frame pointer
- This information is stored in the "extra" fields of the frame_info.
A typical Thumb function prologue would create this stack frame
(offsets relative to FP)
@@ -523,7 +524,7 @@ arm_skip_prologue (CORE_ADDR pc)
/* *INDENT-ON* */
static void
-thumb_scan_prologue (struct arm_prologue_cache *cache)
+thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
{
CORE_ADDR prologue_start;
CORE_ADDR prologue_end;
@@ -538,16 +539,12 @@ thumb_scan_prologue (struct arm_prologue
int findmask = 0;
int i;
- /* Don't try to scan dummy frames. */
- if (DEPRECATED_PC_IN_CALL_DUMMY (cache->unwound_pc, 0, 0))
- return;
-
- if (find_pc_partial_function (cache->unwound_pc, NULL, &prologue_start, &prologue_end))
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
if (sal.line == 0) /* no line info, use current PC */
- prologue_end = cache->unwound_pc;
+ prologue_end = prev_pc;
else if (sal.end < prologue_end) /* next line begins after fn end */
prologue_end = sal.end; /* (probably means no prologue) */
}
@@ -556,7 +553,7 @@ thumb_scan_prologue (struct arm_prologue
16 pushes, an add, and "mv fp,sp". */
prologue_end = prologue_start + 40;
- prologue_end = min (prologue_end, cache->unwound_pc);
+ prologue_end = min (prologue_end, prev_pc);
/* Initialize the saved register map. When register H is copied to
register L, we will put H in saved_reg[L]. */
@@ -591,7 +588,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,11 +705,11 @@ 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;
+ CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
/* Assume there is no frame until proven otherwise. */
cache->framereg = ARM_SP_REGNUM;
@@ -720,15 +717,15 @@ arm_scan_prologue (struct arm_prologue_c
cache->frameoffset = 0;
/* Check for Thumb prologue. */
- if (arm_pc_is_thumb (cache->unwound_pc))
+ if (arm_pc_is_thumb (prev_pc))
{
- thumb_scan_prologue (cache);
+ thumb_scan_prologue (prev_pc, cache);
return;
}
/* Find the function prologue. If we can't find the function in
the symbol table, peek in the stack frame to find the PC. */
- if (find_pc_partial_function (cache->unwound_pc, NULL, &prologue_start, &prologue_end))
+ if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
{
/* One way to find the end of the prologue (which works well
for unoptimized code) is to do the following:
@@ -736,7 +733,7 @@ arm_scan_prologue (struct arm_prologue_c
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
if (sal.line == 0)
- prologue_end = cache->unwound_pc;
+ prologue_end = prev_pc;
else if (sal.end < prologue_end)
prologue_end = sal.end;
@@ -769,9 +766,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
{
@@ -780,6 +784,9 @@ arm_scan_prologue (struct arm_prologue_c
}
}
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
+
/* Now search the prologue looking for instructions that set up the
frame pointer, adjust the stack pointer, and save registers.
@@ -830,7 +837,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 +873,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 +900,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 +923,252 @@ 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);
-}
-/* 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. */
+ int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
-CORE_ADDR
-arm_minimal_frame_chain (struct frame_info *next_frame, struct arm_prologue_cache *cache)
-{
- CORE_ADDR caller_pc;
- int framereg = arm_get_cache (next_frame)->framereg;
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
- return get_frame_base (next_frame);
+ arm_scan_prologue (next_frame, cache);
- if (get_frame_pc (next_frame) < LOWEST_PC)
- return 0;
+ unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+ if (unwound_fp == 0)
+ return cache;
- caller_pc = cache->unwound_pc;
+ cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
- /* 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. */
+ /* 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->prev_sp;
+
+ return 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_minimal_frame_info (struct frame_info *next_frame,
- struct arm_prologue_cache *cache)
+arm_prologue_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
{
- int reg;
- CORE_ADDR sp;
+ struct arm_prologue_cache *cache;
+ struct frame_id id;
+ CORE_ADDR func;
- 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;
+
+ 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;
- /* Compute stack pointer for this frame. We use this value for both
- the sigtramp and call dummy cases. */
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return;
- 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.
+ id = frame_id_build (cache->prev_sp, func);
- 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. */
+ /* 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;
- /* 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);
- }
+ *this_id = id;
}
-static struct arm_prologue_cache *
-arm_make_prologue_cache (struct frame_info *next_frame)
+static void
+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)
{
struct arm_prologue_cache *cache;
- cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)
- + sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS - 1));
+ 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;
+
+ /* SP is generally not saved to the stack, but this frame is
+ identified by NEXT_FRAME's stack pointer at the time of the call.
+ The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
+ {
+ *lvalp = not_lval;
+ if (valuep)
+ store_unsigned_integer (valuep, 4, cache->prev_sp);
+ return;
+ }
- 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);
+ trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
+}
- return cache;
+struct frame_unwind arm_prologue_unwind = {
+ NORMAL_FRAME,
+ arm_prologue_this_id,
+ arm_prologue_prev_register
+};
+
+static const struct frame_unwind *
+arm_prologue_unwind_p (CORE_ADDR pc)
+{
+ return &arm_prologue_unwind;
}
static CORE_ADDR
-arm_frame_chain (struct frame_info *next_frame)
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
{
struct arm_prologue_cache *cache;
- cache = arm_make_prologue_cache (next_frame);
- return cache->unwound_sp;
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ return cache->prev_sp + cache->frameoffset - cache->framesize;
}
-static void
-arm_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+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_sigtramp_cache (struct frame_info *next_frame)
{
struct arm_prologue_cache *cache;
+ int reg;
- cache = arm_make_prologue_cache (deprecated_get_next_frame_hack (fi));
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
- if (get_frame_saved_regs (fi) == NULL)
- frame_saved_regs_zalloc (fi);
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
- frame_extra_info_zalloc (fi, (sizeof (struct arm_prologue_cache)
- + ((NUM_REGS + NUM_PSEUDO_REGS - 1)
- * sizeof (CORE_ADDR))));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- 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));
+ for (reg = 0; reg < NUM_REGS; reg++)
+ cache->saved_regs[reg].addr
+ = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
+ frame_pc_unwind (next_frame), reg);
+
+ /* FIXME: What about thumb mode? */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->prev_sp
+ = read_memory_integer (cache->saved_regs[cache->framereg].addr,
+ REGISTER_RAW_SIZE (cache->framereg));
+
+ return cache;
}
-/* 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.
+static void
+arm_sigtramp_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
- The old definition of this function was a macro:
- #define FRAME_SAVED_PC(FRAME) \
- ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
+
+ /* FIXME drow/2003-07-07: This isn't right if we single-step within
+ the sigtramp frame; the PC should be the beginning of the trampoline. */
+ *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
+}
-static CORE_ADDR
-arm_frame_saved_pc (struct frame_info *fi)
+static void
+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)
{
- /* 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);
+ struct arm_prologue_cache *cache;
- 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;
- }
+ 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);
}
-/* 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. */
+struct frame_unwind arm_sigtramp_unwind = {
+ SIGTRAMP_FRAME,
+ arm_sigtramp_this_id,
+ arm_sigtramp_prev_register
+};
-static CORE_ADDR
-arm_read_fp (void)
+static const struct frame_unwind *
+arm_sigtramp_unwind_p (CORE_ADDR pc)
{
- 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 */
+ /* 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. */
+
+ if (SIGCONTEXT_REGISTER_ADDRESS_P () && PC_IN_SIGTRAMP (pc, (char *) 0))
+ return &arm_sigtramp_unwind;
+
+ return NULL;
}
-/* 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. */
+/* 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 returned from
+ arm_push_dummy_call, and the PC needs to match the dummy frame's
+ breakpoint. */
-static void
-arm_frame_init_saved_regs (struct frame_info *fip)
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
+ return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
- if (get_frame_saved_regs (fip))
- return;
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+ be used to construct the previous frame's ID, after looking up the
+ containing function). */
+
+static CORE_ADDR
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+ return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+}
- arm_init_extra_frame_info (0, fip);
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
}
/* Set the return address for a generic dummy frame. ARM uses the
@@ -1359,40 +1313,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 +2793,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 +2835,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 +2911,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-07-03 09:43:47.000000000 -0400
+++ gdb/Makefile.in 2003-07-07 09:15:39.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-07-03 09:43:47.000000000 -0400
+++ gdb/varobj.c 2003-07-07 09:15:39.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: gdb/std-regs.c
===================================================================
--- gdb.orig/std-regs.c 2003-06-08 14:27:14.000000000 -0400
+++ gdb/std-regs.c 2003-07-07 09:48:01.000000000 -0400
@@ -90,7 +90,7 @@ value_of_builtin_frame_fp_reg (struct fr
memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0);
else
ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf,
- get_frame_base (frame));
+ get_frame_base_address (frame));
return val;
}
}