* 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.
This commit is contained in:
Jeff Law 1994-03-04 17:54:41 +00:00
parent 7b5f6e48f1
commit 70e43abe7c
4 changed files with 255 additions and 24 deletions

View File

@ -1,3 +1,20 @@
Fri Mar 4 09:50:47 1994 Jeffrey A. Law (law@snake.cs.utah.edu)
* 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.
Thu Mar 3 12:41:16 1994 Jim Kingdon (kingdon@deneb.cygnus.com)
* ch-exp.y (match_simple_name_string): Accept '_' as well as an

View File

@ -2,5 +2,46 @@
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu). */
/* It's all just the common stuff. */
/* For BSD:
The signal context structure pointer is always saved at the base
of the frame + 0x4.
We get the PC & SP directly from the sigcontext structure itself.
For other registers we have to dive in a little deeper:
The hardware save state pointer is at offset 0x10 within the
signal context structure.
Within the hardware save state, registers are found in the same order
as the register numbers in GDB. */
#define FRAME_SAVED_PC_IN_SIGTRAMP(FRAME, TMP) \
{ \
*(TMP) = read_memory_integer ((FRAME)->frame + 0x4, 4); \
*(TMP) = read_memory_integer (*(TMP) + 0x18, 4); \
}
#define FRAME_BASE_BEFORE_SIGTRAMP(FRAME, TMP) \
{ \
*(TMP) = read_memory_integer ((FRAME)->frame + 0x4, 4); \
*(TMP) = read_memory_integer (*(TMP) + 0x8, 4); \
}
#define FRAME_FIND_SAVED_REGS_IN_SIGTRAMP(FRAME, FSR) \
{ \
int i; \
CORE_ADDR TMP; \
TMP = read_memory_integer ((FRAME)->frame + 0x4, 4); \
TMP = read_memory_integer (TMP + 0x10, 4); \
for (i = 0; i < NUM_REGS; i++) \
{ \
if (i == SP_REGNUM) \
(FSR)->regs[SP_REGNUM] = read_memory_integer (TMP + SP_REGNUM * 4, 4); \
else \
(FSR)->regs[i] = TMP + i * 4; \
} \
}
/* It's mostly just the common stuff. */
#include "pa/tm-hppa.h"

View File

@ -2,8 +2,50 @@
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu). */
/* It's all just the common stuff. */
#include "pa/tm-hppa.h"
/* For OSF1 (Should be close if not identical to BSD, but I haven't
tested it yet):
The signal context structure pointer is always saved at the base
of the frame + 0x4.
We get the PC & SP directly from the sigcontext structure itself.
For other registers we have to dive in a little deeper:
The hardware save state pointer is at offset 0x10 within the
signal context structure.
Within the hardware save state, registers are found in the same order
as the register numbers in GDB. */
#define FRAME_SAVED_PC_IN_SIGTRAMP(FRAME, TMP) \
{ \
*(TMP) = read_memory_integer ((FRAME)->frame + 0x4, 4); \
*(TMP) = read_memory_integer (*(TMP) + 0x18, 4); \
}
#define FRAME_BASE_BEFORE_SIGTRAMP(FRAME, TMP) \
{ \
*(TMP) = read_memory_integer ((FRAME)->frame + 0x4, 4); \
*(TMP) = read_memory_integer (*(TMP) + 0x8, 4); \
}
#define FRAME_FIND_SAVED_REGS_IN_SIGTRAMP(FRAME, FSR) \
{ \
int i; \
CORE_ADDR TMP; \
TMP = read_memory_integer ((FRAME)->frame + 0x4, 4); \
TMP = read_memory_integer (TMP + 0x10, 4); \
for (i = 0; i < NUM_REGS; i++) \
{ \
if (i == SP_REGNUM) \
(FSR)->regs[SP_REGNUM] = read_memory_integer (TMP + SP_REGNUM * 4, 4); \
else \
(FSR)->regs[i] = TMP + i * 4; \
} \
}
/* OSF1 needs an extra trap. I assume for the emulator startup (?!?) */
#define START_INFERIOR_TRAPS_EXPECTED 3
/* It's mostly just the common stuff. */
#include "pa/tm-hppa.h"

View File

@ -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);