X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ffrv-linux-tdep.c;h=cee2d0c5e24fdb9e06fefdcdf74b45bcc7743007;hb=1ae58f0c640ccef6ae9cc9b349547bb552274b69;hp=b9447edc86e99bd4b41bf6e90fc0b9882754b5e1;hpb=e2b7c96630b46f3da7c97525ba900c638b679c8d;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/frv-linux-tdep.c b/gdb/frv-linux-tdep.c index b9447edc86..cee2d0c5e2 100644 --- a/gdb/frv-linux-tdep.c +++ b/gdb/frv-linux-tdep.c @@ -1,12 +1,13 @@ /* Target-dependent code for GNU/Linux running on the Fujitsu FR-V, for GDB. - Copyright 2004 Free Software Foundation, Inc. + + Copyright (C) 2004-2019 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,19 +16,22 @@ 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. */ + along with this program. If not, see . */ #include "defs.h" +#include "gdbcore.h" #include "target.h" #include "frame.h" #include "osabi.h" +#include "regcache.h" #include "elf-bfd.h" #include "elf/frv.h" #include "frv-tdep.h" #include "trad-frame.h" #include "frame-unwind.h" +#include "regset.h" +#include "linux-tdep.h" +#include "gdbarch.h" /* Define the size (in bytes) of an FR-V instruction. */ static const int frv_instr_size = 4; @@ -38,27 +42,29 @@ enum { }; static int -frv_linux_pc_in_sigtramp (CORE_ADDR pc, char *name) +frv_linux_pc_in_sigtramp (struct gdbarch *gdbarch, CORE_ADDR pc, + const char *name) { - char buf[frv_instr_size]; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte 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); + instr = extract_unsigned_integer (buf, sizeof buf, byte_order); if (instr == 0x8efc0077) /* setlos #__NR_sigreturn, gr7 */ retval = NORMAL_SIGTRAMP; - else if (instr -= 0x8efc00ad) /* setlos #__NR_rt_sigreturn, gr7 */ + 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); + instr = extract_unsigned_integer (buf, sizeof buf, byte_order); if (instr != 0xc0700000) /* tira gr0, 0 */ return 0; @@ -162,9 +168,11 @@ frv_linux_pc_in_sigtramp (CORE_ADDR pc, char *name) } __attribute__((aligned(8))); */ static LONGEST -frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, +frv_linux_sigcontext_reg_addr (struct frame_info *this_frame, int regno, CORE_ADDR *sc_addr_cache_ptr) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR sc_addr; if (sc_addr_cache_ptr && *sc_addr_cache_ptr) @@ -174,14 +182,14 @@ frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, else { CORE_ADDR pc, sp; - char buf[4]; + gdb_byte buf[4]; int tramp_type; - pc = frame_pc_unwind (next_frame); - tramp_type = frv_linux_pc_in_sigtramp (pc, 0); + pc = get_frame_pc (this_frame); + tramp_type = frv_linux_pc_in_sigtramp (gdbarch, pc, 0); - frame_unwind_register (next_frame, sp_regnum, buf); - sp = extract_unsigned_integer (buf, sizeof buf); + get_frame_register (this_frame, sp_regnum, buf); + sp = extract_unsigned_integer (buf, sizeof buf, byte_order); if (tramp_type == NORMAL_SIGTRAMP) { @@ -197,13 +205,13 @@ frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, uc_mcontext within struct ucontext is derived as follows: stack_t is a 12-byte struct and struct sigcontext is 8-byte aligned. This gives an offset of 8 + 12 + 4 (for - padding) = 24.) */ + padding) = 24.) */ 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 = extract_unsigned_integer (buf, sizeof buf, byte_order); sc_addr += 24; } else @@ -232,7 +240,7 @@ frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, 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]. */ + sc_addr + 44 is gner[1]. */ case iacc0h_regnum : return sc_addr + 48; case iacc0l_regnum : @@ -243,40 +251,42 @@ frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno, else if (first_fpr_regnum <= regno && regno <= last_fpr_regnum) return sc_addr + 312 + 4 * (regno - first_fpr_regnum); else - return -1; /* not saved. */ + return -1; /* not saved. */ } } /* Signal trampolines. */ static struct trad_frame_cache * -frv_linux_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) +frv_linux_sigtramp_frame_cache (struct frame_info *this_frame, + void **this_cache) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct trad_frame_cache *cache; - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); CORE_ADDR addr; - char buf[4]; + gdb_byte buf[4]; int regnum; CORE_ADDR sc_addr_cache_val = 0; struct frame_id this_id; if (*this_cache) - return *this_cache; + return (struct trad_frame_cache *) *this_cache; - cache = trad_frame_cache_zalloc (next_frame); + cache = trad_frame_cache_zalloc (this_frame); /* FIXME: cagney/2004-05-01: This is is long standing broken code. The frame ID's code address should be the start-address of the signal trampoline and not the current PC within that trampoline. */ - frame_unwind_register (next_frame, sp_regnum, buf); - this_id = frame_id_build (extract_unsigned_integer (buf, sizeof buf), - frame_pc_unwind (next_frame)); + get_frame_register (this_frame, sp_regnum, buf); + addr = extract_unsigned_integer (buf, sizeof buf, byte_order); + this_id = frame_id_build (addr, get_frame_pc (this_frame)); trad_frame_set_id (cache, this_id); for (regnum = 0; regnum < frv_num_regs; regnum++) { - LONGEST reg_addr = frv_linux_sigcontext_reg_addr (next_frame, regnum, + LONGEST reg_addr = frv_linux_sigcontext_reg_addr (this_frame, regnum, &sc_addr_cache_val); if (reg_addr != -1) trad_frame_set_reg_addr (cache, regnum, reg_addr); @@ -287,53 +297,172 @@ frv_linux_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache } static void -frv_linux_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache, - struct frame_id *this_id) +frv_linux_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) { - struct trad_frame_cache *cache = - frv_linux_sigtramp_frame_cache (next_frame, this_cache); + struct trad_frame_cache *cache + = frv_linux_sigtramp_frame_cache (this_frame, this_cache); trad_frame_get_id (cache, this_id); } -static void -frv_linux_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, gdb_byte *valuep) +static struct value * +frv_linux_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) { /* Make sure we've initialized the cache. */ - struct trad_frame_cache *cache = - frv_linux_sigtramp_frame_cache (next_frame, this_cache); - trad_frame_get_register (cache, next_frame, regnum, optimizedp, lvalp, - addrp, realnump, valuep); + struct trad_frame_cache *cache + = frv_linux_sigtramp_frame_cache (this_frame, this_cache); + return trad_frame_get_register (cache, this_frame, regnum); +} + +static int +frv_linux_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (frv_linux_pc_in_sigtramp (gdbarch, pc, name)) + return 1; + + return 0; } static const struct frame_unwind frv_linux_sigtramp_frame_unwind = { SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, frv_linux_sigtramp_frame_this_id, - frv_linux_sigtramp_frame_prev_register + frv_linux_sigtramp_frame_prev_register, + NULL, + frv_linux_sigtramp_frame_sniffer }; + +/* The FRV kernel defines ELF_NGREG as 46. We add 2 in order to include + the loadmap addresses in the register set. (See below for more info.) */ +#define FRV_ELF_NGREG (46 + 2) +typedef unsigned char frv_elf_greg_t[4]; +typedef struct { frv_elf_greg_t reg[FRV_ELF_NGREG]; } frv_elf_gregset_t; + +typedef unsigned char frv_elf_fpreg_t[4]; +typedef struct +{ + frv_elf_fpreg_t fr[64]; + frv_elf_fpreg_t fner[2]; + frv_elf_fpreg_t msr[2]; + frv_elf_fpreg_t acc[8]; + unsigned char accg[8]; + frv_elf_fpreg_t fsr[1]; +} frv_elf_fpregset_t; + +/* Register maps. */ + +static const struct regcache_map_entry frv_linux_gregmap[] = + { + { 1, psr_regnum, 4 }, + { 1, REGCACHE_MAP_SKIP, 4 }, /* isr */ + { 1, ccr_regnum, 4 }, + { 1, cccr_regnum, 4 }, + { 1, lr_regnum, 4 }, + { 1, lcr_regnum, 4 }, + { 1, pc_regnum, 4 }, + { 1, REGCACHE_MAP_SKIP, 4 }, /* __status */ + { 1, REGCACHE_MAP_SKIP, 4 }, /* syscallno */ + { 1, REGCACHE_MAP_SKIP, 4 }, /* orig_gr8 */ + { 1, gner0_regnum, 4 }, + { 1, gner1_regnum, 4 }, + { 1, REGCACHE_MAP_SKIP, 8 }, /* iacc0 */ + { 1, tbr_regnum, 4 }, + { 31, first_gpr_regnum + 1, 4 }, /* gr1 ... gr31 */ + + /* Technically, the loadmap addresses are not part of `pr_reg' as + found in the elf_prstatus struct. The fields which communicate + the loadmap address appear (by design) immediately after + `pr_reg' though, and the BFD function elf32_frv_grok_prstatus() + has been implemented to include these fields in the register + section that it extracts from the core file. So, for our + purposes, they may be viewed as registers. */ + + { 1, fdpic_loadmap_exec_regnum, 4 }, + { 1, fdpic_loadmap_interp_regnum, 4 }, + { 0 } + }; + +static const struct regcache_map_entry frv_linux_fpregmap[] = + { + { 64, first_fpr_regnum, 4 }, /* fr0 ... fr63 */ + { 1, fner0_regnum, 4 }, + { 1, fner1_regnum, 4 }, + { 1, msr0_regnum, 4 }, + { 1, msr1_regnum, 4 }, + { 8, acc0_regnum, 4 }, /* acc0 ... acc7 */ + { 1, accg0123_regnum, 4 }, + { 1, accg4567_regnum, 4 }, + { 1, fsr0_regnum, 4 }, + { 0 } + }; + +/* Unpack an frv_elf_gregset_t into GDB's register cache. */ + +static void +frv_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + int regi; + + /* gr0 always contains 0. Also, the kernel passes the TBR value in + this slot. */ + regcache->raw_supply_zeroed (first_gpr_regnum); + + /* Fill gr32, ..., gr63 with zeros. */ + for (regi = first_gpr_regnum + 32; regi <= last_gpr_regnum; regi++) + regcache->raw_supply_zeroed (regi); -static const struct frame_unwind * -frv_linux_sigtramp_frame_sniffer (struct frame_info *next_frame) + regcache_supply_regset (regset, regcache, regnum, gregs, len); +} + +/* FRV Linux kernel register sets. */ + +static const struct regset frv_linux_gregset = { - CORE_ADDR pc = frame_pc_unwind (next_frame); - char *name; + frv_linux_gregmap, + frv_linux_supply_gregset, regcache_collect_regset +}; - find_pc_partial_function (pc, &name, NULL, NULL); - if (frv_linux_pc_in_sigtramp (pc, name)) - return &frv_linux_sigtramp_frame_unwind; +static const struct regset frv_linux_fpregset = +{ + frv_linux_fpregmap, + regcache_supply_regset, regcache_collect_regset +}; - return NULL; +static void +frv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + cb (".reg", sizeof (frv_elf_gregset_t), sizeof (frv_elf_gregset_t), + &frv_linux_gregset, NULL, cb_data); + cb (".reg2", sizeof (frv_elf_fpregset_t), sizeof (frv_elf_fpregset_t), + &frv_linux_fpregset, NULL, cb_data); } + static void frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { + linux_init_abi (info, gdbarch); + /* Set the sigtramp frame sniffer. */ - frame_unwind_append_sniffer (gdbarch, frv_linux_sigtramp_frame_sniffer); + frame_unwind_append_unwinder (gdbarch, &frv_linux_sigtramp_frame_unwind); + + set_gdbarch_iterate_over_regset_sections + (gdbarch, frv_linux_iterate_over_regset_sections); } static enum gdb_osabi @@ -352,13 +481,11 @@ frv_linux_elf_osabi_sniffer (bfd *abfd) 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 (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);