Index: frame-unwind.h =================================================================== RCS file: /cvs/src/src/gdb/frame-unwind.h,v retrieving revision 1.9 diff -u -r1.9 frame-unwind.h --- frame-unwind.h 16 Jul 2003 22:29:13 -0000 1.9 +++ frame-unwind.h 16 Mar 2004 15:12:15 -0000 @@ -1,6 +1,6 @@ /* Definitions for a frame unwinder, for GDB, the GNU debugger. - Copyright 2003 Free Software Foundation, Inc. + Copyright 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +22,7 @@ #if !defined (FRAME_UNWIND_H) #define FRAME_UNWIND_H 1 +struct frame_data; struct frame_info; struct frame_id; struct frame_unwind; @@ -30,6 +31,13 @@ #include "frame.h" /* For enum frame_type. */ +/* Given the NEXT frame, take a wiff of THIS frame's registers (namely + the PC and attributes) and if it is the applicable unwinder, return + an unwind cache (allocated using frame_obstack_zalloc). */ + +typedef void *(frame_sniffer_ftype) (const struct frame_unwind *self, + struct frame_info *next_frame); + /* The following unwind functions assume a chain of frames forming the sequence: (outer) prev <-> this <-> next (inner). All the functions are called with called with the next frame's `struct @@ -65,7 +73,8 @@ with the other unwind methods. Memory for that cache should be allocated using frame_obstack_zalloc(). */ -typedef void (frame_this_id_ftype) (struct frame_info *next_frame, +typedef void (frame_this_id_ftype) (const struct frame_unwind *self, + struct frame_info *next_frame, void **this_prologue_cache, struct frame_id *this_id); @@ -101,7 +110,8 @@ with the other unwind methods. Memory for that cache should be allocated using frame_obstack_zalloc(). */ -typedef void (frame_prev_register_ftype) (struct frame_info *next_frame, +typedef void (frame_prev_register_ftype) (const struct frame_unwind *self, + struct frame_info *next_frame, void **this_prologue_cache, int prev_regnum, int *optimized, @@ -118,8 +128,16 @@ here? */ frame_this_id_ftype *this_id; frame_prev_register_ftype *prev_register; + const struct frame_data *unwind_data; + frame_sniffer_ftype *sniffer; }; +/* Register a frame unwinder, appending it to the end of the search + list. */ +extern void frame_unwind_append (struct gdbarch *gdbarch, + const struct frame_unwind *unwinder); + + /* Given the NEXT frame, take a wiff of THIS frame's registers (namely the PC and attributes) and if it is the applicable unwinder return the unwind methods, or NULL if it is not. */ @@ -134,8 +152,9 @@ frame_unwind_sniffer_ftype *sniffer); /* Iterate through the next frame's sniffers until one returns with an - unwinder implementation. */ + unwinder implementation. Possibly initialize THIS_CACHE. */ -extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame); +extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame, + void **this_cache); #endif Index: tramp-frame.h =================================================================== RCS file: tramp-frame.h diff -N tramp-frame.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tramp-frame.h 11 Mar 2004 21:59:53 -0000 1.1.2.1 @@ -0,0 +1,64 @@ +/* Signal trampoline unwinder, for GDB the GNU Debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef TRAMP_FRAME_H +#define TRAMP_FRAME_H + +struct trad_frame; +struct frame_info; +struct trad_frame_cache; + +/* A trampline consists of a small sequence of instructions placed at + an unspecified location in the inferior's address space. The only + identifying attribute of the trampoline's address is that it does + not fall inside an object file's section. + + The only way to identify a trampoline is to perform a brute force + examination of the instructions at and around the PC. + + This module provides a convient interface for performing that + operation. */ + +/* A trampoline descriptor. */ + +struct tramp_frame +{ + /* The trampoline's entire instruction sequence. Search for this in + the inferior at or around the frame's PC. It is assumed that the + PC is INSN_SIZE aligned, and that each element of TRAMP containts + one INSN_SIZE instruction. It is also assumed that TRAMP[0] + contains the first instruction of the trampoline and hence the + address of the instruction matching TRAMP[0] is the trampolines + "func" address. */ + int insn_size; + ULONGEST insn[8]; + /* Initialize a trad-frame cache corresponding to the tramp-frame. + FUNC is the address of the instruction TRAMP[0] in memory. */ + void (*init) (const struct tramp_frame *self, + struct frame_info *next_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func); +}; + +void tramp_frame_append (struct gdbarch *gdbarch, + const struct tramp_frame *tramp); + +#endif Index: ppcnbsd-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/ppcnbsd-tdep.c,v retrieving revision 1.11 retrieving revision 1.11.10.1 diff -u -r1.11 -r1.11.10.1 --- ppcnbsd-tdep.c 10 Nov 2003 22:47:28 -0000 1.11 +++ ppcnbsd-tdep.c 9 Mar 2004 22:59:00 -0000 1.11.10.1 @@ -30,6 +30,8 @@ #include "ppc-tdep.h" #include "ppcnbsd-tdep.h" #include "nbsd-tdep.h" +#include "tramp-frame.h" +#include "trad-frame.h" #include "solib-svr4.h" @@ -228,6 +230,57 @@ } static void +ppcnbsd_sigtramp_cache_init (const struct tramp_frame *self, + struct frame_info *next_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func) +{ + CORE_ADDR offset; + int i; + struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + this_cache->this_base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + offset = this_cache->this_base + 0x18 + 2 * tdep->wordsize; + for (i = 0; i < 32; i++) + { + int regnum = i + tdep->ppc_gp0_regnum; + this_cache->prev_regs[regnum].addr = offset; + offset += tdep->wordsize; + } + this_cache->prev_regs[tdep->ppc_lr_regnum].addr = offset; + offset += tdep->wordsize; + this_cache->prev_regs[tdep->ppc_cr_regnum].addr = offset; + offset += tdep->wordsize; + this_cache->prev_regs[tdep->ppc_xer_regnum].addr = offset; + offset += tdep->wordsize; + this_cache->prev_regs[tdep->ppc_ctr_regnum].addr = offset; + offset += tdep->wordsize; + this_cache->prev_regs[PC_REGNUM].addr = offset; /* SRR0? */ + offset += tdep->wordsize; + + /* Construct the frame ID using the function start. */ + this_cache->this_id = frame_id_build (this_cache->this_base, func); +} + +/* 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 const struct tramp_frame ppcnbsd_sigtramp = { + 4, /* insn size */ + { /* insn */ + 0x38610018, /* addi r3,r1,24 */ + 0x38000127, /* li r0,295 */ + 0x44000002, /* sc */ + 0x38000001, /* li r0,1 */ + 0x44000002, /* sc */ + }, + ppcnbsd_sigtramp_cache_init +}; + +static void ppcnbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -237,6 +290,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); + tramp_frame_append (gdbarch, &ppcnbsd_sigtramp); } void Index: tramp-frame.c =================================================================== RCS file: tramp-frame.c diff -N tramp-frame.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tramp-frame.c 16 Mar 2004 15:12:23 -0000 @@ -0,0 +1,161 @@ +/* Signal trampoline unwinder, for GDB the GNU Debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "tramp-frame.h" +#include "frame-unwind.h" +#include "gdbcore.h" +#include "symtab.h" +#include "objfiles.h" +#include "target.h" +#include "trad-frame.h" + +struct frame_data +{ + const struct tramp_frame *tramp_frame; +}; + +struct tramp_frame_cache +{ + CORE_ADDR func; + struct trad_frame_cache *trad_cache; +}; + +static struct trad_frame_cache * +tramp_frame_cache (const struct frame_unwind *self, + struct frame_info *next_frame, + void **this_cache) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + struct tramp_frame_cache *tramp_cache = (*this_cache); + if (tramp_cache->trad_cache == NULL) + { + tramp_cache->trad_cache = trad_frame_cache_zalloc (next_frame); + self->unwind_data->tramp_frame->init (self->unwind_data->tramp_frame, + next_frame, + tramp_cache->trad_cache, + tramp_cache->func); + } + return tramp_cache->trad_cache; +} + +static void +tramp_frame_this_id (const struct frame_unwind *self, + struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct trad_frame_cache *trad_cache + = tramp_frame_cache (self, next_frame, this_cache); + trad_frame_this_id (trad_cache, next_frame, this_id); +} + +static void +tramp_frame_prev_register (const struct frame_unwind *self, + struct frame_info *next_frame, + void **this_cache, + int prev_regnum, + int *optimizedp, + enum lval_type * lvalp, + CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct trad_frame_cache *trad_cache + = tramp_frame_cache (self, next_frame, this_cache); + trad_frame_prev_register (trad_cache, next_frame, prev_regnum, optimizedp, + lvalp, addrp, realnump, valuep); +} + +static CORE_ADDR +tramp_frame_start (CORE_ADDR pc, const struct tramp_frame *tramp) +{ + int ti; + /* Search through the trampoline for one that matches the + instruction sequence around PC. */ + for (ti = 0; tramp->insn[ti] != 0; ti++) + { + CORE_ADDR func = pc - tramp->insn_size * ti; + int i; + for (i = 0; 1; i++) + { + bfd_byte buf[sizeof (LONGEST)]; + CORE_ADDR insn; + if (tramp->insn[i] == 0) + return func; + if (target_read_memory (func + i * tramp->insn_size, buf, + tramp->insn_size) != 0) + break; + insn = extract_unsigned_integer (buf, tramp->insn_size); + if (tramp->insn[i] != insn) + break; + } + } + /* Trampoline doesn't match. */ + return 0; +} + +static void * +tramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *next_frame) +{ + const struct tramp_frame *tramp = self->unwind_data->tramp_frame; + CORE_ADDR pc = frame_pc_unwind (next_frame); + CORE_ADDR func; + char *name; + struct tramp_frame_cache *tramp_cache; + + /* If the function has a valid symbol name, it isn't a + trampoline. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (name != NULL) + return NULL; + /* If the function lives in a valid section (even without a starting + point) it isn't a trampoline. */ + if (find_pc_section (pc) != NULL) + return NULL; + /* Finally, check that the trampoline matches at PC. */ + func = tramp_frame_start (pc, tramp); + if (func == 0) + return NULL; + tramp_cache = FRAME_OBSTACK_ZALLOC (struct tramp_frame_cache); + tramp_cache->func = func; + return tramp_cache; +} + +void +tramp_frame_append (struct gdbarch *gdbarch, + const struct tramp_frame *tramp_frame) +{ + struct frame_data *data; + struct frame_unwind *unwinder; + + data = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_data); + unwinder = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind); + + data->tramp_frame = tramp_frame; + unwinder->type = SIGTRAMP_FRAME; + unwinder->unwind_data = data; + unwinder->sniffer = tramp_frame_sniffer; + unwinder->this_id = tramp_frame_this_id; + unwinder->prev_register = tramp_frame_prev_register; + + frame_unwind_append (gdbarch, unwinder); +}