diff options
author | Wei-cheng Wang <cole945@gmail.com> | 2015-01-17 14:29:16 +0800 |
---|---|---|
committer | Cole Wang <cole945@gmail.com> | 2015-01-17 19:48:22 +0800 |
commit | 2608dbf8a3ee666ac0a7d5d7c45611d489edcda5 (patch) | |
tree | ec1422eaaefd1fd6681b1a686586c9dcbdfb34f4 /gdb/rs6000-tdep.c | |
parent | 07d57b544c88f230cf689cc80f5a15e1b1a0cb9a (diff) | |
download | gdb-2608dbf8a3ee666ac0a7d5d7c45611d489edcda5.zip gdb-2608dbf8a3ee666ac0a7d5d7c45611d489edcda5.tar.gz gdb-2608dbf8a3ee666ac0a7d5d7c45611d489edcda5.tar.bz2 |
Epilogue unwinder for PowerPC.
Diffstat (limited to 'gdb/rs6000-tdep.c')
-rw-r--r-- | gdb/rs6000-tdep.c | 100 |
1 files changed, 96 insertions, 4 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 455318a..e6e2e60 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -872,14 +872,14 @@ insn_changes_sp_or_jumps (unsigned long insn) limit for the size of an epilogue. */ static int -rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +rs6000_in_function_epilogue_frame_p (struct frame_info *curfrm, + struct gdbarch *gdbarch, CORE_ADDR pc) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); bfd_byte insn_buf[PPC_INSN_SIZE]; CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end; unsigned long insn; - struct frame_info *curfrm; /* Find the search limits based on function boundaries and hard limit. */ @@ -892,8 +892,6 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE; if (epilogue_end > func_end) epilogue_end = func_end; - curfrm = get_current_frame (); - /* Scan forward until next 'blr'. */ for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE) @@ -934,6 +932,15 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) return 0; } +/* Implementation of gdbarch_in_function_epilogue_p. */ + +static int +rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return rs6000_in_function_epilogue_frame_p (get_current_frame (), + gdbarch, pc); +} + /* Get the ith function argument for the current function. */ static CORE_ADDR rs6000_fetch_pointer_argument (struct frame_info *frame, int argi, @@ -3339,6 +3346,89 @@ static const struct frame_unwind rs6000_frame_unwind = NULL, default_frame_sniffer }; + +static struct rs6000_frame_cache * +rs6000_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache) +{ + volatile struct gdb_exception ex; + struct rs6000_frame_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + CORE_ADDR sp; + + if (*this_cache) + return *this_cache; + + cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + /* At this point the stack looks as if we just entered the + function, and the return address is stored in LR. */ + CORE_ADDR sp, lr; + + sp = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); + lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum); + + cache->base = sp; + cache->initial_sp = sp; + + trad_frame_set_value (cache->saved_regs, + gdbarch_pc_regnum (gdbarch), lr); + } + if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR) + throw_exception (ex); + + return cache; +} + +static void +rs6000_epilogue_frame_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + CORE_ADDR pc; + struct rs6000_frame_cache *info = + rs6000_epilogue_frame_cache (this_frame, this_cache); + + pc = get_frame_func (this_frame); + if (info->base == 0) + (*this_id) = frame_id_build_unavailable_stack (pc); + else + (*this_id) = frame_id_build (info->base, pc); +} + +static struct value * +rs6000_epilogue_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct rs6000_frame_cache *info = + rs6000_epilogue_frame_cache (this_frame, this_cache); + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); +} + +static int +rs6000_epilogue_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + if (frame_relative_level (this_frame) == 0) + return rs6000_in_function_epilogue_frame_p (this_frame, + get_frame_arch (this_frame), + get_frame_pc (this_frame)); + else + return 0; +} + +static const struct frame_unwind rs6000_epilogue_frame_unwind = +{ + NORMAL_FRAME, + default_frame_unwind_stop_reason, + rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register, + NULL, + rs6000_epilogue_frame_sniffer +}; static CORE_ADDR @@ -4154,6 +4244,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) case GDB_OSABI_NETBSD_ELF: case GDB_OSABI_UNKNOWN: set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); + frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id); frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); @@ -4162,6 +4253,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_believe_pcc_promotion (gdbarch, 1); set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); + frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id); frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); |