diff options
author | Daniel Jacobowitz <drow@false.org> | 2003-09-03 20:46:02 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2003-09-03 20:46:02 +0000 |
commit | eb5492fa14c7748db0c9558922ef94e0bf500015 (patch) | |
tree | d8ed24d9678439450c5bf3f14c453cd35e39e279 /gdb/arm-tdep.c | |
parent | 24de872b6ff8cb2ff55e61013eba440f9fc4a98a (diff) | |
download | gdb-eb5492fa14c7748db0c9558922ef94e0bf500015.zip gdb-eb5492fa14c7748db0c9558922ef94e0bf500015.tar.gz gdb-eb5492fa14c7748db0c9558922ef94e0bf500015.tar.bz2 |
* 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_sniffer)
(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_sniffer)
(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.
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r-- | gdb/arm-tdep.c | 576 |
1 files changed, 248 insertions, 328 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 411d7d6..d54b956 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -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 struct floatformat *, const void *, 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_cache *cache) 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_cache *cache) 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_cache *cache) 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_cache *cache) */ 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_cache *cache) 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_cache *cache) 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_cache *cache) } 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_cache *cache) } } + 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_cache *cache) 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_cache *cache) { 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_cache *cache) 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,253 @@ arm_scan_prologue (struct arm_prologue_cache *cache) 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; - - /* 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); - } + cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset; - /* 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; + /* 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; } -/* 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. */ +/* 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; - - memset (cache->saved_regs, '\000', sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS)); - - /* Compute stack pointer for this frame. We use this value for both - the sigtramp and call dummy cases. */ - - 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 */ + struct arm_prologue_cache *cache; + struct frame_id id; + CORE_ADDR func; - /* 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. + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; - 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. */ + func = frame_func_unwind (next_frame); - /* 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. */ + /* 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; - /* NOTE drow/2003-06-26: This will move to a predicate for a different unwinder shortly. */ + /* If we've hit a wall, stop. */ + if (cache->prev_sp == 0) + return; - 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 (); - } + id = frame_id_build (cache->prev_sp, func); - /* 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); - } + /* 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; + + *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; - 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); + /* 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; - return cache; + /* 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; + } + + trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum, + optimized, lvalp, addrp, realnump, valuep); +} + +struct frame_unwind arm_prologue_unwind = { + NORMAL_FRAME, + arm_prologue_this_id, + arm_prologue_prev_register +}; + +static const struct frame_unwind * +arm_prologue_unwind_sniffer (struct frame_info *next_frame) +{ + 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 = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)); - cache = arm_make_prologue_cache (deprecated_get_next_frame_hack (fi)); + cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM); - if (get_frame_saved_regs (fi) == NULL) - frame_saved_regs_zalloc (fi); + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - frame_extra_info_zalloc (fi, (sizeof (struct arm_prologue_cache) - + ((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); - 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)); + /* 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; -static CORE_ADDR -arm_frame_saved_pc (struct frame_info *fi) + /* 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 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_sniffer (struct frame_info *next_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 */ + /* 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 (frame_pc_unwind (next_frame), (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). */ - arm_init_extra_frame_info (0, fip); +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; +} + +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 +1314,6 @@ arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, 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 +2794,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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 +2836,15 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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 +2912,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Hook in the ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); + /* Add some default predicates. */ + frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer); + frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer); + /* Now we have tuned the configuration, set a few final things, based on what the OS ABI has told us. */ |