diff options
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r-- | gdb/arm-tdep.c | 282 |
1 files changed, 168 insertions, 114 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index fa0b365..646d5c6 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -417,10 +417,15 @@ arm_skip_prologue (CORE_ADDR pc) { unsigned long inst; CORE_ADDR skip_pc; - CORE_ADDR func_addr, func_end; + CORE_ADDR func_addr, func_end = 0; char *func_name; struct symtab_and_line sal; + /* If we're in a dummy frame, don't even try to skip the prologue. */ + if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (pc, 0, 0)) + return pc; + /* See what the symbol table says. */ if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) @@ -444,74 +449,63 @@ arm_skip_prologue (CORE_ADDR pc) /* Can't find the prologue end in the symbol table, try it the hard way by disassembling the instructions. */ - skip_pc = pc; - inst = read_memory_integer (skip_pc, 4); - /* "mov ip, sp" is no longer a required part of the prologue. */ - if (inst == 0xe1a0c00d) /* mov ip, sp */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - /* Some prologues begin with "str lr, [sp, #-4]!". */ - if (inst == 0xe52de004) /* str lr, [sp, #-4]! */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } + /* Like arm_scan_prologue, stop no later than pc + 64. */ + if (func_end == 0 || func_end > pc + 64) + func_end = pc + 64; - if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */ + for (skip_pc = pc; skip_pc < func_end; skip_pc += 4) { - skip_pc += 4; inst = read_memory_integer (skip_pc, 4); - } - if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } + /* "mov ip, sp" is no longer a required part of the prologue. */ + if (inst == 0xe1a0c00d) /* mov ip, sp */ + continue; - /* Any insns after this point may float into the code, if it makes - for better instruction scheduling, so we skip them only if we - find them, but still consider the function to be frame-ful. */ + /* Some prologues begin with "str lr, [sp, #-4]!". */ + if (inst == 0xe52de004) /* str lr, [sp, #-4]! */ + continue; - /* We may have either one sfmfd instruction here, or several stfe - insns, depending on the version of floating point code we - support. */ - if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - else - { - while ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - } + if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */ + continue; - if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } + if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */ + continue; - if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } + /* Any insns after this point may float into the code, if it makes + for better instruction scheduling, so we skip them only if we + find them, but still consider the function to be frame-ful. */ - while ((inst & 0xffffcfc0) == 0xe50b0000) /* str r(0123), [r11, #-nn] */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); + /* We may have either one sfmfd instruction here, or several stfe + insns, depending on the version of floating point code we + support. */ + if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */ + continue; + + if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */ + continue; + + if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */ + continue; + + if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */ + continue; + + if ((inst & 0xffffc000) == 0xe54b0000 || /* strb r(0123),[r11,#-nn] */ + (inst & 0xffffc0f0) == 0xe14b00b0 || /* strh r(0123),[r11,#-nn] */ + (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */ + continue; + + if ((inst & 0xffffc000) == 0xe5cd0000 || /* strb r(0123),[sp,#nn] */ + (inst & 0xffffc0f0) == 0xe1cd00b0 || /* strh r(0123),[sp,#nn] */ + (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */ + continue; + + /* Un-recognized instruction; stop scanning. */ + break; } - return skip_pc; + return skip_pc; /* End of prologue */ } /* *INDENT-OFF* */ @@ -553,6 +547,12 @@ thumb_scan_prologue (struct frame_info *fi) int findmask = 0; int i; + /* Don't try to scan dummy frames. */ + if (USE_GENERIC_DUMMY_FRAMES + && fi != NULL + && PC_IN_CALL_DUMMY (fi->pc, 0, 0)) + return; + if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) { struct symtab_and_line sal = find_pc_line (prologue_start, 0); @@ -597,7 +597,7 @@ thumb_scan_prologue (struct frame_info *fi) whether to save LR (R14). */ mask = (insn & 0xff) | ((insn & 0x100) << 6); - /* Calculate offsets of saved R0-R7 and LR. */ + /* Calculate offsets of saved R0-R7 and LR. */ for (regno = ARM_LR_REGNUM; regno >= 0; regno--) if (mask & (1 << regno)) { @@ -611,7 +611,7 @@ thumb_scan_prologue (struct frame_info *fi) else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ { - if ((findmask & 1) == 0) /* before push? */ + if ((findmask & 1) == 0) /* before push? */ continue; else findmask |= 4; /* add/sub sp found */ @@ -857,7 +857,7 @@ arm_scan_prologue (struct frame_info *fi) Be careful, however, and if it doesn't look like a prologue, don't try to scan it. If, for instance, a frameless function begins with stmfd sp!, then we will tell ourselves there is - a frame, which will confuse stack traceback, as well ad"finish" + a frame, which will confuse stack traceback, as well as "finish" and other operations that rely on a knowledge of the stack traceback. @@ -870,7 +870,7 @@ arm_scan_prologue (struct frame_info *fi) [Note further: The "mov ip,sp" only seems to be missing in frameless functions at optimization level "-O2" or above, in which case it is often (but not always) replaced by - "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */ + "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */ sp_offset = fp_offset = 0; @@ -904,7 +904,16 @@ arm_scan_prologue (struct frame_info *fi) fi->saved_regs[regno] = sp_offset; } } - else if ((insn & 0xffffcfc0) == 0xe50b0000) /* str rx, [r11, -n] */ + else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */ + (insn & 0xffffc0f0) == 0xe14b00b0 || /* strh rx,[r11,#-n] */ + (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */ + { + /* No need to add this to saved_regs -- it's just an arg reg. */ + continue; + } + else if ((insn & 0xffffc000) == 0xe5cd0000 || /* strb rx,[sp,#n] */ + (insn & 0xffffc0f0) == 0xe1cd00b0 || /* strh rx,[sp,#n] */ + (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */ { /* No need to add this to saved_regs -- it's just an arg reg. */ continue; @@ -960,7 +969,7 @@ arm_scan_prologue (struct frame_info *fi) } else if ((insn & 0xf0000000) != 0xe0000000) break; /* Condition not true, exit early */ - else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */ + else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */ break; /* Don't scan past a block load */ else /* The optimizer might shove anything into the prologue, @@ -990,16 +999,27 @@ arm_scan_prologue (struct frame_info *fi) static CORE_ADDR arm_find_callers_reg (struct frame_info *fi, int regnum) { + /* 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 = fi->next) - -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) - return generic_read_register_dummy (fi->pc, fi->frame, regnum); - else -#endif - if (fi->saved_regs[regnum] != 0) - return read_memory_integer (fi->saved_regs[regnum], - REGISTER_RAW_SIZE (regnum)); + { + if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (fi->pc, 0, 0)) + { + return generic_read_register_dummy (fi->pc, fi->frame, regnum); + } + else if (fi->saved_regs[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 (fi->saved_regs[regnum], + REGISTER_RAW_SIZE (regnum)); + } + } return read_register (regnum); } /* Function: frame_chain Given a GDB frame, determine the address of @@ -1011,34 +1031,19 @@ arm_find_callers_reg (struct frame_info *fi, int regnum) static CORE_ADDR arm_frame_chain (struct frame_info *fi) { -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - CORE_ADDR fn_start, callers_pc, fp; - - /* Is this a dummy frame? */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) - return fi->frame; /* dummy frame same as caller's frame */ - - /* Is caller-of-this a dummy frame? */ - callers_pc = FRAME_SAVED_PC (fi); /* find out who called us: */ - fp = arm_find_callers_reg (fi, ARM_FP_REGNUM); - if (PC_IN_CALL_DUMMY (callers_pc, fp, fp)) - return fp; /* dummy frame's frame may bear no relation to ours */ - - if (find_pc_partial_function (fi->pc, 0, &fn_start, 0)) - if (fn_start == entry_point_address ()) - return 0; /* in _start fn, don't chain further */ -#endif - CORE_ADDR caller_pc, fn_start; + CORE_ADDR caller_pc; int framereg = fi->extra_info->framereg; + if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (fi->pc, 0, 0)) + /* A generic call dummy's frame is the same as caller's. */ + return fi->frame; + if (fi->pc < LOWEST_PC) return 0; /* If the caller is the startup code, we're at the end of the chain. */ caller_pc = FRAME_SAVED_PC (fi); - if (find_pc_partial_function (caller_pc, 0, &fn_start, 0)) - if (fn_start == entry_point_address ()) - return 0; /* If the caller is Thumb and the caller is ARM, or vice versa, the frame register of the caller is different from ours. @@ -1109,24 +1114,16 @@ arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) memset (fi->saved_regs, '\000', sizeof fi->saved_regs); -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) - { - /* We need to setup fi->frame here because run_stack_dummy gets - it wrong by assuming it's always FP. */ - fi->frame = generic_read_register_dummy (fi->pc, fi->frame, - ARM_SP_REGNUM); - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - return; - } - else -#endif - /* Compute stack pointer for this frame. We use this value for both the sigtramp and call dummy cases. */ if (!fi->next) sp = read_sp(); + else if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (fi->next->pc, 0, 0)) + /* For generic dummy frames, pull the value direct from the frame. + Having an unwind function to do this would be nice. */ + sp = generic_read_register_dummy (fi->next->pc, fi->next->frame, + ARM_SP_REGNUM); else sp = (fi->next->frame - fi->next->extra_info->frameoffset + fi->next->extra_info->framesize); @@ -1188,6 +1185,11 @@ arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) if (!fi->next) /* This is the innermost frame? */ fi->frame = read_register (fi->extra_info->framereg); + else if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (fi->next->pc, 0, 0)) + /* Next inner most frame is a dummy, just grab its frame. + Dummy frames always have the same FP as their caller. */ + fi->frame = fi->next->frame; else if (fi->extra_info->framereg == ARM_FP_REGNUM || fi->extra_info->framereg == THUMB_FP_REGNUM) { @@ -1224,11 +1226,11 @@ arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) static CORE_ADDR arm_frame_saved_pc (struct frame_info *fi) { -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) + /* If a dummy frame, pull the PC out of the frame's register buffer. */ + if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (fi->pc, 0, 0)) return generic_read_register_dummy (fi->pc, fi->frame, ARM_PC_REGNUM); - else -#endif + if (PC_IN_CALL_DUMMY (fi->pc, fi->frame - fi->extra_info->frameoffset, fi->frame)) { @@ -1270,6 +1272,16 @@ arm_frame_init_saved_regs (struct frame_info *fip) arm_init_extra_frame_info (0, fip); } +/* Set the return address for a generic dummy frame. ARM uses the + entry point. */ + +static CORE_ADDR +arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp) +{ + write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ()); + return sp; +} + /* Push an empty stack frame, to record the current PC, etc. */ static void @@ -1524,6 +1536,14 @@ arm_pop_frame (void) CORE_ADDR old_SP = (frame->frame - frame->extra_info->frameoffset + frame->extra_info->framesize); + if (USE_GENERIC_DUMMY_FRAMES + && PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) + { + generic_pop_dummy_frame (); + flush_cached_frames (); + return; + } + for (regnum = 0; regnum < NUM_REGS; regnum++) if (frame->saved_regs[regnum] != 0) write_register (regnum, @@ -2050,7 +2070,7 @@ arm_get_next_pc (CORE_ADDR pc) static void arm_software_single_step (enum target_signal sig, int insert_bpt) { - static int next_pc; /* State between setting and unsetting. */ + static int next_pc; /* State between setting and unsetting. */ static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */ if (insert_bpt) @@ -2336,7 +2356,7 @@ arm_store_return_value (struct type *type, char *valbuf) if (TYPE_CODE (type) == TYPE_CODE_FLT) { struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - char buf[MAX_REGISTER_RAW_SIZE]; + char buf[ARM_MAX_REGISTER_RAW_SIZE]; switch (tdep->fp_model) { @@ -2344,7 +2364,7 @@ arm_store_return_value (struct type *type, char *valbuf) convert_to_extended (valbuf, buf); write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf, - MAX_REGISTER_RAW_SIZE); + FP_REGISTER_RAW_SIZE); break; case ARM_FLOAT_SOFT: @@ -2893,6 +2913,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->lowest_pc = 0x20; tdep->jb_pc = -1; /* Longjump support not enabled by default. */ +#if OLD_STYLE_ARM_DUMMY_FRAMES + /* NOTE: cagney/2002-05-07: Enable the below to restore the old ARM + specific (non-generic) dummy frame code. Might be useful if + there appears to be a problem with the generic dummy frame + mechanism that replaced it. */ set_gdbarch_use_generic_dummy_frames (gdbarch, 0); /* Call dummy code. */ @@ -2912,6 +2937,27 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_fix_call_dummy (gdbarch, arm_fix_call_dummy); set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack); +#else + set_gdbarch_use_generic_dummy_frames (gdbarch, 1); + set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT); + + set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); + set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0); + + set_gdbarch_call_dummy_p (gdbarch, 1); + set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); + + set_gdbarch_call_dummy_words (gdbarch, arm_call_dummy_words); + set_gdbarch_sizeof_call_dummy_words (gdbarch, 0); + set_gdbarch_call_dummy_start_offset (gdbarch, 0); + set_gdbarch_call_dummy_length (gdbarch, 0); + + set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy); + set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy); + + set_gdbarch_call_dummy_address (gdbarch, entry_point_address); + set_gdbarch_push_return_address (gdbarch, arm_push_return_address); +#endif set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register); set_gdbarch_push_arguments (gdbarch, arm_push_arguments); @@ -2931,7 +2977,15 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_frame_num_args (gdbarch, arm_frame_num_args); set_gdbarch_frame_args_skip (gdbarch, 0); set_gdbarch_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs); +#if OLD_STYLE_ARM_DUMMY_FRAMES + /* NOTE: cagney/2002-05-07: Enable the below to restore the old ARM + specific (non-generic) dummy frame code. Might be useful if + there appears to be a problem with the generic dummy frame + mechanism that replaced it. */ set_gdbarch_push_dummy_frame (gdbarch, arm_push_dummy_frame); +#else + set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame); +#endif set_gdbarch_pop_frame (gdbarch, arm_pop_frame); /* Address manipulation. */ |