diff options
-rw-r--r-- | gdb/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 96 |
2 files changed, 103 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3deec46401b..8a9b31ae3c4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -34,6 +34,13 @@ * Makefile.in (reverse.c): New file. * reverse.c: New file. User interface for reverse execution. +2007-04-18 Daniel Jacobowitz <dan@codesourcery.com> + + * arm-tdep.c (arm_scan_epilogue): New. + (arm_make_prologue_cache): Use it. + (arm_epilogue_unwind_sniffer): New. + (arm_gdbarch_init): Register it. + 2008-06-09 Doug Evans <dje@google.com> * remote.c (remote_wait): Include beginning of malformed packet diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index fd732a87e45..0d4d1fe55b0 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1011,6 +1011,84 @@ arm_scan_prologue (struct frame_info *this_frame, do_cleanups (back_to); } +/* This function tries to guess whether we are in the epilogue of an + ARM function. We need to detect whether the stack frame has + already been destroyed - if it has, then neither the prologue + scanner nor GCC's unwind tables will be valid. This is very hokey + and generally unsafe. */ + +static int +arm_scan_epilogue (struct frame_info *next_frame, + struct arm_prologue_cache *cache) +{ + unsigned int insn; + gdb_byte buf[4]; + CORE_ADDR prev_pc = frame_pc_unwind (next_frame); + + /* Assume there is no frame until proven otherwise. */ + if (cache != NULL) + { + cache->framereg = ARM_SP_REGNUM; + cache->framesize = 0; + cache->frameoffset = 0; + } + + /* Check for Thumb epilogue. */ + if (arm_pc_is_thumb (prev_pc)) + /* Not yet implemented. */ + return 0; + + if (target_read_memory (prev_pc, buf, 4) != 0) + return 0; + insn = extract_unsigned_integer (buf, 4); + + if (insn == 0xe12fff1e) /* bx lr */ + /* If this is a return, we have no frame left and no saved + registers. */ + return 1; + + return 0; +} + +/* This function tries to guess whether we are in the epilogue of an + ARM function. We need to detect whether the stack frame has + already been destroyed - if it has, then neither the prologue + scanner nor GCC's unwind tables will be valid. This is very hokey + and generally unsafe. */ + +static int +arm_scan_epilogue (struct frame_info *next_frame, + struct arm_prologue_cache *cache) +{ + unsigned int insn; + gdb_byte buf[4]; + CORE_ADDR prev_pc = frame_pc_unwind (next_frame); + + /* Assume there is no frame until proven otherwise. */ + if (cache != NULL) + { + cache->framereg = ARM_SP_REGNUM; + cache->framesize = 0; + cache->frameoffset = 0; + } + + /* Check for Thumb epilogue. */ + if (arm_pc_is_thumb (prev_pc)) + /* Not yet implemented. */ + return 0; + + if (target_read_memory (prev_pc, buf, 4) != 0) + return 0; + insn = extract_unsigned_integer (buf, 4); + + if (insn == 0xe12fff1e) /* bx lr */ + /* If this is a return, we have no frame left and no saved + registers. */ + return 1; + + return 0; +} + static struct arm_prologue_cache * arm_make_prologue_cache (struct frame_info *this_frame) { @@ -1132,6 +1210,24 @@ struct frame_unwind arm_prologue_unwind = { default_frame_sniffer }; +static const struct frame_unwind * +arm_epilogue_unwind_sniffer (struct frame_info *next_frame) +{ + if (arm_scan_epilogue (next_frame, NULL)) + return &arm_prologue_unwind; + else + return NULL; +} + +static const struct frame_unwind * +arm_epilogue_unwind_sniffer (struct frame_info *next_frame) +{ + if (arm_scan_epilogue (next_frame, NULL)) + return &arm_prologue_unwind; + else + return NULL; +} + static struct arm_prologue_cache * arm_make_stub_cache (struct frame_info *this_frame) { |