From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3898 invoked by alias); 15 Mar 2004 20:08:42 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 3869 invoked from network); 15 Mar 2004 20:08:40 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 15 Mar 2004 20:08:40 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.10/8.12.10) with ESMTP id i2FK8d07008804 for ; Mon, 15 Mar 2004 15:08:39 -0500 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id i2FK8dS10103 for ; Mon, 15 Mar 2004 15:08:39 -0500 Received: from localhost.localdomain (vpn50-70.rdu.redhat.com [172.16.50.70]) by pobox.corp.redhat.com (8.12.8/8.12.8) with ESMTP id i2FK8c4q011304 for ; Mon, 15 Mar 2004 15:08:38 -0500 Received: from saguaro (saguaro.lan [192.168.64.2]) by localhost.localdomain (8.12.10/8.12.10) with SMTP id i2FK8WcG017586 for ; Mon, 15 Mar 2004 13:08:32 -0700 Date: Mon, 15 Mar 2004 20:08:00 -0000 From: Kevin Buettner To: gdb-patches@sources.redhat.com Subject: [PATCH] Add signal frame support for FR-V Linux Message-ID: <20040315130832.5edc5508@saguaro> Organization: Red Hat Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-SW-Source: 2004-03.o/txt/msg00327.txt Message-ID: <20040315200800.sJWkQOzv3OL-fB-dhf6_yLNMs1ldHRtavNzFtxKz5fc@z> I've just committed the patch below... * Makefile.in (frv-linux-tdep.o): Add dependencies. * frv-linux-tdep.c: New file. * frv-tdep.c (struct gdbarch_tdep): Add new field ``sigcontext_reg_addr''. (frv_set_sigcontext_reg_addr, frv_sigtramp,frame_cache) (frv_sigtramp_frame_this_id, frv_sigtramp_frame_prev_register) (frv_sigramp_frame_sniffer): New functions. (frv_sigtramp_frame_unwind): New static global. (frv_gdbarch_init): Hook in ABI-specific overrides. Hook up frame sniffers. * frv-tdep.h (frv_set_sigcontext_reg_addr): New function. * config/frv/frv.mt (TDEPFILES): Add frv-linux-tdep.o. Index: Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.522 diff -u -p -r1.522 Makefile.in --- Makefile.in 14 Mar 2004 22:39:26 -0000 1.522 +++ Makefile.in 15 Mar 2004 19:32:55 -0000 @@ -1766,6 +1766,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $( $(command_h) $(gdbcmd_h) frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \ $(gdb_assert_h) $(dummy_frame_h) +frv-linux-tdep.o: frv-linux-tdep.c $(defs_h) $(target_h) $(osabi_h) \ + $(elf_bfd_h) $(elf_frv_h) $(frv_tdep_h) frv-tdep.o: frv-tdep.c $(defs_h) $(gdb_string_h) $(inferior_h) $(gdbcore_h) \ $(arch_utils_h) $(regcache_h) $(frame_h) $(frame_unwind_h) \ $(frame_base_h) $(trad_frame_h) $(dis_asm_h) $(gdb_assert_h) \ Index: frv-linux-tdep.c =================================================================== RCS file: frv-linux-tdep.c diff -N frv-linux-tdep.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ frv-linux-tdep.c 15 Mar 2004 19:32:55 -0000 @@ -0,0 +1,273 @@ +/* Target-dependent code for GNU/Linux running on the Fujitsu FR-V, + for GDB. + 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 "target.h" +#include "frame.h" +#include "osabi.h" +#include "elf-bfd.h" +#include "elf/frv.h" +#include "frv-tdep.h" + +/* Define the size (in bytes) of an FR-V instruction. */ +static const int frv_instr_size = 4; + +enum { + NORMAL_SIGTRAMP = 1, + RT_SIGTRAMP = 2 +}; + +static int +frv_linux_pc_in_sigtramp (CORE_ADDR pc, char *name) +{ + char buf[frv_instr_size]; + LONGEST instr; + int retval = 0; + + if (target_read_memory (pc, buf, sizeof buf) != 0) + return 0; + + instr = extract_unsigned_integer (buf, sizeof buf); + + if (instr == 0x8efc0077) /* setlos #__NR_sigreturn, gr7 */ + retval = NORMAL_SIGTRAMP; + else if (instr -= 0x8efc00ad) /* setlos #__NR_rt_sigreturn, gr7 */ + retval = RT_SIGTRAMP; + else + return 0; + + if (target_read_memory (pc + frv_instr_size, buf, sizeof buf) != 0) + return 0; + instr = extract_unsigned_integer (buf, sizeof buf); + if (instr != 0xc0700000) /* tira gr0, 0 */ + return 0; + + /* If we get this far, we'll return a non-zero value, either + NORMAL_SIGTRAMP (1) or RT_SIGTRAMP (2). */ + return retval; +} + +/* Given NEXT_FRAME, "callee" frame of the sigtramp frame that we + wish to decode, and REGNO, one of the frv register numbers defined + in frv-tdep.h, return the address of the saved register (corresponding + to REGNO) in the sigtramp frame. Return -1 if the register is not + found in the sigtramp frame. The magic numbers in the code below + were computed by examining the following kernel structs: + + From arch/frvnommu/signal.c: + + struct sigframe + { + void (*pretcode)(void); + int sig; + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + uint32_t retcode[2]; + }; + + struct rt_sigframe + { + void (*pretcode)(void); + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + uint32_t retcode[2]; + }; + + From include/asm-frvnommu/ucontext.h: + + struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; + }; + + From include/asm-frvnommu/sigcontext.h: + + struct sigcontext { + struct user_context sc_context; + unsigned long sc_oldmask; + } __attribute__((aligned(8))); + + From include/asm-frvnommu/registers.h: + struct user_int_regs + { + unsigned long psr; + unsigned long isr; + unsigned long ccr; + unsigned long cccr; + unsigned long lr; + unsigned long lcr; + unsigned long pc; + unsigned long __status; + unsigned long syscallno; + unsigned long orig_gr8; + unsigned long gner[2]; + unsigned long long iacc[1]; + + union { + unsigned long tbr; + unsigned long gr[64]; + }; + }; + + struct user_fpmedia_regs + { + unsigned long fr[64]; + unsigned long fner[2]; + unsigned long msr[2]; + unsigned long acc[8]; + unsigned char accg[8]; + unsigned long fsr[1]; + }; + + struct user_context + { + struct user_int_regs i; + struct user_fpmedia_regs f; + + void *extension; + } __attribute__((aligned(8))); */ + +static CORE_ADDR +frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, + CORE_ADDR *sc_addr_cache_ptr) +{ + CORE_ADDR sc_addr; + + if (sc_addr_cache_ptr && *sc_addr_cache_ptr) + { + sc_addr = *sc_addr_cache_ptr; + } + else + { + CORE_ADDR pc, sp; + char buf[4]; + int tramp_type; + + pc = frame_pc_unwind (next_frame); + tramp_type = frv_linux_pc_in_sigtramp (pc, 0); + + frame_unwind_register (next_frame, sp_regnum, buf); + sp = extract_unsigned_integer (buf, sizeof buf); + + if (tramp_type == NORMAL_SIGTRAMP) + { + /* For a normal sigtramp frame, the sigcontext struct starts + at SP + 8. */ + sc_addr = sp + 8; + } + else if (tramp_type == RT_SIGTRAMP) + { + /* For a realtime sigtramp frame, SP + 12 contains a pointer + to the a ucontext struct. The ucontext struct contains + a sigcontext struct starting 12 bytes in. */ + if (target_read_memory (sp + 12, buf, sizeof buf) != 0) + { + warning ("Can't read realtime sigtramp frame."); + return 0; + } + sc_addr = extract_unsigned_integer (buf, sizeof buf); + sc_addr += 12; + } + else + internal_error (__FILE__, __LINE__, "not a signal trampoline"); + + if (sc_addr_cache_ptr) + *sc_addr_cache_ptr = sc_addr; + } + + switch (regno) + { + case psr_regnum : + return sc_addr + 0; + /* sc_addr + 4 has "isr", the Integer Status Register. */ + case ccr_regnum : + return sc_addr + 8; + case cccr_regnum : + return sc_addr + 12; + case lr_regnum : + return sc_addr + 16; + case lcr_regnum : + return sc_addr + 20; + case pc_regnum : + return sc_addr + 24; + /* sc_addr + 28 is __status, the exception status. + sc_addr + 32 is syscallno, the syscall number or -1. + sc_addr + 36 is orig_gr8, the original syscall arg #1. + sc_addr + 40 is gner[0]. + sc_addr + 44 is gner[1]. */ + case iacc0h_regnum : + return sc_addr + 48; + case iacc0l_regnum : + return sc_addr + 52; + default : + if (first_gpr_regnum <= regno && regno <= last_gpr_regnum) + return sc_addr + 56 + 4 * (regno - first_gpr_regnum); + else if (first_fpr_regnum <= regno && regno <= last_fpr_regnum) + return sc_addr + 312 + 4 * (regno - first_fpr_regnum); + else + return -1; /* not saved. */ + } +} + +static void +frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + /* When the FR-V Linux kernel calls a signal handler, the return + address points to a bit of code on the stack. This function is + used to identify this bit of code as a signal trampoline in order + to support backtracing through calls to signal handlers. */ + set_gdbarch_pc_in_sigtramp (gdbarch, frv_linux_pc_in_sigtramp); + frv_set_sigcontext_reg_addr (gdbarch, frv_linux_sigcontext_reg_addr); +} + +static enum gdb_osabi +frv_linux_elf_osabi_sniffer (bfd *abfd) +{ + int elf_flags; + + elf_flags = elf_elfheader (abfd)->e_flags; + + /* Assume GNU/Linux if using the FDPIC ABI. If/when another OS shows + up that uses this ABI, we'll need to start using .note sections + or some such. */ + if (elf_flags & EF_FRV_FDPIC) + return GDB_OSABI_LINUX; + else + return GDB_OSABI_UNKNOWN; +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_frv_linux_tdep (void); + +void +_initialize_frv_linux_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_frv, 0, GDB_OSABI_LINUX, frv_linux_init_abi); + gdbarch_register_osabi_sniffer (bfd_arch_frv, + bfd_target_elf_flavour, + frv_linux_elf_osabi_sniffer); +} Index: frv-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/frv-tdep.c,v retrieving revision 1.78 diff -u -p -r1.78 frv-tdep.c --- frv-tdep.c 15 Mar 2004 18:49:02 -0000 1.78 +++ frv-tdep.c 15 Mar 2004 19:32:55 -0000 @@ -96,6 +96,11 @@ struct gdbarch_tdep /* Register names. */ char **register_names; + + /* Given NEXT_FRAME, determine the address of register REGNO saved in + the calling sigtramp frame. */ + CORE_ADDR (*sigcontext_reg_addr) (struct frame_info *next_frame, int regno, + CORE_ADDR *); }; #define CURRENT_VARIANT (gdbarch_tdep (current_gdbarch)) @@ -107,6 +112,15 @@ frv_abi (struct gdbarch *gdbarch) return gdbarch_tdep (gdbarch)->frv_abi; } +/* Set sigcontext_reg_addr. */ +void +frv_set_sigcontext_reg_addr (struct gdbarch *gdbarch, + CORE_ADDR (*sigcontext_reg_addr) + (struct frame_info *, int, CORE_ADDR *)) +{ + gdbarch_tdep (gdbarch)->sigcontext_reg_addr = sigcontext_reg_addr; +} + /* Fetch the interpreter and executable loadmap addresses (for shared library support) for the FDPIC ABI. Return 0 if successful, -1 if not. (E.g, -1 will be returned if the ABI isn't the FDPIC ABI.) */ @@ -1344,6 +1358,101 @@ frv_unwind_dummy_id (struct gdbarch *gdb frame_pc_unwind (next_frame)); } +/* Signal trampolines. */ + +static struct frv_unwind_cache * +frv_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct frv_unwind_cache *cache; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + CORE_ADDR addr; + char buf[4]; + int regno; + CORE_ADDR sc_addr_cache_val = 0; + + if (*this_cache) + return *this_cache; + + cache = FRAME_OBSTACK_ZALLOC (struct frv_unwind_cache); + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + frame_unwind_register (next_frame, sp_regnum, buf); + cache->base = extract_unsigned_integer (buf, sizeof buf); + + for (regno = 0; regno < frv_num_regs; regno++) + { + cache->saved_regs[regno].addr + = tdep->sigcontext_reg_addr (next_frame, regno, &sc_addr_cache_val); + } + + + if (cache->saved_regs[sp_regnum].addr != -1 + && target_read_memory (cache->saved_regs[sp_regnum].addr, + buf, sizeof buf) == 0) + { + cache->prev_sp = extract_unsigned_integer (buf, sizeof buf); + + /* Now that we've bothered to read it out of memory, save the + prev frame's SP value in the cache. */ + trad_frame_set_value (cache->saved_regs, sp_regnum, cache->prev_sp); + } + else + { + warning ("Can't read SP value from sigtramp frame"); + } + + *this_cache = cache; + return cache; +} + +static void +frv_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct frv_unwind_cache *cache = + frv_sigtramp_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, frame_pc_unwind (next_frame)); +} + +static void +frv_sigtramp_frame_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) +{ + /* Make sure we've initialized the cache. */ + frv_sigtramp_frame_cache (next_frame, this_cache); + + frv_frame_prev_register (next_frame, this_cache, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind frv_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + frv_sigtramp_frame_this_id, + frv_sigtramp_frame_prev_register +}; + +static const struct frame_unwind * +frv_sigtramp_frame_sniffer (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + + /* We shouldn't even bother to try if the OSABI didn't register + a sigcontext_reg_addr handler. */ + if (!gdbarch_tdep (current_gdbarch)->sigcontext_reg_addr) + return NULL; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (PC_IN_SIGTRAMP (pc, name)) + return &frv_sigtramp_frame_unwind; + + return NULL; +} static struct gdbarch * frv_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) @@ -1434,8 +1543,9 @@ frv_gdbarch_init (struct gdbarch_info in set_gdbarch_unwind_pc (gdbarch, frv_unwind_pc); set_gdbarch_unwind_sp (gdbarch, frv_unwind_sp); set_gdbarch_frame_align (gdbarch, frv_frame_align); - frame_unwind_append_sniffer (gdbarch, frv_frame_sniffer); frame_base_set_default (gdbarch, &frv_frame_base); + /* We set the sniffer lower down after the OSABI hooks have been + established. */ /* Settings for calling functions in the inferior. */ set_gdbarch_push_dummy_call (gdbarch, frv_push_dummy_call); @@ -1479,6 +1589,15 @@ frv_gdbarch_init (struct gdbarch_info in if (frv_abi (gdbarch) == FRV_ABI_FDPIC) set_gdbarch_convert_from_func_ptr_addr (gdbarch, frv_convert_from_func_ptr_addr); + + /* Hook in ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch); + + /* Set the sigtramp frame sniffer. */ + frame_unwind_append_sniffer (gdbarch, frv_sigtramp_frame_sniffer); + + /* Set the fallback (prologue based) frame sniffer. */ + frame_unwind_append_sniffer (gdbarch, frv_frame_sniffer); return gdbarch; } Index: frv-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/frv-tdep.h,v retrieving revision 1.4 diff -u -p -r1.4 frv-tdep.h --- frv-tdep.h 13 Mar 2004 01:24:20 -0000 1.4 +++ frv-tdep.h 15 Mar 2004 19:32:55 -0000 @@ -84,6 +84,11 @@ enum { /* Return the FR-V ABI associated with GDBARCH. */ enum frv_abi frv_abi (struct gdbarch *gdbarch); +/* Associate a sigcontext address fetcher with GDBARCH. */ +void frv_set_sigcontext_reg_addr (struct gdbarch *gdbarch, + CORE_ADDR (*sigcontext_reg_addr) + (struct frame_info *, int, CORE_ADDR *)); + /* Fetch the interpreter and executable loadmap addresses (for shared library support) for the FDPIC ABI. Return 0 if successful, -1 if not. (E.g, -1 will be returned if the ABI isn't the FDPIC ABI.) */ Index: config/frv/frv.mt =================================================================== RCS file: /cvs/src/src/gdb/config/frv/frv.mt,v retrieving revision 1.3 diff -u -p -r1.3 frv.mt --- config/frv/frv.mt 13 Mar 2004 00:50:53 -0000 1.3 +++ config/frv/frv.mt 15 Mar 2004 19:32:56 -0000 @@ -1,5 +1,5 @@ # Target: Fujitsu FRV processor -TDEPFILES= frv-tdep.o solib.o solib-frv.o +TDEPFILES= frv-tdep.o frv-linux-tdep.o solib.o solib-frv.o TM_FILE= tm-frv.h SIM_OBS = remote-sim.o SIM = ../sim/frv/libsim.a