aboutsummaryrefslogtreecommitdiff
path: root/gdb/hppa-tdep.c
diff options
context:
space:
mode:
authorJeff Law <law@redhat.com>1994-03-04 17:54:41 +0000
committerJeff Law <law@redhat.com>1994-03-04 17:54:41 +0000
commit70e43abe7c41fcf6b7682aab3c6fd9716c255dc2 (patch)
tree78c6175e7726575856ce9ab20d66ec874c58d389 /gdb/hppa-tdep.c
parent7b5f6e48f11614a3937aa3d327c945cd677976f4 (diff)
downloadfsf-binutils-gdb-70e43abe7c41fcf6b7682aab3c6fd9716c255dc2.zip
fsf-binutils-gdb-70e43abe7c41fcf6b7682aab3c6fd9716c255dc2.tar.gz
fsf-binutils-gdb-70e43abe7c41fcf6b7682aab3c6fd9716c255dc2.tar.bz2
* hppa-tdep.c (pc_in_linker_stub): Move decl to beginning of file.
(pc_in_interrupt_handler): New function. Also add PARAM decl. (find_proc_framesize): Deal with HPUX setting SAVE_SP bit for signal trampoline and interrupt routines. (frame_saved_pc): Handle signal trampolines and interrupt routines. (frame_chain, frame_chain_valid): Likewise. (hppa_frame_find_saved_regs): Likewise. Also deal with special saved regs convention for SP. * tm-hppa[bho].h: FRAME_FIND_SAVED_PC_IN_SIGTRAMP): Define. (FRAME_BASE_BEFORE_SIGTRAMP): Define. (FRAME_FIND_SAVED_REGS_IN_SIGTRAMP): Define. * tm-hppah.h (IN_SIGTRAMP): Define.
Diffstat (limited to 'gdb/hppa-tdep.c')
-rw-r--r--gdb/hppa-tdep.c173
1 files changed, 152 insertions, 21 deletions
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index ca849c5..da8ffc5 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -66,6 +66,8 @@ static int prologue_inst_adjust_sp PARAMS ((unsigned long));
static int is_branch PARAMS ((unsigned long));
static int inst_saves_gr PARAMS ((unsigned long));
static int inst_saves_fr PARAMS ((unsigned long));
+static int pc_in_interrupt_handler PARAMS ((CORE_ADDR));
+static int pc_in_linker_stub PARAMS ((CORE_ADDR));
/* Routines to extract various sized constants out of hppa
@@ -298,9 +300,29 @@ find_unwind_entry(pc)
return NULL;
}
+/* Called to determine if PC is in an interrupt handler of some
+ kind. */
+
+static int
+pc_in_interrupt_handler (pc)
+ CORE_ADDR pc;
+{
+ struct unwind_table_entry *u;
+ struct minimal_symbol *msym_us;
+
+ u = find_unwind_entry (pc);
+ if (!u)
+ return 0;
+
+ /* Oh joys. HPUX sets the interrupt bit for _sigreturn even though
+ its frame isn't a pure interrupt frame. Deal with this. */
+ msym_us = lookup_minimal_symbol_by_pc (pc);
+
+ return u->HP_UX_interrupt_marker && !IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us));
+}
+
/* Called when no unwind descriptor was found for PC. Returns 1 if it
appears that PC is in a linker stub. */
-static int pc_in_linker_stub PARAMS ((CORE_ADDR));
static int
pc_in_linker_stub (pc)
@@ -388,10 +410,11 @@ find_return_regnum(pc)
/* Return size of frame, or -1 if we should use a frame pointer. */
int
-find_proc_framesize(pc)
+find_proc_framesize (pc)
CORE_ADDR pc;
{
struct unwind_table_entry *u;
+ struct minimal_symbol *msym_us;
u = find_unwind_entry (pc);
@@ -404,9 +427,12 @@ find_proc_framesize(pc)
return -1;
}
- if (u->Save_SP)
- /* If this bit is set, it means there is a frame pointer and we should
- use it. */
+ msym_us = lookup_minimal_symbol_by_pc (pc);
+
+ /* If Save_SP is set, and we're not in an interrupt or signal caller,
+ then we have a frame pointer. Use it. */
+ if (u->Save_SP && !pc_in_interrupt_handler (pc)
+ && !IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us)))
return -1;
return u->Total_frame_size << 3;
@@ -481,19 +507,71 @@ frame_saved_pc (frame)
{
CORE_ADDR pc = get_frame_pc (frame);
+ /* BSD, HPUX & OSF1 all lay out the hardware state in the same manner
+ at the base of the frame in an interrupt handler. Registers within
+ are saved in the exact same order as GDB numbers registers. How
+ convienent. */
+ if (pc_in_interrupt_handler (pc))
+ return read_memory_integer (frame->frame + PC_REGNUM * 4, 4) & ~0x3;
+
+ /* Deal with signal handler caller frames too. */
+ if (frame->signal_handler_caller)
+ {
+ CORE_ADDR rp;
+ FRAME_SAVED_PC_IN_SIGTRAMP (frame, &rp);
+ return rp;
+ }
+
if (frameless_function_invocation (frame))
{
int ret_regnum;
ret_regnum = find_return_regnum (pc);
- return read_register (ret_regnum) & ~0x3;
+ /* If the next frame is an interrupt frame or a signal
+ handler caller, then we need to look in the saved
+ register area to get the return pointer (the values
+ in the registers may not correspond to anything useful). */
+ if (frame->next
+ && (frame->next->signal_handler_caller
+ || pc_in_interrupt_handler (frame->next->pc)))
+ {
+ struct frame_info *fi;
+ struct frame_saved_regs saved_regs;
+
+ fi = get_frame_info (frame->next);
+ get_frame_saved_regs (fi, &saved_regs);
+ if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM] & 0x2, 4))
+ return read_memory_integer (saved_regs.regs[31], 4);
+ else
+ return read_memory_integer (saved_regs.regs[RP_REGNUM], 4);
+ }
+ else
+ return read_register (ret_regnum) & ~0x3;
}
else
{
int rp_offset = rp_saved (pc);
- if (rp_offset == 0)
+ /* Similar to code in frameless function case. If the next
+ frame is a signal or interrupt handler, then dig the right
+ information out of the saved register info. */
+ if (rp_offset == 0
+ && frame->next
+ && (frame->next->signal_handler_caller
+ || pc_in_interrupt_handler (frame->next->pc)))
+ {
+ struct frame_info *fi;
+ struct frame_saved_regs saved_regs;
+
+ fi = get_frame_info (frame->next);
+ get_frame_saved_regs (fi, &saved_regs);
+ if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM] & 0x2, 4))
+ return read_memory_integer (saved_regs.regs[31], 4);
+ else
+ return read_memory_integer (saved_regs.regs[RP_REGNUM], 4);
+ }
+ else if (rp_offset == 0)
return read_register (RP_REGNUM) & ~0x3;
else
return read_memory_integer (frame->frame + rp_offset, 4) & ~0x3;
@@ -569,6 +647,20 @@ frame_chain (frame)
{
int my_framesize, caller_framesize;
struct unwind_table_entry *u;
+ CORE_ADDR frame_base;
+
+ /* Handle HPUX, BSD, and OSF1 style interrupt frames first. These
+ are easy; at *sp we have a full save state strucutre which we can
+ pull the old stack pointer from. Also see frame_saved_pc for
+ code to dig a saved PC out of the save state structure. */
+ if (pc_in_interrupt_handler (frame->pc))
+ frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4, 4);
+ else if (frame->signal_handler_caller)
+ {
+ FRAME_BASE_BEFORE_SIGTRAMP (frame, &frame_base);
+ }
+ else
+ frame_base = frame->frame;
/* Get frame sizes for the current frame and the frame of the
caller. */
@@ -578,13 +670,13 @@ frame_chain (frame)
/* If caller does not have a frame pointer, then its frame
can be found at current_frame - caller_framesize. */
if (caller_framesize != -1)
- return frame->frame - caller_framesize;
+ return frame_base - caller_framesize;
/* Both caller and callee have frame pointers and are GCC compiled
(SAVE_SP bit in unwind descriptor is on for both functions.
The previous frame pointer is found at the top of the current frame. */
if (caller_framesize == -1 && my_framesize == -1)
- return read_memory_integer (frame->frame, 4);
+ return read_memory_integer (frame_base, 4);
/* Caller has a frame pointer, but callee does not. This is a little
more difficult as GCC and HP C lay out locals and callee register save
@@ -618,7 +710,9 @@ frame_chain (frame)
/* Entry_GR specifies the number of callee-saved general registers
saved in the stack. It starts at %r3, so %r3 would be 1. */
- if (u->Entry_GR >= 1 || u->Save_SP)
+ if (u->Entry_GR >= 1 || u->Save_SP
+ || frame->signal_handler_caller
+ || pc_in_interrupt_handler (frame->pc))
break;
else
frame = frame->next;
@@ -628,7 +722,9 @@ frame_chain (frame)
{
/* We may have walked down the chain into a function with a frame
pointer. */
- if (u->Save_SP)
+ if (u->Save_SP
+ && !frame->signal_handler_caller
+ && !pc_in_interrupt_handler (frame->pc))
return read_memory_integer (frame->frame, 4);
/* %r3 was saved somewhere in the stack. Dig it out. */
else
@@ -660,13 +756,17 @@ frame_chain_valid (chain, thisframe)
{
struct minimal_symbol *msym_us;
struct minimal_symbol *msym_start;
- struct unwind_table_entry *u;
+ struct unwind_table_entry *u, *next_u = NULL;
+ FRAME next;
if (!chain)
return 0;
u = find_unwind_entry (thisframe->pc);
+ if (u == NULL)
+ return 1;
+
/* We can't just check that the same of msym_us is "_start", because
someone idiotically decided that they were going to make a Ltext_end
symbol with the same address. This Ltext_end symbol is totally
@@ -680,10 +780,16 @@ frame_chain_valid (chain, thisframe)
&& SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
return 0;
- if (u == NULL)
- return 1;
+ next = get_next_frame (thisframe);
+ if (next)
+ next_u = find_unwind_entry (next->pc);
- if (u->Save_SP || u->Total_frame_size || u->stub_type != 0)
+ /* If this frame does not save SP, has no stack, isn't a stub,
+ and doesn't "call" an interrupt routine or signal handler caller,
+ then its not valid. */
+ if (u->Save_SP || u->Total_frame_size || u->stub_type != 0
+ || (thisframe->next && thisframe->next->signal_handler_caller)
+ || (next_u && next_u->HP_UX_interrupt_marker))
return 1;
if (pc_in_linker_stub (thisframe->pc))
@@ -1407,6 +1513,29 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
+ 6 * 4)))
find_dummy_frame_regs (frame_info, frame_saved_regs);
+ /* Interrupt handlers are special too. They lay out the register
+ state in the exact same order as the register numbers in GDB. */
+ if (pc_in_interrupt_handler (frame_info->pc))
+ {
+ for (i = 0; i < NUM_REGS; i++)
+ {
+ /* SP is a little special. */
+ if (i == SP_REGNUM)
+ frame_saved_regs->regs[SP_REGNUM]
+ = read_memory_integer (frame_info->frame + SP_REGNUM * 4, 4);
+ else
+ frame_saved_regs->regs[i] = frame_info->frame + i * 4;
+ }
+ return;
+ }
+
+ /* Handle signal handler callers. */
+ if (frame_info->signal_handler_caller)
+ {
+ FRAME_FIND_SAVED_REGS_IN_SIGTRAMP (frame_info, frame_saved_regs);
+ return;
+ }
+
/* Get the starting address of the function referred to by the PC
saved in frame_info. */
pc = get_pc_function_start (frame_info->pc);
@@ -1439,6 +1568,11 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
for (i = 12; i < u->Entry_FR + 12; i++)
save_fr |= (1 << i);
+ /* The frame always represents the value of %sp at entry to the
+ current function (and is thus equivalent to the "saved" stack
+ pointer. */
+ frame_saved_regs->regs[SP_REGNUM] = frame_info->frame;
+
/* Loop until we find everything of interest or hit a branch.
For unoptimized GCC code and for any HP CC code this will never ever
@@ -1472,13 +1606,10 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 20;
}
- /* This is the only way we save SP into the stack. At this time
- the HP compilers never bother to save SP into the stack. */
+ /* Just note that we found the save of SP into the stack. The
+ value for frame_saved_regs was computed above. */
if ((inst & 0xffffc000) == 0x6fc10000)
- {
- save_sp = 0;
- frame_saved_regs->regs[SP_REGNUM] = frame_info->frame;
- }
+ save_sp = 0;
/* Account for general and floating-point register saves. */
reg = inst_saves_gr (inst);