2004-03-03 Andrew Cagney * ppcnbsd-tdep.c: Include "objfiles.h", "trad-frame.h", and "frame-unwind.h". (struct ppcnbsd_sigtramp_cache, ppcnbsd_sigtramp_this_id) (ppcnbsd_sigtramp_prev_register, ppcnbsd_sigtramp_cache) (ppcnbsd_sigtramp_sniffer, ppcnbsd_sigtramp_unwind) (ppcnbsd_sigtramp_start, ppcnbsd_init_abi): Implement a NetBSD/PPC signal trampline unwinder, register. Index: ppcnbsd-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/ppcnbsd-tdep.c,v retrieving revision 1.11 diff -u -r1.11 ppcnbsd-tdep.c --- ppcnbsd-tdep.c 10 Nov 2003 22:47:28 -0000 1.11 +++ ppcnbsd-tdep.c 5 Mar 2004 15:39:35 -0000 @@ -26,6 +26,9 @@ #include "breakpoint.h" #include "value.h" #include "osabi.h" +#include "trad-frame.h" +#include "frame-unwind.h" +#include "objfiles.h" #include "ppc-tdep.h" #include "ppcnbsd-tdep.h" @@ -227,6 +230,165 @@ readbuf, writebuf); } +/* Given the NEXTE frame, examine the instructions at and around this + frame's resume address (aka PC) to see of they look like a signal + trampoline. Return the address of the trampolines first + instruction, or zero if it isn't a signal trampoline. */ + +static CORE_ADDR +ppcnbsd_sigtramp_start (struct frame_info *next_frame) +{ + static const long sigtramp[] = { + 0x38610018, /* addi r3,r1,24 */ + 0x38000127, /* li r0,295 */ + 0x44000002, /* sc */ + 0x38000001, /* li r0,1 */ + 0x44000002, /* sc */ + }; + CORE_ADDR pc = frame_pc_unwind (next_frame); + long pcinsn; + int pci; + + /* Fetch the instruction at PC and try to find it in the + sigtramp. */ + pcinsn = read_memory_unsigned_integer (pc, 4); + for (pci = 0; pci < ARRAY_SIZE (sigtramp); pci++) + { + if (sigtramp[pci] == pcinsn) + { + /* With the PC's instruction found, check that the remaining + instructions also match. Because there are two SC's in + the above, this part may need to be executed more than + once. */ + int i; + long insn; + for (i = 0; i < ARRAY_SIZE (sigtramp); i++) + { + if (i == pci) continue; + insn = read_memory_unsigned_integer (pc + 4 * (i - pci), 4); + if (sigtramp[i] != insn) + break; + } + /* All matched, return the start of the signal + trampoline. */ + if (i >= ARRAY_SIZE (sigtramp)) + return pc - 4 * pci; + } + } + /* Not a sigtramp. */ + return 0; +} + +struct ppcnbsd_sigtramp_cache +{ + struct frame_id this_id; + CORE_ADDR this_base; + struct trad_frame_saved_reg *saved_regs; +}; + +static struct ppcnbsd_sigtramp_cache * +ppcnbsd_sigtramp_cache (struct frame_info *next_frame, void **this_cache) +{ + CORE_ADDR offset; + int i; + struct ppcnbsd_sigtramp_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if ((*this_cache) != NULL) + return (*this_cache); + cache = FRAME_OBSTACK_ZALLOC (struct ppcnbsd_sigtramp_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + cache->this_base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + offset = cache->this_base + 0x18 + 2 * tdep->wordsize; + for (i = 0; i < 32; i++) + { + int regnum = i + tdep->ppc_gp0_regnum; + cache->saved_regs[regnum].addr = offset; + offset += tdep->wordsize; + } + cache->saved_regs[tdep->ppc_lr_regnum].addr = offset; + offset += tdep->wordsize; + cache->saved_regs[tdep->ppc_cr_regnum].addr = offset; + offset += tdep->wordsize; + cache->saved_regs[tdep->ppc_xer_regnum].addr = offset; + offset += tdep->wordsize; + cache->saved_regs[tdep->ppc_ctr_regnum].addr = offset; + offset += tdep->wordsize; + cache->saved_regs[PC_REGNUM].addr = offset; /* SRR0? */ + offset += tdep->wordsize; + + /* Construct the frame ID using the function start. */ + { + CORE_ADDR func = frame_func_unwind (next_frame); + if (func == 0) + cache->this_id = frame_id_build (cache->this_base, + ppcnbsd_sigtramp_start (next_frame)); + else + cache->this_id = frame_id_build (cache->this_base, func); + } + + return cache; +} + +static void +ppcnbsd_sigtramp_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct ppcnbsd_sigtramp_cache *info = ppcnbsd_sigtramp_cache (next_frame, + this_cache); + (*this_id) = info->this_id; +} + +static void +ppcnbsd_sigtramp_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct ppcnbsd_sigtramp_cache *info = ppcnbsd_sigtramp_cache (next_frame, + this_cache); + trad_frame_prev_register (next_frame, info->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind ppcnbsd_sigtramp_unwind = +{ + SIGTRAMP_FRAME, + ppcnbsd_sigtramp_this_id, + ppcnbsd_sigtramp_prev_register +}; + +static const struct frame_unwind * +ppcnbsd_sigtramp_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + find_pc_partial_function (pc, &name, NULL, NULL); + if (name != NULL) + { + /* A modern unwinder (post 1.6.x) that lives in libc. It can be + identified by its name. */ + if (nbsd_pc_in_sigtramp (pc, name)) + return &ppcnbsd_sigtramp_unwind; + else + return NULL; + } + if (find_pc_section (pc) != NULL) + /* Old style signal trampolines (which lived on the stack) never + had a section, so if one is found, it can't be a sigtramp. */ + return NULL; + /* Examine instructions around PC to see if they match the sigtramp, + if they do ok. */ + if (ppcnbsd_sigtramp_start (next_frame) != 0) + return &ppcnbsd_sigtramp_unwind; + else + return NULL; +} + static void ppcnbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -237,6 +399,7 @@ set_gdbarch_return_value (gdbarch, ppcnbsd_return_value); set_solib_svr4_fetch_link_map_offsets (gdbarch, nbsd_ilp32_solib_svr4_fetch_link_map_offsets); + frame_unwind_append_sniffer (gdbarch, ppcnbsd_sigtramp_sniffer); } void