aboutsummaryrefslogtreecommitdiff
path: root/gdb/hppa-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/hppa-tdep.c')
-rw-r--r--gdb/hppa-tdep.c90
1 files changed, 48 insertions, 42 deletions
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 85c0766..687b309 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -1153,7 +1153,7 @@ int
hppa_pop_frame ()
{
register struct frame_info *frame = get_current_frame ();
- register CORE_ADDR fp;
+ register CORE_ADDR fp, npc, target_pc;
register int regnum;
struct frame_saved_regs fsr;
double freg_buffer;
@@ -1187,12 +1187,16 @@ hppa_pop_frame ()
/* If the PC was explicitly saved, then just restore it. */
if (fsr.regs[PCOQ_TAIL_REGNUM])
- write_register (PCOQ_TAIL_REGNUM,
- read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4));
-
+ {
+ npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4);
+ write_register (PCOQ_TAIL_REGNUM, npc);
+ }
/* Else use the value in %rp to set the new PC. */
else
- target_write_pc (read_register (RP_REGNUM), 0);
+ {
+ npc = read_register (RP_REGNUM);
+ target_write_pc (npc, 0);
+ }
write_register (FP_REGNUM, read_memory_integer (fp, 4));
@@ -1201,6 +1205,35 @@ hppa_pop_frame ()
else
write_register (SP_REGNUM, fp);
+ /* The PC we just restored may be inside a return trampoline. If so
+ we want to restart the inferior and run it through the trampoline.
+
+ Do this by setting a momentary breakpoint at the location the
+ trampoline returns to. */
+ target_pc = SKIP_TRAMPOLINE_CODE (npc & ~0x3) & ~0x3;
+ if (target_pc)
+ {
+ struct symtab_and_line sal;
+ struct breakpoint *breakpoint;
+ struct cleanup *old_chain;
+
+ /* Set up our breakpoint. Set it to be silent as the MI code
+ for "return_command" will print the frame we returned to. */
+ sal = find_pc_line (target_pc, 0);
+ sal.pc = target_pc;
+ breakpoint = set_momentary_breakpoint (sal, NULL, bp_finish);
+ breakpoint->silent = 1;
+
+ /* So we can clean things up. */
+ old_chain = make_cleanup (delete_breakpoint, breakpoint);
+
+ /* Start up the inferior. */
+ proceed_to_finish = 1;
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+
+ /* Perform our cleanups. */
+ do_cleanups (old_chain);
+ }
flush_cached_frames ();
}
@@ -1631,24 +1664,10 @@ in_solib_call_trampoline (pc, name)
if (u->stub_type == IMPORT)
return 1;
- if (u->stub_type == EXPORT)
- {
- /* The linker may group many EXPORT stubs into one unwind entry. So
- lookup the minimal symbol and use that as the beginning of this
- particular stub. */
- minsym = lookup_minimal_symbol_by_pc (pc);
- if (minsym == NULL)
- return 0;
-
- /* Export stubs have distinct call and return paths. The first
- two instructions are the call path, following four are the
- return path. */
- return (pc >= SYMBOL_VALUE (minsym) && pc < SYMBOL_VALUE (minsym) + 8);
- }
-
/* Parameter relocation stubs always have a call path and may have a
return path. */
- if (u->stub_type == PARAMETER_RELOCATION)
+ if (u->stub_type == PARAMETER_RELOCATION
+ || u->stub_type == EXPORT)
{
CORE_ADDR addr;
@@ -1661,10 +1680,11 @@ in_solib_call_trampoline (pc, name)
insn = read_memory_integer (addr, 4);
/* Does it look like a bl? If so then it's the call path, if
- we find a bv first, then we're on the return path. */
+ we find a bv or be first, then we're on the return path. */
if ((insn & 0xfc00e000) == 0xe8000000)
return 1;
- else if ((insn & 0xfc00e001) == 0xe800c000)
+ else if ((insn & 0xfc00e001) == 0xe800c000
+ || (insn & 0xfc000000) == 0xe0000000)
return 0;
}
@@ -1706,25 +1726,10 @@ in_solib_return_trampoline (pc, name)
if (u->stub_type == IMPORT)
return 1;
- if (u->stub_type == EXPORT)
- {
- /* The linker may group many EXPORT stubs into one unwind entry. So
- lookup the minimal symbol and use that as the beginning of this
- particular stub. */
- minsym = lookup_minimal_symbol_by_pc (pc);
- if (minsym == NULL)
- return 0;
-
- /* Export stubs have distinct call and return paths. The first
- two instructions are the call path, following four are the
- return path. */
- return (pc >= SYMBOL_VALUE (minsym) + 8
- && pc < SYMBOL_VALUE (minsym) + 20);
- }
-
/* Parameter relocation stubs always have a call path and may have a
return path. */
- if (u->stub_type == PARAMETER_RELOCATION)
+ if (u->stub_type == PARAMETER_RELOCATION
+ || u->stub_type == EXPORT)
{
CORE_ADDR addr;
@@ -1737,10 +1742,11 @@ in_solib_return_trampoline (pc, name)
insn = read_memory_integer (addr, 4);
/* Does it look like a bl? If so then it's the call path, if
- we find a bv first, then we're on the return path. */
+ we find a bv or be first, then we're on the return path. */
if ((insn & 0xfc00e000) == 0xe8000000)
return 0;
- else if ((insn & 0xfc00e001) == 0xe800c000)
+ else if ((insn & 0xfc00e001) == 0xe800c000
+ || (insn & 0xfc000000) == 0xe0000000)
return 1;
}