X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmips-linux-nat.c;h=2db2969c5fee7190d1257e43cab1c448b8850550;hb=2bd7c093f663139ad9e57ddc748ade12f6bfbe01;hp=15b23a2ffcb6ec7ff1383d07ef037a43a5fcf8b8;hpb=6aba47ca06d9150c6196a374b745c2711b46e045;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c index 15b23a2ffc..2db2969c5f 100644 --- a/gdb/mips-linux-nat.c +++ b/gdb/mips-linux-nat.c @@ -1,13 +1,13 @@ /* Native-dependent code for GNU/Linux on MIPS processors. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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, @@ -16,21 +16,26 @@ 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., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "inferior.h" #include "mips-tdep.h" #include "target.h" +#include "regcache.h" #include "linux-nat.h" #include "mips-linux-tdep.h" +#include "target-descriptions.h" #include "gdb_proc_service.h" +#include "gregset.h" +#include #include +#include "features/mips-linux.c" +#include "features/mips64-linux.c" + #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 25 #endif @@ -42,48 +47,84 @@ static int have_ptrace_regsets = 1; /* Saved function pointers to fetch and store a single register using PTRACE_PEEKUSER and PTRACE_POKEUSER. */ -void (*super_fetch_registers) (int); -void (*super_store_registers) (int); +void (*super_fetch_registers) (struct target_ops *, struct regcache *, int); +void (*super_store_registers) (struct target_ops *, struct regcache *, int); + +/* Map gdb internal register number to ptrace ``address''. + These ``addresses'' are normally defined in . -/* Pseudo registers can not be read. ptrace does not provide a way to - read (or set) MIPS_PS_REGNUM, and there's no point in reading or - setting MIPS_ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or - FCRIR via ptrace(). */ + ptrace does not provide a way to read (or set) MIPS_PS_REGNUM, + and there's no point in reading or setting MIPS_ZERO_REGNUM. + We also can not set BADVADDR, CAUSE, or FCRIR via ptrace(). */ -int -mips_linux_cannot_fetch_register (int regno) +static CORE_ADDR +mips_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) { + CORE_ADDR regaddr; + + if (regno < 0 || regno >= gdbarch_num_regs (gdbarch)) + error (_("Bogon register number %d."), regno); + if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32) - return 0; - else if (regno >= mips_regnum (current_gdbarch)->fp0 - && regno <= mips_regnum (current_gdbarch)->fp0 + 32) - return 0; - else if (regno == mips_regnum (current_gdbarch)->lo - || regno == mips_regnum (current_gdbarch)->hi - || regno == mips_regnum (current_gdbarch)->badvaddr - || regno == mips_regnum (current_gdbarch)->cause - || regno == mips_regnum (current_gdbarch)->pc - || regno == mips_regnum (current_gdbarch)->fp_control_status - || regno == mips_regnum (current_gdbarch)->fp_implementation_revision) - return 0; + regaddr = regno; + else if ((regno >= mips_regnum (gdbarch)->fp0) + && (regno < mips_regnum (gdbarch)->fp0 + 32)) + regaddr = FPR_BASE + (regno - mips_regnum (gdbarch)->fp0); + else if (regno == mips_regnum (gdbarch)->pc) + regaddr = PC; + else if (regno == mips_regnum (gdbarch)->cause) + regaddr = store? (CORE_ADDR) -1 : CAUSE; + else if (regno == mips_regnum (gdbarch)->badvaddr) + regaddr = store? (CORE_ADDR) -1 : BADVADDR; + else if (regno == mips_regnum (gdbarch)->lo) + regaddr = MMLO; + else if (regno == mips_regnum (gdbarch)->hi) + regaddr = MMHI; + else if (regno == mips_regnum (gdbarch)->fp_control_status) + regaddr = FPC_CSR; + else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) + regaddr = store? (CORE_ADDR) -1 : FPC_EIR; + else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM) + regaddr = 0; else - return 1; + regaddr = (CORE_ADDR) -1; + + return regaddr; } -int -mips_linux_cannot_store_register (int regno) +static CORE_ADDR +mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) { + CORE_ADDR regaddr; + + if (regno < 0 || regno >= gdbarch_num_regs (gdbarch)) + error (_("Bogon register number %d."), regno); + if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32) - return 0; - else if (regno >= FP0_REGNUM && regno <= FP0_REGNUM + 32) - return 0; - else if (regno == mips_regnum (current_gdbarch)->lo - || regno == mips_regnum (current_gdbarch)->hi - || regno == mips_regnum (current_gdbarch)->pc - || regno == mips_regnum (current_gdbarch)->fp_control_status) - return 0; + regaddr = regno; + else if ((regno >= mips_regnum (gdbarch)->fp0) + && (regno < mips_regnum (gdbarch)->fp0 + 32)) + regaddr = MIPS64_FPR_BASE + (regno - gdbarch_fp0_regnum (gdbarch)); + else if (regno == mips_regnum (gdbarch)->pc) + regaddr = MIPS64_PC; + else if (regno == mips_regnum (gdbarch)->cause) + regaddr = store? (CORE_ADDR) -1 : MIPS64_CAUSE; + else if (regno == mips_regnum (gdbarch)->badvaddr) + regaddr = store? (CORE_ADDR) -1 : MIPS64_BADVADDR; + else if (regno == mips_regnum (gdbarch)->lo) + regaddr = MIPS64_MMLO; + else if (regno == mips_regnum (gdbarch)->hi) + regaddr = MIPS64_MMHI; + else if (regno == mips_regnum (gdbarch)->fp_control_status) + regaddr = MIPS64_FPC_CSR; + else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) + regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR; + else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM) + regaddr = 0; else - return 1; + regaddr = (CORE_ADDR) -1; + + return regaddr; } /* Fetch the thread-local storage pointer for libthread_db. */ @@ -103,21 +144,63 @@ ps_get_thread_area (const struct ps_prochandle *ph, return PS_OK; } +/* Wrapper functions. These are only used by libthread_db. */ + +void +supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) +{ + if (mips_isa_regsize (get_regcache_arch (regcache)) == 4) + mips_supply_gregset (regcache, (const mips_elf_gregset_t *) gregsetp); + else + mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *) gregsetp); +} + +void +fill_gregset (const struct regcache *regcache, + gdb_gregset_t *gregsetp, int regno) +{ + if (mips_isa_regsize (get_regcache_arch (regcache)) == 4) + mips_fill_gregset (regcache, (mips_elf_gregset_t *) gregsetp, regno); + else + mips64_fill_gregset (regcache, (mips64_elf_gregset_t *) gregsetp, regno); +} + +void +supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp) +{ + if (mips_isa_regsize (get_regcache_arch (regcache)) == 4) + mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *) fpregsetp); + else + mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp); +} + +void +fill_fpregset (const struct regcache *regcache, + gdb_fpregset_t *fpregsetp, int regno) +{ + if (mips_isa_regsize (get_regcache_arch (regcache)) == 4) + mips_fill_fpregset (regcache, (mips_elf_fpregset_t *) fpregsetp, regno); + else + mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno); +} + + /* Fetch REGNO (or all registers if REGNO == -1) from the target using PTRACE_GETREGS et al. */ static void -mips64_linux_regsets_fetch_registers (int regno) +mips64_linux_regsets_fetch_registers (struct regcache *regcache, int regno) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); int is_fp; int tid; - if (regno >= mips_regnum (current_gdbarch)->fp0 - && regno <= mips_regnum (current_gdbarch)->fp0 + 32) + if (regno >= mips_regnum (gdbarch)->fp0 + && regno <= mips_regnum (gdbarch)->fp0 + 32) is_fp = 1; - else if (regno == mips_regnum (current_gdbarch)->fp_control_status) + else if (regno == mips_regnum (gdbarch)->fp_control_status) is_fp = 1; - else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) + else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) is_fp = 1; else is_fp = 0; @@ -140,7 +223,8 @@ mips64_linux_regsets_fetch_registers (int regno) perror_with_name (_("Couldn't get registers")); } - mips64_supply_gregset (®s); + mips64_supply_gregset (regcache, + (const mips64_elf_gregset_t *) ®s); } if (regno == -1 || is_fp) @@ -158,7 +242,8 @@ mips64_linux_regsets_fetch_registers (int regno) perror_with_name (_("Couldn't get FP registers")); } - mips64_supply_fpregset (&fp_regs); + mips64_supply_fpregset (regcache, + (const mips64_elf_fpregset_t *) &fp_regs); } } @@ -166,17 +251,18 @@ mips64_linux_regsets_fetch_registers (int regno) using PTRACE_SETREGS et al. */ static void -mips64_linux_regsets_store_registers (int regno) +mips64_linux_regsets_store_registers (const struct regcache *regcache, int regno) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); int is_fp; int tid; - if (regno >= mips_regnum (current_gdbarch)->fp0 - && regno <= mips_regnum (current_gdbarch)->fp0 + 32) + if (regno >= mips_regnum (gdbarch)->fp0 + && regno <= mips_regnum (gdbarch)->fp0 + 32) is_fp = 1; - else if (regno == mips_regnum (current_gdbarch)->fp_control_status) + else if (regno == mips_regnum (gdbarch)->fp_control_status) is_fp = 1; - else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) + else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) is_fp = 1; else is_fp = 0; @@ -192,7 +278,7 @@ mips64_linux_regsets_store_registers (int regno) if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1) perror_with_name (_("Couldn't get registers")); - mips64_fill_gregset (®s, regno); + mips64_fill_gregset (regcache, ®s, regno); if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1) perror_with_name (_("Couldn't set registers")); @@ -206,7 +292,7 @@ mips64_linux_regsets_store_registers (int regno) (PTRACE_TYPE_ARG3) &fp_regs) == -1) perror_with_name (_("Couldn't get FP registers")); - mips64_fill_fpregset (&fp_regs, regno); + mips64_fill_fpregset (regcache, &fp_regs, regno); if (ptrace (PTRACE_SETFPREGS, tid, 0L, (PTRACE_TYPE_ARG3) &fp_regs) == -1) @@ -218,32 +304,57 @@ mips64_linux_regsets_store_registers (int regno) using any working method. */ static void -mips64_linux_fetch_registers (int regnum) +mips64_linux_fetch_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) { /* Unless we already know that PTRACE_GETREGS does not work, try it. */ if (have_ptrace_regsets) - mips64_linux_regsets_fetch_registers (regnum); + mips64_linux_regsets_fetch_registers (regcache, regnum); /* If we know, or just found out, that PTRACE_GETREGS does not work, fall back to PTRACE_PEEKUSER. */ if (!have_ptrace_regsets) - super_fetch_registers (regnum); + super_fetch_registers (ops, regcache, regnum); } /* Store REGNO (or all registers if REGNO == -1) to the target using any working method. */ static void -mips64_linux_store_registers (int regnum) +mips64_linux_store_registers (struct target_ops *ops, + struct regcache *regcache, int regnum) { /* Unless we already know that PTRACE_GETREGS does not work, try it. */ if (have_ptrace_regsets) - mips64_linux_regsets_store_registers (regnum); + mips64_linux_regsets_store_registers (regcache, regnum); /* If we know, or just found out, that PTRACE_GETREGS does not work, fall back to PTRACE_PEEKUSER. */ if (!have_ptrace_regsets) - super_store_registers (regnum); + super_store_registers (ops, regcache, regnum); +} + +/* Return the address in the core dump or inferior of register + REGNO. */ + +static CORE_ADDR +mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p) +{ + if (mips_abi_regsize (gdbarch) == 8) + return mips64_linux_register_addr (gdbarch, regno, store_p); + else + return mips_linux_register_addr (gdbarch, regno, store_p); +} + +static const struct target_desc * +mips_linux_read_description (struct target_ops *ops) +{ + /* Report that target registers are a size we know for sure + that we can get from ptrace. */ + if (_MIPS_SIM == _ABIO32) + return tdesc_mips_linux; + else + return tdesc_mips64_linux; } void _initialize_mips_linux_nat (void); @@ -251,7 +362,7 @@ void _initialize_mips_linux_nat (void); void _initialize_mips_linux_nat (void) { - struct target_ops *t = linux_target (); + struct target_ops *t = linux_trad_target (mips_linux_register_u_offset); super_fetch_registers = t->to_fetch_registers; super_store_registers = t->to_store_registers; @@ -259,5 +370,11 @@ _initialize_mips_linux_nat (void) t->to_fetch_registers = mips64_linux_fetch_registers; t->to_store_registers = mips64_linux_store_registers; + t->to_read_description = mips_linux_read_description; + linux_nat_add_target (t); + + /* Initialize the standard target descriptions. */ + initialize_tdesc_mips_linux (); + initialize_tdesc_mips64_linux (); }