From 70e43abe7c41fcf6b7682aab3c6fd9716c255dc2 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 4 Mar 1994 17:54:41 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 17 ++++ gdb/config/pa/tm-hppab.h | 43 +++++++++- gdb/config/pa/tm-hppao.h | 46 ++++++++++- gdb/hppa-tdep.c | 173 ++++++++++++++++++++++++++++++++++----- 4 files changed, 255 insertions(+), 24 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index de9ed0842f9..c5fa1b9b289 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 diff --git a/gdb/config/pa/tm-hppab.h b/gdb/config/pa/tm-hppab.h index 73ff419a520..1cd438df75e 100644 --- a/gdb/config/pa/tm-hppab.h +++ b/gdb/config/pa/tm-hppab.h @@ -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" diff --git a/gdb/config/pa/tm-hppao.h b/gdb/config/pa/tm-hppao.h index 9697a2c340e..fd0d25c721b 100644 --- a/gdb/config/pa/tm-hppao.h +++ b/gdb/config/pa/tm-hppao.h @@ -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" diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index ca849c5a119..da8ffc5fd0e 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); -- 2.30.2