aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/hppa-hpux-tdep.c40
-rw-r--r--gdb/hppa-tdep.c13
-rw-r--r--gdb/hppa-tdep.h9
4 files changed, 70 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a337deaf..248197e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,13 @@
2004-12-07 Randolph Chung <tausq@debian.org>
+ * 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 <tausq@debian.org>
+
* hppa-tdep.c (hppa_stub_Frame_unwind_cache): Stop unwinding if
unwinding from a frame with pc == 0.
(hppa_stub_frame_this_id): Likewise.
diff --git a/gdb/hppa-hpux-tdep.c b/gdb/hppa-hpux-tdep.c
index cd5c016..9aebb04 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 ae7c519..6be4ad5 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 a0632de..0b4185a 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);
+
};
/*