From mboxrd@z Thu Jan 1 00:00:00 1970 From: Randolph Chung To: gdb-patches@sources.redhat.com Subject: [patch/rfa] Signal trampoline unwinder for hppa-hpux Date: Thu, 20 May 2004 04:17:00 -0000 Message-id: <20040520041746.GW566@tausq.org> X-SW-Source: 2004-05/msg00594.html This patch implements a signal trampoline unwinder for hpux. It also cleans up some old sigtramp cruft that was in hppa-hpux-tdep.c. I tested this against hppa2.0w-hp-hpux11.11 and hppa2.0w-hp-hpux11.00, but I don't have a hpux machine running a 32-bit kernel to test. If anyone is interested in that target, please give it a try. It *should* work :) Unfortunately this still fails a lot of the signal related testcases. It is not because of a problem with the signal unwinder though: On HPUX-SOM, there is an export stub inserted into the call sequence in some cases; the export stub is hit on the return path from indirect function calls, and apparently on return from a signal handler. This creates an extra frame in the backtrace, viz: (gdb) bt #0 0x000029e4 in handle_USR1 (sig=0) at ../../../gdb/gdb/testsuite/gdb.base/annota1.c:18 #1 0x000029c8 in handle_USR1 () at ../../../gdb/gdb/testsuite/gdb.base/annota1.c:17 #2 #3 main () at ../../../gdb/gdb/testsuite/gdb.base/annota1.c:40 Frame 1 comes from the export stub. Because of this, the pattern matching in the backtrace test fails. I am not sure if this is a problem with the test script or with the handling of export stubs -- am I supposed to somehow supress the export stub from showing up in the backtrace? (if so, how?) Comments? ok to check in? randolph 2004-05-19 Randolph Chung * hppa-hpux-tdep.c (offsetof): Define. (hppa_hpux_pc_in_sigtramp, hppa32_hpux_frame_saved_pc_in_sigtramp) (hppa32_hpux_frame_base_before_sigtramp) (hppa32_hpux_frame_find_saved_regs_in_sigtramp) (hppa64_hpux_frame_saved_pc_in_sigtramp) (hppa64_hpux_frame_base_before_sigtramp) (hppa64_hpux_frame_find_saved_regs_in_sigtramp): Remove unused functions. (hppa_hpux_sigtramp_find_sigcontext, hppa_hpux_sigtramp_unwind_cache) (hppa_hpux_sigtramp_frame_unwind_cache, hppa_hpux_sigtramp_frame_this_id) (hppa_hpux_sigtramp_frame_prev_register, hppa_hpux_sigtramp_frame_unwind) (hppa_hpux_sigtramp_unwind_sniffer): New signal trampoline unwinder. (hppa_hpux_init_abi): Register sigtramp unwinder. Index: hppa-hpux-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/hppa-hpux-tdep.c,v retrieving revision 1.18 diff -u -p -r1.18 hppa-hpux-tdep.c --- hppa-hpux-tdep.c 7 May 2004 05:48:48 -0000 1.18 +++ hppa-hpux-tdep.c 20 May 2004 03:45:07 -0000 @@ -24,15 +24,21 @@ Foundation, Inc., 59 Temple Place - Suit #include "osabi.h" #include "gdb_string.h" #include "frame.h" +#include "frame-unwind.h" +#include "trad-frame.h" #include "symtab.h" #include "objfiles.h" #include "inferior.h" #include "infcall.h" #include "hppa-tdep.h" #include #include +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + /* Forward declarations. */ extern void _initialize_hppa_hpux_tdep (void); extern initialize_file_ftype _initialize_hppa_hpux_tdep; @@ -45,125 +52,6 @@ typedef struct } args_for_find_stub; -/* FIXME: brobecker 2002-12-25. The following functions will eventually - become static, after the multiarching conversion is done. */ -int hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name); -void hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp); -void hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp); -void hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi, - CORE_ADDR *fsr); -void hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp); -void hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp); -void hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi, - CORE_ADDR *fsr); - -int -hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name) -{ - /* Actually, for a PA running HPUX the kernel calls the signal handler - without an intermediate trampoline. Luckily the kernel always sets - the return pointer for the signal handler to point to _sigreturn. */ - return (name && (strcmp ("_sigreturn", name) == 0)); -} - -/* For hppa32_hpux_frame_saved_pc_in_sigtramp, - hppa32_hpux_frame_base_before_sigtramp and - hppa32_hpux_frame_find_saved_regs_in_sigtramp: - - The signal context structure pointer is always saved at the base - of the frame which "calls" the signal handler. We only want to find - the hardware save state structure, which lives 10 32bit words into - sigcontext structure. - - Within the hardware save state structure, registers are found in the - same order as the register numbers in GDB. - - At one time we peeked at %r31 rather than the PC queues to determine - what instruction took the fault. This was done on purpose, but I don't - remember why. Looking at the PC queues is really the right way, and - I don't remember why that didn't work when this code was originally - written. */ - -void -hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp) -{ - *tmp = read_memory_integer (get_frame_base (fi) + (43 * 4), 4); -} - -void -hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp) -{ - *tmp = read_memory_integer (get_frame_base (fi) + (40 * 4), 4); -} - -void -hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi, - CORE_ADDR *fsr) -{ - int i; - const CORE_ADDR tmp = get_frame_base (fi) + (10 * 4); - - for (i = 0; i < NUM_REGS; i++) - { - if (i == HPPA_SP_REGNUM) - fsr[HPPA_SP_REGNUM] = read_memory_integer (tmp + HPPA_SP_REGNUM * 4, 4); - else - fsr[i] = tmp + i * 4; - } -} - -/* For hppa64_hpux_frame_saved_pc_in_sigtramp, - hppa64_hpux_frame_base_before_sigtramp and - hppa64_hpux_frame_find_saved_regs_in_sigtramp: - - These functions are the PA64 ABI equivalents of the 32bits counterparts - above. See the comments there. - - For PA64, the save_state structure is at an offset of 24 32-bit words - from the sigcontext structure. The 64 bit general registers are at an - offset of 640 bytes from the beginning of the save_state structure, - and the floating pointer register are at an offset of 256 bytes from - the beginning of the save_state structure. */ - -void -hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp) -{ - *tmp = read_memory_integer - (get_frame_base (fi) + (24 * 4) + 640 + (33 * 8), 8); -} - -void -hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi, - CORE_ADDR *tmp) -{ - *tmp = read_memory_integer - (get_frame_base (fi) + (24 * 4) + 640 + (30 * 8), 8); -} - -void -hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi, - CORE_ADDR *fsr) -{ - int i; - const CORE_ADDR tmp1 = get_frame_base (fi) + (24 * 4) + 640; - const CORE_ADDR tmp2 = get_frame_base (fi) + (24 * 4) + 256; - - for (i = 0; i < NUM_REGS; i++) - { - if (i == HPPA_SP_REGNUM) - fsr[HPPA_SP_REGNUM] = read_memory_integer (tmp1 + HPPA_SP_REGNUM * 8, 8); - else if (i >= HPPA_FP0_REGNUM) - fsr[i] = tmp2 + (i - HPPA_FP0_REGNUM) * 8; - else - fsr[i] = tmp1 + i * 8; - } -} - /* Return one if PC is in the call path of a trampoline, else return zero. Note we return one for *any* call trampoline (long-call, arg-reloc), not @@ -1222,6 +1060,202 @@ child_get_current_exception_event (void) return ¤t_ex_event; } +/* Signal frames. */ + +static CORE_ADDR +hppa_hpux_sigtramp_find_sigcontext (CORE_ADDR sp, CORE_ADDR pc) +{ + unsigned int insns[5]; + + read_memory_nobpt (pc, (char *)insns, sizeof(insns)); + + /* This comes from _sigreturn: + 379a0000 ldo 0(%r28), %r26 + 6bd33fc9 stw %r19, -28(%sp) + 20200801 ldil -40000000, %r1 + e420e008 be,l 4(%sr7, %rr1), %sr0, %r31 + 34160116 ldi 139, %r22 */ + + if (extract_unsigned_integer (&insns[0], 4) != 0x379a0000 + || extract_unsigned_integer (&insns[1], 4) != 0x6bd33fc9 + || extract_unsigned_integer (&insns[2], 4) != 0x20200801 + || extract_unsigned_integer (&insns[3], 4) != 0xe420e008 + || extract_unsigned_integer (&insns[4], 4) != 0x34160116) + return 0; + + /* We can find a ucontext_t 1352 bytes above the stack. The first + element of the ucontext_t is a mcontext_t (save_state_t), which + contains the registers we want. */ + return sp - 1352; +} + +struct hppa_hpux_sigtramp_unwind_cache +{ + CORE_ADDR base; + struct trad_frame_saved_reg *saved_regs; +}; + +static struct hppa_hpux_sigtramp_unwind_cache * +hppa_hpux_sigtramp_frame_unwind_cache (struct frame_info *next_frame, + void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct hppa_hpux_sigtramp_unwind_cache *info; + unsigned int flag; + CORE_ADDR sp, pc, scptr; + int i, incr, off, szoff; + + if (*this_cache) + return *this_cache; + + info = FRAME_OBSTACK_ZALLOC (struct hppa_hpux_sigtramp_unwind_cache); + *this_cache = info; + info->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM); + pc = frame_pc_unwind (next_frame); + scptr = hppa_hpux_sigtramp_find_sigcontext (sp, pc); + + /* See /usr/include/machine/save_state.h for the structure of the save_state_t + structure. */ + + off = scptr; + flag = read_memory_unsigned_integer(scptr, 4); + + if (!(flag & 0x40)) + { + /* Narrow registers. */ + off = scptr + offsetof (save_state_t, ss_narrow); + incr = 4; + szoff = 0; + } + else + { + /* Wide registers. */ + off = scptr + offsetof (save_state_t, ss_wide) + 8; + incr = 8; + szoff = (tdep->bytes_per_address == 4 ? 4 : 0); + } + + for (i = 1; i < 32; i++) + { + info->saved_regs[HPPA_R0_REGNUM + i].addr = off + szoff; + off += incr; + } + + info->saved_regs[HPPA_SAR_REGNUM].addr = off + szoff; + off += incr; + + info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PCSQ_HEAD_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PCOQ_TAIL_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PCSQ_TAIL_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_EIEM_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_IIR_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_ISR_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_IOR_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_IPSW_REGNUM].addr = off + szoff; + off += incr; + + /* ignore ss_cpustate */ + off += incr; + + info->saved_regs[HPPA_SR4_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+1].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+2].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+3].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+4].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+5].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+6].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_SR4_REGNUM+7].addr = off + szoff; + off += incr; + + info->saved_regs[HPPA_RCR_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PID0_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PID1_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_CCR_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PID2_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_PID3_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_TR0_REGNUM].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_TR0_REGNUM + 1].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_TR0_REGNUM + 2].addr = off + szoff; + off += incr; + info->saved_regs[HPPA_CR27_REGNUM].addr = off + szoff; + off += incr; + + /* TODO: fp regs */ + + info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM); + + return info; +} + +static void +hppa_hpux_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) +{ + struct hppa_hpux_sigtramp_unwind_cache *info + = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache); + *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame)); +} + +static void +hppa_hpux_sigtramp_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct hppa_hpux_sigtramp_unwind_cache *info + = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache); + hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = { + SIGTRAMP_FRAME, + hppa_hpux_sigtramp_frame_this_id, + hppa_hpux_sigtramp_frame_prev_register +}; + +static const struct frame_unwind * +hppa_hpux_sigtramp_unwind_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM); + CORE_ADDR pc = frame_pc_unwind (next_frame); + + if (hppa_hpux_sigtramp_find_sigcontext (sp, pc)) + return &hppa_hpux_sigtramp_frame_unwind; + + return NULL; +} + static void hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -1237,6 +1277,8 @@ hppa_hpux_init_abi (struct gdbarch_info set_gdbarch_in_solib_return_trampoline (gdbarch, hppa_hpux_in_solib_return_trampoline); set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code); + + frame_unwind_append_sniffer (gdbarch, hppa_hpux_sigtramp_unwind_sniffer); } static void -- Randolph Chung Debian GNU/Linux Developer, hppa/ia64 ports http://www.tausq.org/