From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13252 invoked by alias); 5 Mar 2004 16:06:03 -0000 Mailing-List: contact gdb-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 13242 invoked from network); 5 Mar 2004 16:06:01 -0000 Received: from unknown (HELO localhost.redhat.com) (216.129.200.20) by sources.redhat.com with SMTP; 5 Mar 2004 16:06:01 -0000 Received: from gnu.org (localhost [127.0.0.1]) by localhost.redhat.com (Postfix) with ESMTP id 924552B92; Fri, 5 Mar 2004 11:05:54 -0500 (EST) Message-ID: <4048A562.5020106@gnu.org> Date: Fri, 05 Mar 2004 16:06:00 -0000 From: Andrew Cagney User-Agent: Mozilla/5.0 (X11; U; NetBSD macppc; en-GB; rv:1.4.1) Gecko/20040217 MIME-Version: 1.0 To: gdb@sources.redhat.com Subject: get_frame_func() VS get_frame_id().code Content-Type: multipart/mixed; boundary="------------010801020500070601040108" X-SW-Source: 2004-03/txt/msg00036.txt.bz2 This is a multi-part message in MIME format. --------------010801020500070601040108 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1445 Hello, The current get_frame_func() is implemented as roughly: fi->prev_func.addr = get_pc_function_start (addr_in_block); Unfortunatly this isn't valid for a signal trampoline (or at least the evil ones that consist of random bytes in a random memory location). For such trampolines, get_pc_function_start [rightly] fails and "func" ends up as zero -- not good -- a properly constructed frame ID requires non-zero code and stack addresses. Fortunatly, with a bit of extra instruction pattern matching, it is possible to identify the first instruction of a signal trampoline and hence correctly compute the trampolines "func" address. Similarly, more normal frames can determine the function start using the symbol table's get_pc_function_start. Consequently, I think there should be mechanism for obtaining both the symbol table and frame's idea of a function's start address. This would mean introducing: - get_frame_func_by_symtab Returns the function start according to the symbol table. Much of the existing code (especially unwinders) would need to be updated to use this. - get_frame_func_by_id Returns the function start based on the frame ID. With the first change made, this could even be called get_frame_func. I've attached a proof-of-concept and as such the patch points to a number of additional changes (the most obvious being the need for a "tramp-frame" that generalizes the technique). Andrew --------------010801020500070601040108 Content-Type: text/plain; name="diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diffs" Content-length: 6297 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 --------------010801020500070601040108--