X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Falphanbsd-tdep.c;h=bc1738595a671aebb5ac6405b636c58ed676013c;hb=0f4d39d53de83e8b4ecf0eb1fa85182074b04bc5;hp=d10a3cab1597762c4488948f7456abd48536969d;hpb=ea5bc2a6064698fb3a18f816e1d8f11baa74180a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/alphanbsd-tdep.c b/gdb/alphanbsd-tdep.c index d10a3cab15..bc1738595a 100644 --- a/gdb/alphanbsd-tdep.c +++ b/gdb/alphanbsd-tdep.c @@ -1,12 +1,14 @@ -/* Target-dependent code for NetBSD/Alpha. - Copyright 2002 Free Software Foundation, Inc. +/* Target-dependent code for NetBSD/alpha. + + Copyright (C) 2002-2004, 2006-2012 Free Software Foundation, Inc. + Contributed by Wasabi Systems, 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,27 +17,97 @@ 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 "frame.h" #include "gdbcore.h" +#include "osabi.h" #include "regcache.h" +#include "regset.h" #include "value.h" +#include "gdb_assert.h" +#include "gdb_string.h" + #include "alpha-tdep.h" #include "alphabsd-tdep.h" #include "nbsd-tdep.h" +#include "solib-svr4.h" +#include "target.h" + +/* Core file support. */ + +/* Even though NetBSD/alpha used ELF since day one, it used the + traditional a.out-style core dump format before NetBSD 1.6. */ + +/* Sizeof `struct reg' in . */ +#define ALPHANBSD_SIZEOF_GREGS (32 * 8) + +/* Sizeof `struct fpreg' in = ALPHANBSD_SIZEOF_FPREGS); + + for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++) + { + if (regnum == i || regnum == -1) + regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8); + } + + if (regnum == ALPHA_FPCR_REGNUM || regnum == -1) + regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 32 * 8); +} + +/* Supply register REGNUM from the buffer specified by GREGS and LEN + in the general-purpose register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +static void +alphanbsd_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + const gdb_byte *regs = gregs; + int i; + + gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS); + + for (i = 0; i < ALPHA_ZERO_REGNUM; i++) + { + if (regnum == i || regnum == -1) + regcache_raw_supply (regcache, i, regs + i * 8); + } + + if (regnum == ALPHA_PC_REGNUM || regnum == -1) + regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8); +} + +/* Supply register REGNUM from the buffer specified by GREGS and LEN + in the general-purpose register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ static void -fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, - CORE_ADDR ignore) +alphanbsd_aout_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) { - char *regs, *fpregs; - int regno; + const gdb_byte *regs = gregs; + int i; - /* Table to map a gdb register number to a trapframe register index. */ + /* Table to map a GDB register number to a trapframe register index. */ static const int regmap[] = { 0, 1, 2, 3, @@ -47,76 +119,70 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, 21, 22, 23, 24, 25, 29, 26 }; -#define SIZEOF_TRAPFRAME (33 * 8) - - /* We get everything from one section. */ - if (which != 0) - return; - regs = core_reg_sect; - fpregs = core_reg_sect + SIZEOF_TRAPFRAME; + gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS); - if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG)) + for (i = 0; i < ARRAY_SIZE(regmap); i++) { - warning ("Wrong size register set in core file."); - return; + if (regnum == i || regnum == -1) + regcache_raw_supply (regcache, i, regs + regmap[i] * 8); } - /* Integer registers. */ - for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++) - supply_register (regno, regs + (regmap[regno] * 8)); - supply_register (ALPHA_ZERO_REGNUM, NULL); - supply_register (FP_REGNUM, NULL); - supply_register (PC_REGNUM, regs + (28 * 8)); + if (regnum == ALPHA_PC_REGNUM || regnum == -1) + regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8); - /* Floating point registers. */ - alphabsd_supply_fpreg (fpregs, -1); -} - -static void -fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which, - CORE_ADDR ignore) -{ - switch (which) + if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS) { - case 0: /* Integer registers. */ - if (core_reg_size != SIZEOF_STRUCT_REG) - warning ("Wrong size register set in core file."); - else - alphabsd_supply_reg (core_reg_sect, -1); - break; - - case 2: /* Floating point registers. */ - if (core_reg_size != SIZEOF_STRUCT_FPREG) - warning ("Wrong size FP register set in core file."); - else - alphabsd_supply_fpreg (core_reg_sect, -1); - break; - - default: - /* Don't know what kind of register request this is; just ignore it. */ - break; + regs += ALPHANBSD_SIZEOF_GREGS; + len -= ALPHANBSD_SIZEOF_GREGS; + alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len); } } -static struct core_fns alphanbsd_core_fns = +/* NetBSD/alpha register sets. */ + +static struct regset alphanbsd_gregset = +{ + NULL, + alphanbsd_supply_gregset +}; + +static struct regset alphanbsd_fpregset = { - bfd_target_unknown_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_core_registers, /* core_read_registers */ - NULL /* next */ + NULL, + alphanbsd_supply_fpregset }; -static struct core_fns alphanbsd_elfcore_fns = +static struct regset alphanbsd_aout_gregset = { - bfd_target_elf_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_elfcore_registers, /* core_read_registers */ - NULL /* next */ + NULL, + alphanbsd_aout_supply_gregset }; +/* Return the appropriate register set for the core section identified + by SECT_NAME and SECT_SIZE. */ + +const struct regset * +alphanbsd_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, size_t sect_size) +{ + if (strcmp (sect_name, ".reg") == 0 && sect_size >= ALPHANBSD_SIZEOF_GREGS) + { + if (sect_size >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS) + return &alphanbsd_aout_gregset; + else + return &alphanbsd_gregset; + } + + if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ALPHANBSD_SIZEOF_FPREGS) + return &alphanbsd_fpregset; + + return NULL; +} + + +/* Signal trampolines. */ + /* Under NetBSD/alpha, signal handler invocations can be identified by the designated code sequence that is used to return from a signal handler. In particular, the return address of a signal handler points to the @@ -133,29 +199,29 @@ static struct core_fns alphanbsd_elfcore_fns = sequence and can then check whether we really are executing in the signal trampoline. If not, -1 is returned, otherwise the offset from the start of the return sequence is returned. */ -static const unsigned int sigtramp_retcode[] = +static const unsigned char sigtramp_retcode[] = { - 0xa61e0000, /* ldq a0, 0(sp) */ - 0x23de0010, /* lda sp, 16(sp) */ - 0x201f0127, /* lda v0, 295(zero) */ - 0x00000083, /* call_pal callsys */ + 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */ + 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */ + 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */ + 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */ }; -#define RETCODE_NWORDS \ - (sizeof (sigtramp_retcode) / sizeof (sigtramp_retcode[0])) +#define RETCODE_NWORDS 4 +#define RETCODE_SIZE (RETCODE_NWORDS * 4) -LONGEST -alphanbsd_sigtramp_offset (CORE_ADDR pc) +static LONGEST +alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc) { - unsigned int ret[4], w; + unsigned char ret[RETCODE_SIZE], w[4]; LONGEST off; int i; - if (read_memory_nobpt (pc, (char *) &w, 4) != 0) + if (target_read_memory (pc, (char *) w, 4) != 0) return -1; for (i = 0; i < RETCODE_NWORDS; i++) { - if (w == sigtramp_retcode[i]) + if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0) break; } if (i == RETCODE_NWORDS) @@ -164,20 +230,34 @@ alphanbsd_sigtramp_offset (CORE_ADDR pc) off = i * 4; pc -= off; - if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) + if (target_read_memory (pc, (char *) ret, sizeof (ret)) != 0) return -1; - if (memcmp (ret, sigtramp_retcode, sizeof (sigtramp_retcode)) == 0) + if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0) return off; return -1; } static int -alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name) +alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch, + CORE_ADDR pc, const char *func_name) +{ + return (nbsd_pc_in_sigtramp (pc, func_name) + || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0); +} + +static CORE_ADDR +alphanbsd_sigcontext_addr (struct frame_info *frame) { - return (alphanbsd_sigtramp_offset (pc) >= 0); + /* FIXME: This is not correct for all versions of NetBSD/alpha. + We will probably need to disassemble the trampoline to figure + out which trampoline frame type we have. */ + if (!get_next_frame (frame)) + return 0; + return get_frame_base (get_next_frame (frame)); } + static void alphanbsd_init_abi (struct gdbarch_info info, @@ -185,26 +265,52 @@ alphanbsd_init_abi (struct gdbarch_info info, { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp); + /* Hook into the DWARF CFI frame unwinder. */ + alpha_dwarf2_init_abi (info, gdbarch); + + /* Hook into the MDEBUG frame unwinder. */ + alpha_mdebug_init_abi (info, gdbarch); /* NetBSD/alpha does not provide single step support via ptrace(2); we must use software single-stepping. */ set_gdbarch_software_single_step (gdbarch, alpha_software_single_step); - set_solib_svr4_fetch_link_map_offsets (gdbarch, - nbsd_lp64_solib_svr4_fetch_link_map_offsets); + /* NetBSD/alpha has SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset; + tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp; + tdep->sigcontext_addr = alphanbsd_sigcontext_addr; tdep->jb_pc = 2; tdep->jb_elt_size = 8; + + set_gdbarch_regset_from_core_section + (gdbarch, alphanbsd_regset_from_core_section); +} + + +static enum gdb_osabi +alphanbsd_core_osabi_sniffer (bfd *abfd) +{ + if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0) + return GDB_OSABI_NETBSD_ELF; + + return GDB_OSABI_UNKNOWN; } + + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_alphanbsd_tdep (void); void _initialize_alphanbsd_tdep (void) { - alpha_gdbarch_register_os_abi (ALPHA_ABI_NETBSD, alphanbsd_init_abi); + /* BFD doesn't set a flavour for NetBSD style a.out core files. */ + gdbarch_register_osabi_sniffer (bfd_arch_alpha, bfd_target_unknown_flavour, + alphanbsd_core_osabi_sniffer); - add_core_fns (&alphanbsd_core_fns); - add_core_fns (&alphanbsd_elfcore_fns); + gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF, + alphanbsd_init_abi); }