diff options
-rw-r--r-- | gdb/rs6000-tdep.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index cc91250..f61e084 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -3858,6 +3858,8 @@ rs6000_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache) struct rs6000_frame_cache *cache; struct gdbarch *gdbarch = get_frame_arch (this_frame); ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch); + struct rs6000_framedata fdata; + int wordsize = tdep->wordsize; if (*this_cache) return (struct rs6000_frame_cache *) *this_cache; @@ -3868,17 +3870,56 @@ rs6000_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache) try { - /* 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; + /* At this point the stack looks as if we just entered the function. + The SP (r1) has been restored but the LR and r31 may not have been + restored yet. Need to update the register unrolling information in + the cache for the LR and the saved gprs. */ + CORE_ADDR sp; + CORE_ADDR func = 0, pc = 0; - sp = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); - lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum); + func = get_frame_func (this_frame); + cache->pc = func; + pc = get_frame_pc (this_frame); + skip_prologue (gdbarch, func, pc, &fdata); + + /* SP is in r1 and it has been restored. Get the current value. */ + sp = get_frame_register_unsigned (this_frame, + gdbarch_sp_regnum (gdbarch)); cache->base = sp; cache->initial_sp = sp; - cache->saved_regs[gdbarch_pc_regnum (gdbarch)].set_value (lr); + /* Store the unwinding rules for the gpr registers that have not been + restored yet, specifically r31. + + if != -1, fdata.saved_gpr is the smallest number of saved_gpr. + All gpr's from saved_gpr to gpr31 are saved (except during the + prologue). */ + + if (fdata.saved_gpr >= 0) + { + int i; + CORE_ADDR gpr_addr = cache->base + fdata.gpr_offset; + + for(i = fdata.saved_gpr; i < ppc_num_gprs; i++) + { + if (fdata.gpr_mask & (1U << i)) + cache->saved_regs[tdep->ppc_gp0_regnum + i].set_addr (gpr_addr); + gpr_addr += wordsize; + } + } + + /* Store the lr unwinding rules. */ + if (fdata.lr_offset != 0) + cache->saved_regs[tdep->ppc_lr_regnum].set_addr (cache->base + + fdata.lr_offset); + + else if (fdata.lr_register != -1) + cache->saved_regs[tdep->ppc_lr_regnum].set_realreg (fdata.lr_register); + + /* The PC is found in the link register. */ + cache->saved_regs[gdbarch_pc_regnum (gdbarch)] + = cache->saved_regs[tdep->ppc_lr_regnum]; } catch (const gdb_exception_error &ex) { |