diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a337deaf48..248197e690 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2004-12-07 Randolph Chung + + * hppa-tdep.h (gdbarch_tdep): Add unwind_adjust_stub method. + * hppa-hpux-tdep.c (hppa_hpux_unwind_adjust_stub): New function. + (hppa_hpux_init_abi) Set unwind_adjust_stub method. + * hppa-tdep.c (hppa_frame_cache): Call unwind_adjust_stub method + if defined. + 2004-12-07 Randolph Chung * hppa-tdep.c (hppa_stub_Frame_unwind_cache): Stop unwinding if diff --git a/gdb/hppa-hpux-tdep.c b/gdb/hppa-hpux-tdep.c index cd5c016352..9aebb041ca 100644 --- a/gdb/hppa-hpux-tdep.c +++ b/gdb/hppa-hpux-tdep.c @@ -1471,6 +1471,44 @@ hppa_hpux_inferior_created (struct target_ops *objfile, int from_tty) hp_cxx_exception_support_initialized = 0; } +/* Given the current value of the pc, check to see if it is inside a stub, and + if so, change the value of the pc to point to the caller of the stub. + NEXT_FRAME is the next frame in the current list of frames. + BASE contains to stack frame base of the current frame. + SAVE_REGS is the register file stored in the frame cache. */ +static void +hppa_hpux_unwind_adjust_stub (struct frame_info *next_frame, CORE_ADDR base, + struct trad_frame_saved_reg *saved_regs) +{ + int optimized, realreg; + enum lval_type lval; + CORE_ADDR addr; + char buffer[sizeof(ULONGEST)]; + ULONGEST val; + CORE_ADDR stubpc; + struct unwind_table_entry *u; + + trad_frame_get_prev_register (next_frame, saved_regs, + HPPA_PCOQ_HEAD_REGNUM, + &optimized, &lval, &addr, &realreg, buffer); + val = extract_unsigned_integer (buffer, + register_size (get_frame_arch (next_frame), + HPPA_PCOQ_HEAD_REGNUM)); + + u = find_unwind_entry (val); + if (u && u->stub_unwind.stub_type == EXPORT) + { + stubpc = read_memory_integer (base - 24, TARGET_PTR_BIT / 8); + trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc); + } + else if (hppa_symbol_address ("__gcc_plt_call") + == get_pc_function_start (val)) + { + stubpc = read_memory_integer (base - 8, TARGET_PTR_BIT / 8); + trad_frame_set_value (saved_regs, HPPA_PCOQ_HEAD_REGNUM, stubpc); + } +} + static void hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -1481,6 +1519,8 @@ hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) else tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline; + tdep->unwind_adjust_stub = hppa_hpux_unwind_adjust_stub; + set_gdbarch_in_solib_return_trampoline (gdbarch, hppa_hpux_in_solib_return_trampoline); set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code); diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index ae7c519240..6be4ad52d3 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -1905,6 +1905,19 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) } } + { + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + + gdbarch = get_frame_arch (next_frame); + tdep = gdbarch_tdep (gdbarch); + + if (tdep->unwind_adjust_stub) + { + tdep->unwind_adjust_stub (next_frame, cache->base, cache->saved_regs); + } + } + if (hppa_debug) fprintf_unfiltered (gdb_stdlog, "base=0x%s }", paddr_nz (((struct hppa_frame_cache *)*this_cache)->base)); diff --git a/gdb/hppa-tdep.h b/gdb/hppa-tdep.h index a0632de21f..0b4185a47c 100644 --- a/gdb/hppa-tdep.h +++ b/gdb/hppa-tdep.h @@ -88,6 +88,15 @@ struct gdbarch_tdep IN_SOLIB_CALL_TRAMPOLINE evaluates to nonzero if we are currently stopped in one of these. */ int (*in_solib_call_trampoline) (CORE_ADDR pc, char *name); + + /* For targets that support multiple spaces, we may have additional stubs + in the return path. These stubs are internal to the ABI, and users are + not interested in them. If we detect that we are returning to a stub, + adjust the pc to the real caller. This improves the behavior of commands + that traverse frames such as "up" and "finish". */ + void (*unwind_adjust_stub) (struct frame_info *next_frame, CORE_ADDR base, + struct trad_frame_saved_reg *saved_regs); + }; /*