diff options
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r-- | gdb/arm-tdep.c | 593 |
1 files changed, 280 insertions, 313 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 3f2f13c3bb6..3ba072d1ff8 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,17 +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). */ - -struct frame_extra_info +struct arm_prologue_cache { + /* 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; + + /* Saved register offsets. */ + struct trad_frame_saved_reg *saved_regs; }; /* Addresses for calling Thumb functions have the bit 0 set. @@ -174,12 +186,6 @@ struct frame_extra_info #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; @@ -502,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) @@ -519,7 +524,7 @@ arm_skip_prologue (CORE_ADDR pc) /* *INDENT-ON* */ static void -thumb_scan_prologue (struct frame_info *fi) +thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache) { CORE_ADDR prologue_start; CORE_ADDR prologue_end; @@ -534,17 +539,12 @@ thumb_scan_prologue (struct frame_info *fi) int findmask = 0; int i; - /* Don't try to scan dummy frames. */ - if (fi != NULL - && DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0)) - return; - - if (find_pc_partial_function (get_frame_pc (fi), 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 = get_frame_pc (fi); + prologue_end = prev_pc; else if (sal.end < prologue_end) /* next line begins after fn end */ prologue_end = sal.end; /* (probably means no prologue) */ } @@ -553,7 +553,7 @@ thumb_scan_prologue (struct frame_info *fi) 16 pushes, an add, and "mv fp,sp". */ prologue_end = prologue_start + 40; - prologue_end = min (prologue_end, get_frame_pc (fi)); + 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]. */ @@ -564,7 +564,7 @@ thumb_scan_prologue (struct frame_info *fi) frame pointer, adjust the stack pointer, and save registers. Do this until all basic prolog instructions are found. */ - get_frame_extra_info (fi)->framesize = 0; + cache->framesize = 0; for (current_pc = prologue_start; (current_pc < prologue_end) && ((findmask & 7) != 7); current_pc += 2) @@ -587,9 +587,8 @@ thumb_scan_prologue (struct frame_info *fi) for (regno = ARM_LR_REGNUM; regno >= 0; regno--) if (mask & (1 << regno)) { - get_frame_extra_info (fi)->framesize += 4; - get_frame_saved_regs (fi)[saved_reg[regno]] = - -(get_frame_extra_info (fi)->framesize); + cache->framesize += 4; + cache->saved_regs[saved_reg[regno]].addr = -cache->framesize; /* Reset saved register map. */ saved_reg[regno] = regno; } @@ -605,23 +604,23 @@ thumb_scan_prologue (struct frame_info *fi) offset = (insn & 0x7f) << 2; /* get scaled offset */ if (insn & 0x80) /* is it signed? (==subtracting) */ { - get_frame_extra_info (fi)->frameoffset += offset; + cache->frameoffset += offset; offset = -offset; } - get_frame_extra_info (fi)->framesize -= offset; + cache->framesize -= offset; } else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ { findmask |= 2; /* setting of r7 found */ - get_frame_extra_info (fi)->framereg = THUMB_FP_REGNUM; + cache->framereg = THUMB_FP_REGNUM; /* get scaled offset */ - get_frame_extra_info (fi)->frameoffset = (insn & 0xff) << 2; + cache->frameoffset = (insn & 0xff) << 2; } else if (insn == 0x466f) /* mov r7, sp */ { findmask |= 2; /* setting of r7 found */ - get_frame_extra_info (fi)->framereg = THUMB_FP_REGNUM; - get_frame_extra_info (fi)->frameoffset = 0; + cache->framereg = THUMB_FP_REGNUM; + cache->frameoffset = 0; saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM; } else if ((insn & 0xffc0) == 0x4640) /* mov r0-r7, r8-r15 */ @@ -706,27 +705,27 @@ thumb_scan_prologue (struct frame_info *fi) */ static void -arm_scan_prologue (struct frame_info *fi) +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. */ - get_frame_extra_info (fi)->framereg = ARM_SP_REGNUM; - get_frame_extra_info (fi)->framesize = 0; - get_frame_extra_info (fi)->frameoffset = 0; + cache->framereg = ARM_SP_REGNUM; + cache->framesize = 0; + cache->frameoffset = 0; /* Check for Thumb prologue. */ - if (arm_pc_is_thumb (get_frame_pc (fi))) + if (arm_pc_is_thumb (prev_pc)) { - thumb_scan_prologue (fi); + 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 (get_frame_pc (fi), 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: @@ -734,7 +733,7 @@ arm_scan_prologue (struct frame_info *fi) struct symtab_and_line sal = find_pc_line (prologue_start, 0); if (sal.line == 0) - prologue_end = get_frame_pc (fi); + prologue_end = prev_pc; else if (sal.end < prologue_end) prologue_end = sal.end; @@ -767,9 +766,16 @@ arm_scan_prologue (struct frame_info *fi) } 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 (get_frame_base (fi), 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 { @@ -778,6 +784,9 @@ arm_scan_prologue (struct frame_info *fi) } } + 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. @@ -828,7 +837,7 @@ arm_scan_prologue (struct frame_info *fi) if (mask & (1 << regno)) { sp_offset -= 4; - get_frame_saved_regs (fi)[regno] = sp_offset; + cache->saved_regs[regno].addr = sp_offset; } } else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */ @@ -851,7 +860,7 @@ arm_scan_prologue (struct frame_info *fi) unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ imm = (imm >> rot) | (imm << (32 - rot)); fp_offset = -imm; - get_frame_extra_info (fi)->framereg = ARM_FP_REGNUM; + cache->framereg = ARM_FP_REGNUM; } else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */ { @@ -864,7 +873,7 @@ arm_scan_prologue (struct frame_info *fi) { sp_offset -= 12; regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07); - get_frame_saved_regs (fi)[regno] = sp_offset; + cache->saved_regs[regno].addr = sp_offset; } else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */ { @@ -891,7 +900,7 @@ arm_scan_prologue (struct frame_info *fi) for (; fp_start_reg < fp_bound_reg; fp_start_reg++) { sp_offset -= 12; - get_frame_saved_regs (fi)[fp_start_reg++] = sp_offset; + cache->saved_regs[fp_start_reg++].addr = sp_offset; } } else if ((insn & 0xf0000000) != 0xe0000000) @@ -907,266 +916,260 @@ arm_scan_prologue (struct frame_info *fi) /* The frame size is just the negative of the offset (from the original SP) of the last thing thing we pushed on the stack. The frame offset is [new FP] - [new SP]. */ - get_frame_extra_info (fi)->framesize = -sp_offset; - if (get_frame_extra_info (fi)->framereg == ARM_FP_REGNUM) - get_frame_extra_info (fi)->frameoffset = fp_offset - sp_offset; + cache->framesize = -sp_offset; + if (cache->framereg == ARM_FP_REGNUM) + cache->frameoffset = fp_offset - sp_offset; else - get_frame_extra_info (fi)->frameoffset = 0; + 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); + + arm_scan_prologue (next_frame, cache); + + unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg); + if (unwound_fp == 0) + return cache; + + cache->prev_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->prev_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. */ -static CORE_ADDR -arm_frame_chain (struct frame_info *fi) +/* 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 = get_frame_extra_info (fi)->framereg; + struct arm_prologue_cache *cache; + struct frame_id id; + CORE_ADDR func; - if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0)) - /* A generic call dummy's frame is the same as caller's. */ - return get_frame_base (fi); + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; - if (get_frame_pc (fi) < LOWEST_PC) - return 0; + 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 || deprecated_inside_entry_file (func)) + return; - /* If the caller is the startup code, we're at the end of the chain. */ - caller_pc = DEPRECATED_FRAME_SAVED_PC (fi); + /* If we've hit a wall, stop. */ + if (cache->prev_sp == 0) + return; + + id = frame_id_build (cache->prev_sp, func); + + /* 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 - caller_fi. */ - if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (get_frame_pc (fi))) + *this_id = id; +} + +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; + + 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) { - struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); - struct frame_info *caller_fi = - deprecated_frame_xmalloc_with_cleanup (SIZEOF_FRAME_SAVED_REGS, - sizeof (struct frame_extra_info)); - - /* Now, scan the prologue and obtain the frame register. */ - deprecated_update_frame_pc_hack (caller_fi, caller_pc); - arm_scan_prologue (caller_fi); - framereg = get_frame_extra_info (caller_fi)->framereg; - - /* Deallocate the storage associated with the temporary frame - created above. */ - do_cleanups (old_chain); + *lvalp = not_lval; + if (valuep) + store_unsigned_integer (valuep, 4, cache->prev_sp); + return; } - /* 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 (fi, framereg); - else - return get_frame_base (fi) + get_frame_extra_info (fi)->framesize; + trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum, + optimized, lvalp, addrp, realnump, valuep); } -/* 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. FROMLEAF is a little confusing, it means - this is the next frame up the chain AFTER a frameless function. If - this is true, then the frame value for this frame is still in the - fp register. */ +struct frame_unwind arm_prologue_unwind = { + NORMAL_FRAME, + arm_prologue_this_id, + arm_prologue_prev_register +}; -static void -arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) +static const struct frame_unwind * +arm_prologue_unwind_sniffer (struct frame_info *next_frame) { - int reg; - CORE_ADDR sp; + return &arm_prologue_unwind; +} - if (get_frame_saved_regs (fi) == NULL) - frame_saved_regs_zalloc (fi); +static CORE_ADDR +arm_normal_frame_base (struct frame_info *next_frame, void **this_cache) +{ + struct arm_prologue_cache *cache; - frame_extra_info_zalloc (fi, sizeof (struct frame_extra_info)); + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; - get_frame_extra_info (fi)->framesize = 0; - get_frame_extra_info (fi)->frameoffset = 0; - get_frame_extra_info (fi)->framereg = 0; + return cache->prev_sp + cache->frameoffset - cache->framesize; +} - if (get_next_frame (fi)) - deprecated_update_frame_pc_hack (fi, DEPRECATED_FRAME_SAVED_PC (get_next_frame (fi))); +struct frame_base arm_normal_base = { + &arm_prologue_unwind, + arm_normal_frame_base, + arm_normal_frame_base, + arm_normal_frame_base +}; - memset (get_frame_saved_regs (fi), '\000', sizeof get_frame_saved_regs (fi)); +static struct arm_prologue_cache * +arm_make_sigtramp_cache (struct frame_info *next_frame) +{ + struct arm_prologue_cache *cache; + int reg; - /* Compute stack pointer for this frame. We use this value for both - the sigtramp and call dummy cases. */ - if (!get_next_frame (fi)) - sp = read_sp(); - else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (get_next_frame (fi)), 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 (get_next_frame (fi)), - get_frame_base (get_next_frame (fi)), - ARM_SP_REGNUM); - else - sp = (get_frame_base (get_next_frame (fi)) - - get_frame_extra_info (get_next_frame (fi))->frameoffset - + get_frame_extra_info (get_next_frame (fi))->framesize); - - /* 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. - - 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. */ + cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)); - /* 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. */ + cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM); - if (SIGCONTEXT_REGISTER_ADDRESS_P () - && ((get_frame_type (fi) == SIGTRAMP_FRAME) || PC_IN_SIGTRAMP (get_frame_pc (fi), (char *)0))) - { - for (reg = 0; reg < NUM_REGS; reg++) - get_frame_saved_regs (fi)[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, get_frame_pc (fi), reg); + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - /* FIXME: What about thumb mode? */ - get_frame_extra_info (fi)->framereg = ARM_SP_REGNUM; - deprecated_update_frame_base_hack (fi, read_memory_integer (get_frame_saved_regs (fi)[get_frame_extra_info (fi)->framereg], REGISTER_RAW_SIZE (get_frame_extra_info (fi)->framereg))); - get_frame_extra_info (fi)->framesize = 0; - get_frame_extra_info (fi)->frameoffset = 0; + for (reg = 0; reg < NUM_REGS; reg++) + cache->saved_regs[reg].addr + = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp, + frame_pc_unwind (next_frame), reg); - } - else - { - arm_scan_prologue (fi); - - if (!get_next_frame (fi)) - /* This is the innermost frame? */ - deprecated_update_frame_base_hack (fi, read_register (get_frame_extra_info (fi)->framereg)); - else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (get_next_frame (fi)), 0, 0)) - /* Next inner most frame is a dummy, just grab its frame. - Dummy frames always have the same FP as their caller. */ - deprecated_update_frame_base_hack (fi, get_frame_base (get_next_frame (fi))); - else if (get_frame_extra_info (fi)->framereg == ARM_FP_REGNUM - || get_frame_extra_info (fi)->framereg == THUMB_FP_REGNUM) - { - /* not the innermost frame */ - /* If we have an FP, the callee saved it. */ - if (get_frame_saved_regs (get_next_frame (fi))[get_frame_extra_info (fi)->framereg] != 0) - deprecated_update_frame_base_hack (fi, read_memory_integer (get_frame_saved_regs (get_next_frame (fi))[get_frame_extra_info (fi)->framereg], 4)); - else if (fromleaf) - /* If we were called by a frameless fn. then our frame is - still in the frame pointer register on the board... */ - deprecated_update_frame_base_hack (fi, deprecated_read_fp ()); - } + /* 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)); - /* Calculate actual addresses of saved registers using offsets - determined by arm_scan_prologue. */ - for (reg = 0; reg < NUM_REGS; reg++) - if (get_frame_saved_regs (fi)[reg] != 0) - get_frame_saved_regs (fi)[reg] - += (get_frame_base (fi) - + get_frame_extra_info (fi)->framesize - - get_frame_extra_info (fi)->frameoffset); - } + return cache; } +static void +arm_sigtramp_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct arm_prologue_cache *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. + if (*this_cache == NULL) + *this_cache = arm_make_sigtramp_cache (next_frame); + cache = *this_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)) */ + /* 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) - - get_frame_extra_info (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 @@ -1175,7 +1178,7 @@ arm_frame_init_saved_regs (struct frame_info *fip) static CORE_ADDR arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { - write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ()); + write_register (ARM_LR_REGNUM, entry_point_address ()); return sp; } @@ -1311,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) - - get_frame_extra_info (frame)->frameoffset - + get_frame_extra_info (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. */ @@ -1523,7 +1492,7 @@ static void arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args) { - register unsigned long status = read_register (ARM_FPS_REGNUM); + unsigned long status = read_register (ARM_FPS_REGNUM); int type; type = (status >> 24) & 127; @@ -2283,7 +2252,7 @@ static int arm_use_struct_convention (int gcc_p, struct type *type) { int nRc; - register enum type_code code; + enum type_code code; /* In the ARM ABI, "integer" like aggregate types are returned in registers. For an aggregate type to be integer like, its size @@ -2825,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. */ @@ -2871,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); @@ -2948,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. */ @@ -3024,8 +2992,7 @@ _initialize_arm_tdep (void) int numregs, i, j; static char *helptext; - if (GDB_MULTI_ARCH) - gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); + gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); /* Register an ELF OS ABI sniffer for ARM binaries. */ gdbarch_register_osabi_sniffer (bfd_arch_arm, |