X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdb%2Fmips-linux-tdep.c;h=3ffd53db9ead82b081a8ec64d3556315eb395053;hb=f030440daa989ae3dadc1fa4342cfa16d690db3c;hp=5924b30984db3d95f2219f18082da3c3b1de7c98;hpb=eb1956643ddbb298d1005c939d3b9fce04980a4a;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 5924b30984d..3ffd53db9ea 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1,7 +1,6 @@ /* Target-dependent code for GNU/Linux on MIPS processors. - Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2001-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -24,23 +23,66 @@ #include "solib-svr4.h" #include "osabi.h" #include "mips-tdep.h" -#include "gdb_string.h" -#include "gdb_assert.h" #include "frame.h" #include "regcache.h" #include "trad-frame.h" #include "tramp-frame.h" #include "gdbtypes.h" +#include "objfiles.h" #include "solib.h" -#include "solib-svr4.h" #include "solist.h" #include "symtab.h" #include "target-descriptions.h" +#include "regset.h" #include "mips-linux-tdep.h" #include "glibc-tdep.h" +#include "linux-tdep.h" +#include "xml-syscall.h" +#include "gdbsupport/gdb_signals.h" + +#include "features/mips-linux.c" +#include "features/mips-dsp-linux.c" +#include "features/mips64-linux.c" +#include "features/mips64-dsp-linux.c" static struct target_so_ops mips_svr4_so_ops; +/* This enum represents the signals' numbers on the MIPS + architecture. It just contains the signal definitions which are + different from the generic implementation. + + It is derived from the file , + from the Linux kernel tree. */ + +enum + { + MIPS_LINUX_SIGEMT = 7, + MIPS_LINUX_SIGBUS = 10, + MIPS_LINUX_SIGSYS = 12, + MIPS_LINUX_SIGUSR1 = 16, + MIPS_LINUX_SIGUSR2 = 17, + MIPS_LINUX_SIGCHLD = 18, + MIPS_LINUX_SIGCLD = MIPS_LINUX_SIGCHLD, + MIPS_LINUX_SIGPWR = 19, + MIPS_LINUX_SIGWINCH = 20, + MIPS_LINUX_SIGURG = 21, + MIPS_LINUX_SIGIO = 22, + MIPS_LINUX_SIGPOLL = MIPS_LINUX_SIGIO, + MIPS_LINUX_SIGSTOP = 23, + MIPS_LINUX_SIGTSTP = 24, + MIPS_LINUX_SIGCONT = 25, + MIPS_LINUX_SIGTTIN = 26, + MIPS_LINUX_SIGTTOU = 27, + MIPS_LINUX_SIGVTALRM = 28, + MIPS_LINUX_SIGPROF = 29, + MIPS_LINUX_SIGXCPU = 30, + MIPS_LINUX_SIGXFSZ = 31, + + MIPS_LINUX_SIGRTMIN = 32, + MIPS_LINUX_SIGRT64 = 64, + MIPS_LINUX_SIGRTMAX = 127, + }; + /* Figure out where the longjmp will land. We expect the first arg to be a pointer to the jmp_buf structure from which we extract the pc (MIPS_LINUX_JB_PC) that we will land @@ -56,12 +98,12 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) CORE_ADDR jb_addr; struct gdbarch *gdbarch = get_frame_arch (frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - char buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; + gdb_byte buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM); - if (target_read_memory (jb_addr - + MIPS_LINUX_JB_PC * MIPS_LINUX_JB_ELEMENT_SIZE, + if (target_read_memory ((jb_addr + + MIPS_LINUX_JB_PC * MIPS_LINUX_JB_ELEMENT_SIZE), buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT)) return 0; @@ -79,12 +121,7 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) static void supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - gdb_byte buf[MAX_REGISTER_SIZE]; - store_signed_integer (buf, register_size (gdbarch, regnum), byte_order, - extract_signed_integer (addr, 4, byte_order)); - regcache_raw_supply (regcache, regnum, buf); + regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, 4, true); } /* Unpack an elf_gregset_t into GDB's register cache. */ @@ -95,10 +132,7 @@ mips_supply_gregset (struct regcache *regcache, { int regi; const mips_elf_greg_t *regp = *gregsetp; - char zerobuf[MAX_REGISTER_SIZE]; - struct gdbarch *gdbarch = get_regcache_arch (regcache); - - memset (zerobuf, 0, MAX_REGISTER_SIZE); + struct gdbarch *gdbarch = regcache->arch (); for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++) supply_32bit_reg (regcache, regi - EF_REG0, regp + regi); @@ -117,13 +151,18 @@ mips_supply_gregset (struct regcache *regcache, supply_32bit_reg (regcache, mips_regnum (gdbarch)->cause, regp + EF_CP0_CAUSE); - /* Fill inaccessible registers with zero. */ - regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf); - regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf); - for (regi = MIPS_FIRST_EMBED_REGNUM; - regi <= MIPS_LAST_EMBED_REGNUM; - regi++) - regcache_raw_supply (regcache, regi, zerobuf); + /* Fill the inaccessible zero register with zero. */ + regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM); +} + +static void +mips_supply_gregset_wrapper (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + gdb_assert (len >= sizeof (mips_elf_gregset_t)); + + mips_supply_gregset (regcache, (const mips_elf_gregset_t *)gregs); } /* Pack our registers (or one register) into an elf_gregset_t. */ @@ -132,7 +171,7 @@ void mips_fill_gregset (const struct regcache *regcache, mips_elf_gregset_t *gregsetp, int regno) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); int regaddr, regi; mips_elf_greg_t *regp = *gregsetp; void *dst; @@ -155,7 +194,7 @@ mips_fill_gregset (const struct regcache *regcache, if (regno > 0 && regno < 32) { dst = regp + regno + EF_REG0; - regcache_raw_collect (regcache, regno, dst); + regcache->raw_collect (regno, dst); return; } @@ -180,68 +219,18 @@ mips_fill_gregset (const struct regcache *regcache, if (regaddr != -1) { dst = regp + regaddr; - regcache_raw_collect (regcache, regno, dst); + regcache->raw_collect (regno, dst); } } -/* Likewise, unpack an elf_fpregset_t. */ - -void -mips_supply_fpregset (struct regcache *regcache, - const mips_elf_fpregset_t *fpregsetp) +static void +mips_fill_gregset_wrapper (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - int regi; - char zerobuf[MAX_REGISTER_SIZE]; - - memset (zerobuf, 0, MAX_REGISTER_SIZE); - - for (regi = 0; regi < 32; regi++) - regcache_raw_supply (regcache, - gdbarch_fp0_regnum (gdbarch) + regi, - *fpregsetp + regi); + gdb_assert (len >= sizeof (mips_elf_gregset_t)); - regcache_raw_supply (regcache, - mips_regnum (gdbarch)->fp_control_status, - *fpregsetp + 32); - - /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */ - regcache_raw_supply (regcache, - mips_regnum (gdbarch)->fp_implementation_revision, - zerobuf); -} - -/* Likewise, pack one or all floating point registers into an - elf_fpregset_t. */ - -void -mips_fill_fpregset (const struct regcache *regcache, - mips_elf_fpregset_t *fpregsetp, int regno) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - char *from, *to; - - if ((regno >= gdbarch_fp0_regnum (gdbarch)) - && (regno < gdbarch_fp0_regnum (gdbarch) + 32)) - { - to = (char *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch)); - regcache_raw_collect (regcache, regno, to); - } - else if (regno == mips_regnum (gdbarch)->fp_control_status) - { - to = (char *) (*fpregsetp + 32); - regcache_raw_collect (regcache, regno, to); - } - else if (regno == -1) - { - int regi; - - for (regi = 0; regi < 32; regi++) - mips_fill_fpregset (regcache, fpregsetp, - gdbarch_fp0_regnum (gdbarch) + regi); - mips_fill_fpregset (regcache, fpregsetp, - mips_regnum (gdbarch)->fp_control_status); - } + mips_fill_gregset (regcache, (mips_elf_gregset_t *)gregs, regnum); } /* Support for 64-bit ABIs. */ @@ -262,7 +251,8 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) CORE_ADDR jb_addr; struct gdbarch *gdbarch = get_frame_arch (frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - void *buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + gdb_byte *buf + = (gdb_byte *) alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8; jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM); @@ -289,12 +279,12 @@ static void supply_64bit_reg (struct regcache *regcache, int regnum, const gdb_byte *buf) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG && register_size (gdbarch, regnum) == 4) - regcache_raw_supply (regcache, regnum, buf + 4); + regcache->raw_supply (regnum, buf + 4); else - regcache_raw_supply (regcache, regnum, buf); + regcache->raw_supply (regnum, buf); } /* Unpack a 64-bit elf_gregset_t into GDB's register cache. */ @@ -305,18 +295,15 @@ mips64_supply_gregset (struct regcache *regcache, { int regi; const mips64_elf_greg_t *regp = *gregsetp; - gdb_byte zerobuf[MAX_REGISTER_SIZE]; - struct gdbarch *gdbarch = get_regcache_arch (regcache); - - memset (zerobuf, 0, MAX_REGISTER_SIZE); + struct gdbarch *gdbarch = regcache->arch (); for (regi = MIPS64_EF_REG0 + 1; regi <= MIPS64_EF_REG31; regi++) supply_64bit_reg (regcache, regi - MIPS64_EF_REG0, - (const gdb_byte *)(regp + regi)); + (const gdb_byte *) (regp + regi)); if (mips_linux_restart_reg_p (gdbarch)) supply_64bit_reg (regcache, MIPS_RESTART_REGNUM, - (const gdb_byte *)(regp + MIPS64_EF_REG0)); + (const gdb_byte *) (regp + MIPS64_EF_REG0)); supply_64bit_reg (regcache, mips_regnum (gdbarch)->lo, (const gdb_byte *) (regp + MIPS64_EF_LO)); @@ -332,13 +319,18 @@ mips64_supply_gregset (struct regcache *regcache, supply_64bit_reg (regcache, mips_regnum (gdbarch)->cause, (const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE)); - /* Fill inaccessible registers with zero. */ - regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf); - regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf); - for (regi = MIPS_FIRST_EMBED_REGNUM; - regi <= MIPS_LAST_EMBED_REGNUM; - regi++) - regcache_raw_supply (regcache, regi, zerobuf); + /* Fill the inaccessible zero register with zero. */ + regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM); +} + +static void +mips64_supply_gregset_wrapper (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + gdb_assert (len >= sizeof (mips64_elf_gregset_t)); + + mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *)gregs); } /* Pack our registers (or one register) into a 64-bit elf_gregset_t. */ @@ -347,8 +339,7 @@ void mips64_fill_gregset (const struct regcache *regcache, mips64_elf_gregset_t *gregsetp, int regno) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct gdbarch *gdbarch = regcache->arch (); int regaddr, regi; mips64_elf_greg_t *regp = *gregsetp; void *dst; @@ -357,11 +348,12 @@ mips64_fill_gregset (const struct regcache *regcache, { memset (regp, 0, sizeof (mips64_elf_gregset_t)); for (regi = 1; regi < 32; regi++) - mips64_fill_gregset (regcache, gregsetp, regi); + mips64_fill_gregset (regcache, gregsetp, regi); mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo); mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi); mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc); - mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->badvaddr); + mips64_fill_gregset (regcache, gregsetp, + mips_regnum (gdbarch)->badvaddr); mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM); mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause); mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM); @@ -390,71 +382,88 @@ mips64_fill_gregset (const struct regcache *regcache, if (regaddr != -1) { - gdb_byte buf[MAX_REGISTER_SIZE]; - LONGEST val; - - regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (gdbarch, regno), - byte_order); dst = regp + regaddr; - store_signed_integer (dst, 8, byte_order, val); + regcache->raw_collect_integer (regno, (gdb_byte *) dst, 8, true); } } -/* Likewise, unpack an elf_fpregset_t. */ +static void +mips64_fill_gregset_wrapper (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) +{ + gdb_assert (len >= sizeof (mips64_elf_gregset_t)); + + mips64_fill_gregset (regcache, (mips64_elf_gregset_t *)gregs, regnum); +} + +/* Likewise, unpack an elf_fpregset_t. Linux only uses even-numbered + FPR slots in the Status.FR=0 mode, storing even-odd FPR pairs as the + SDC1 instruction would. When run on MIPS I architecture processors + all FPR slots used to be used, unusually, holding the respective FPRs + in the first 4 bytes, but that was corrected for consistency, with + `linux-mips.org' (LMO) commit 42533948caac ("Major pile of FP emulator + changes."), the fix corrected with LMO commit 849fa7a50dff ("R3k FPU + ptrace() handling fixes."), and then broken and fixed over and over + again, until last time fixed with commit 80cbfad79096 ("MIPS: Correct + MIPS I FP context layout"). */ void mips64_supply_fpregset (struct regcache *regcache, const mips64_elf_fpregset_t *fpregsetp) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); int regi; - /* See mips_linux_o32_sigframe_init for a description of the - peculiar FP register layout. */ if (register_size (gdbarch, gdbarch_fp0_regnum (gdbarch)) == 4) for (regi = 0; regi < 32; regi++) { - const gdb_byte *reg_ptr = (const gdb_byte *)(*fpregsetp + (regi & ~1)); + const gdb_byte *reg_ptr + = (const gdb_byte *) (*fpregsetp + (regi & ~1)); if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1)) reg_ptr += 4; - regcache_raw_supply (regcache, - gdbarch_fp0_regnum (gdbarch) + regi, - reg_ptr); + regcache->raw_supply (gdbarch_fp0_regnum (gdbarch) + regi, reg_ptr); } else for (regi = 0; regi < 32; regi++) - regcache_raw_supply (regcache, - gdbarch_fp0_regnum (gdbarch) + regi, - (const char *)(*fpregsetp + regi)); + regcache->raw_supply (gdbarch_fp0_regnum (gdbarch) + regi, + (const char *) (*fpregsetp + regi)); supply_32bit_reg (regcache, mips_regnum (gdbarch)->fp_control_status, - (const gdb_byte *)(*fpregsetp + 32)); + (const gdb_byte *) (*fpregsetp + 32)); /* The ABI doesn't tell us how to supply FCRIR, and core dumps don't include it - but the result of PTRACE_GETFPREGS does. The best we can do is to assume that its value is present. */ supply_32bit_reg (regcache, mips_regnum (gdbarch)->fp_implementation_revision, - (const gdb_byte *)(*fpregsetp + 32) + 4); + (const gdb_byte *) (*fpregsetp + 32) + 4); +} + +static void +mips64_supply_fpregset_wrapper (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + gdb_assert (len >= sizeof (mips64_elf_fpregset_t)); + + mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *)gregs); } /* Likewise, pack one or all floating point registers into an - elf_fpregset_t. */ + elf_fpregset_t. See `mips_supply_fpregset' for an explanation + of the layout. */ void mips64_fill_fpregset (const struct regcache *regcache, mips64_elf_fpregset_t *fpregsetp, int regno) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct gdbarch *gdbarch = regcache->arch (); gdb_byte *to; if ((regno >= gdbarch_fp0_regnum (gdbarch)) && (regno < gdbarch_fp0_regnum (gdbarch) + 32)) { - /* See mips_linux_o32_sigframe_init for a description of the - peculiar FP register layout. */ if (register_size (gdbarch, regno) == 4) { int regi = regno - gdbarch_fp0_regnum (gdbarch); @@ -462,35 +471,24 @@ mips64_fill_fpregset (const struct regcache *regcache, to = (gdb_byte *) (*fpregsetp + (regi & ~1)); if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1)) to += 4; - regcache_raw_collect (regcache, regno, to); + regcache->raw_collect (regno, to); } else { - to = (gdb_byte *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch)); - regcache_raw_collect (regcache, regno, to); + to = (gdb_byte *) (*fpregsetp + regno + - gdbarch_fp0_regnum (gdbarch)); + regcache->raw_collect (regno, to); } } else if (regno == mips_regnum (gdbarch)->fp_control_status) { - gdb_byte buf[MAX_REGISTER_SIZE]; - LONGEST val; - - regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (gdbarch, regno), - byte_order); to = (gdb_byte *) (*fpregsetp + 32); - store_signed_integer (to, 4, byte_order, val); + regcache->raw_collect_integer (regno, to, 4, true); } else if (regno == mips_regnum (gdbarch)->fp_implementation_revision) { - gdb_byte buf[MAX_REGISTER_SIZE]; - LONGEST val; - - regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (gdbarch, regno), - byte_order); to = (gdb_byte *) (*fpregsetp + 32) + 4; - store_signed_integer (to, 4, byte_order, val); + regcache->raw_collect_integer (regno, to, 4, true); } else if (regno == -1) { @@ -502,78 +500,59 @@ mips64_fill_fpregset (const struct regcache *regcache, mips64_fill_fpregset (regcache, fpregsetp, mips_regnum (gdbarch)->fp_control_status); mips64_fill_fpregset (regcache, fpregsetp, - (mips_regnum (gdbarch) - ->fp_implementation_revision)); + mips_regnum (gdbarch)->fp_implementation_revision); } } +static void +mips64_fill_fpregset_wrapper (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) +{ + gdb_assert (len >= sizeof (mips64_elf_fpregset_t)); + + mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *)gregs, regnum); +} + +static const struct regset mips_linux_gregset = + { + NULL, mips_supply_gregset_wrapper, mips_fill_gregset_wrapper + }; -/* Use a local version of this function to get the correct types for - regsets, until multi-arch core support is ready. */ +static const struct regset mips64_linux_gregset = + { + NULL, mips64_supply_gregset_wrapper, mips64_fill_gregset_wrapper + }; + +static const struct regset mips64_linux_fpregset = + { + NULL, mips64_supply_fpregset_wrapper, mips64_fill_fpregset_wrapper + }; static void -fetch_core_registers (struct regcache *regcache, - char *core_reg_sect, unsigned core_reg_size, - int which, CORE_ADDR reg_addr) +mips_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) { - mips_elf_gregset_t gregset; - mips_elf_fpregset_t fpregset; - mips64_elf_gregset_t gregset64; - mips64_elf_fpregset_t fpregset64; - - if (which == 0) + if (register_size (gdbarch, MIPS_ZERO_REGNUM) == 4) { - if (core_reg_size == sizeof (gregset)) - { - memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset)); - mips_supply_gregset (regcache, - (const mips_elf_gregset_t *) &gregset); - } - else if (core_reg_size == sizeof (gregset64)) - { - memcpy ((char *) &gregset64, core_reg_sect, sizeof (gregset64)); - mips64_supply_gregset (regcache, - (const mips64_elf_gregset_t *) &gregset64); - } - else - { - warning (_("wrong size gregset struct in core file")); - } + cb (".reg", sizeof (mips_elf_gregset_t), sizeof (mips_elf_gregset_t), + &mips_linux_gregset, NULL, cb_data); + cb (".reg2", sizeof (mips64_elf_fpregset_t), + sizeof (mips64_elf_fpregset_t), &mips64_linux_fpregset, + NULL, cb_data); } - else if (which == 2) + else { - if (core_reg_size == sizeof (fpregset)) - { - memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset)); - mips_supply_fpregset (regcache, - (const mips_elf_fpregset_t *) &fpregset); - } - else if (core_reg_size == sizeof (fpregset64)) - { - memcpy ((char *) &fpregset64, core_reg_sect, - sizeof (fpregset64)); - mips64_supply_fpregset (regcache, - (const mips64_elf_fpregset_t *) &fpregset64); - } - else - { - warning (_("wrong size fpregset struct in core file")); - } + cb (".reg", sizeof (mips64_elf_gregset_t), sizeof (mips64_elf_gregset_t), + &mips64_linux_gregset, NULL, cb_data); + cb (".reg2", sizeof (mips64_elf_fpregset_t), + sizeof (mips64_elf_fpregset_t), &mips64_linux_fpregset, + NULL, cb_data); } } -/* Register that we are able to handle ELF file formats using standard - procfs "regset" structures. */ - -static struct core_fns regset_core_fns = -{ - bfd_target_elf_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_core_registers, /* core_read_registers */ - NULL /* next */ -}; - static const struct target_desc * mips_linux_core_read_description (struct gdbarch *gdbarch, struct target_ops *target, @@ -583,7 +562,7 @@ mips_linux_core_read_description (struct gdbarch *gdbarch, if (! section) return NULL; - switch (bfd_section_size (abfd, section)) + switch (bfd_section_size (section)) { case sizeof (mips_elf_gregset_t): return mips_tdesc_gp32; @@ -598,24 +577,33 @@ mips_linux_core_read_description (struct gdbarch *gdbarch, /* Check the code at PC for a dynamic linker lazy resolution stub. - Because they aren't in the .plt section, we pattern-match on the - code generated by GNU ld. They look like this: + GNU ld for MIPS has put lazy resolution stubs into a ".MIPS.stubs" + section uniformly since version 2.15. If the pc is in that section, + then we are in such a stub. Before that ".stub" was used in 32-bit + ELF binaries, however we do not bother checking for that since we + have never had and that case should be extremely rare these days. + Instead we pattern-match on the code generated by GNU ld. They look + like this: lw t9,0x8010(gp) addu t7,ra jalr t9,ra addiu t8,zero,INDEX - (with the appropriate doubleword instructions for N64). Also - return the dynamic symbol index used in the last instruction. */ + (with the appropriate doubleword instructions for N64). As any lazy + resolution stubs in microMIPS binaries will always be in a + ".MIPS.stubs" section we only ever verify standard MIPS patterns. */ static int -mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) +mips_linux_in_dynsym_stub (CORE_ADDR pc) { - unsigned char buf[28], *p; + gdb_byte buf[28], *p; ULONGEST insn, insn1; - int n64 = (mips_abi (target_gdbarch) == MIPS_ABI_N64); - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); + int n64 = (mips_abi (target_gdbarch ()) == MIPS_ABI_N64); + enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); + + if (in_mips_stubs_section (pc)) + return 1; read_memory (pc - 12, buf, 28); @@ -644,14 +632,14 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) insn = extract_unsigned_integer (p + 4, 4, byte_order); if (n64) { - /* daddu t7,ra */ - if (insn != 0x03e0782d) + /* 'daddu t7,ra' or 'or t7, ra, zero'*/ + if (insn != 0x03e0782d && insn != 0x03e07825) return 0; } else { - /* addu t7,ra */ - if (insn != 0x03e07821) + /* 'addu t7,ra' or 'or t7, ra, zero'*/ + if (insn != 0x03e07821 && insn != 0x03e07825) return 0; } @@ -674,7 +662,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) return 0; } - return (insn & 0xffff); + return 1; } /* Return non-zero iff PC belongs to the dynamic linker resolution @@ -688,9 +676,10 @@ mips_linux_in_dynsym_resolve_code (CORE_ADDR pc) if (svr4_in_dynsym_resolve_code (pc)) return 1; - /* Pattern match for the stub. It would be nice if there were a - more efficient way to avoid this check. */ - if (mips_linux_in_dynsym_stub (pc, NULL)) + /* Likewise for the stubs. They live in the .MIPS.stubs section these + days, so we check if the PC is within, than fall back to a pattern + match. */ + if (mips_linux_in_dynsym_stub (pc)) return 1; return 0; @@ -708,11 +697,11 @@ mips_linux_in_dynsym_resolve_code (CORE_ADDR pc) static CORE_ADDR mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) { - struct minimal_symbol *resolver; + struct bound_minimal_symbol resolver; resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL); - if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc) + if (resolver.minsym && BMSYMBOL_VALUE_ADDRESS (resolver) == pc) return frame_unwind_caller_pc (get_current_frame ()); return glibc_skip_solib_resolver (gdbarch, pc); @@ -733,6 +722,14 @@ static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, struct trad_frame_cache *this_cache, CORE_ADDR func); +static int mips_linux_sigframe_validate (const struct tramp_frame *self, + struct frame_info *this_frame, + CORE_ADDR *pc); + +static int micromips_linux_sigframe_validate (const struct tramp_frame *self, + struct frame_info *this_frame, + CORE_ADDR *pc); + #define MIPS_NR_LINUX 4000 #define MIPS_NR_N64_LINUX 5000 #define MIPS_NR_N32_LINUX 6000 @@ -748,47 +745,111 @@ static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, #define MIPS_INST_LI_V0_N32_RT_SIGRETURN 0x24020000 + MIPS_NR_N32_rt_sigreturn #define MIPS_INST_SYSCALL 0x0000000c +#define MICROMIPS_INST_LI_V0 0x3040 +#define MICROMIPS_INST_POOL32A 0x0000 +#define MICROMIPS_INST_SYSCALL 0x8b7c + static const struct tramp_frame mips_linux_o32_sigframe = { SIGTRAMP_FRAME, 4, { - { MIPS_INST_LI_V0_SIGRETURN, -1 }, - { MIPS_INST_SYSCALL, -1 }, - { TRAMP_SENTINEL_INSN, -1 } + { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, + { MIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, - mips_linux_o32_sigframe_init + mips_linux_o32_sigframe_init, + mips_linux_sigframe_validate }; static const struct tramp_frame mips_linux_o32_rt_sigframe = { SIGTRAMP_FRAME, 4, { - { MIPS_INST_LI_V0_RT_SIGRETURN, -1 }, - { MIPS_INST_SYSCALL, -1 }, - { TRAMP_SENTINEL_INSN, -1 } }, - mips_linux_o32_sigframe_init + { MIPS_INST_LI_V0_RT_SIGRETURN, ULONGEST_MAX }, + { MIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, + mips_linux_o32_sigframe_init, + mips_linux_sigframe_validate }; static const struct tramp_frame mips_linux_n32_rt_sigframe = { SIGTRAMP_FRAME, 4, { - { MIPS_INST_LI_V0_N32_RT_SIGRETURN, -1 }, - { MIPS_INST_SYSCALL, -1 }, - { TRAMP_SENTINEL_INSN, -1 } + { MIPS_INST_LI_V0_N32_RT_SIGRETURN, ULONGEST_MAX }, + { MIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, - mips_linux_n32n64_sigframe_init + mips_linux_n32n64_sigframe_init, + mips_linux_sigframe_validate }; static const struct tramp_frame mips_linux_n64_rt_sigframe = { SIGTRAMP_FRAME, 4, { - { MIPS_INST_LI_V0_N64_RT_SIGRETURN, -1 }, - { MIPS_INST_SYSCALL, -1 }, - { TRAMP_SENTINEL_INSN, -1 } + { MIPS_INST_LI_V0_N64_RT_SIGRETURN, ULONGEST_MAX }, + { MIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } }, - mips_linux_n32n64_sigframe_init + mips_linux_n32n64_sigframe_init, + mips_linux_sigframe_validate +}; + +static const struct tramp_frame micromips_linux_o32_sigframe = { + SIGTRAMP_FRAME, + 2, + { + { MICROMIPS_INST_LI_V0, ULONGEST_MAX }, + { MIPS_NR_sigreturn, ULONGEST_MAX }, + { MICROMIPS_INST_POOL32A, ULONGEST_MAX }, + { MICROMIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } + }, + mips_linux_o32_sigframe_init, + micromips_linux_sigframe_validate +}; + +static const struct tramp_frame micromips_linux_o32_rt_sigframe = { + SIGTRAMP_FRAME, + 2, + { + { MICROMIPS_INST_LI_V0, ULONGEST_MAX }, + { MIPS_NR_rt_sigreturn, ULONGEST_MAX }, + { MICROMIPS_INST_POOL32A, ULONGEST_MAX }, + { MICROMIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } + }, + mips_linux_o32_sigframe_init, + micromips_linux_sigframe_validate +}; + +static const struct tramp_frame micromips_linux_n32_rt_sigframe = { + SIGTRAMP_FRAME, + 2, + { + { MICROMIPS_INST_LI_V0, ULONGEST_MAX }, + { MIPS_NR_N32_rt_sigreturn, ULONGEST_MAX }, + { MICROMIPS_INST_POOL32A, ULONGEST_MAX }, + { MICROMIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } + }, + mips_linux_n32n64_sigframe_init, + micromips_linux_sigframe_validate +}; + +static const struct tramp_frame micromips_linux_n64_rt_sigframe = { + SIGTRAMP_FRAME, + 2, + { + { MICROMIPS_INST_LI_V0, ULONGEST_MAX }, + { MIPS_NR_N64_rt_sigreturn, ULONGEST_MAX }, + { MICROMIPS_INST_POOL32A, ULONGEST_MAX }, + { MICROMIPS_INST_SYSCALL, ULONGEST_MAX }, + { TRAMP_SENTINEL_INSN, ULONGEST_MAX } + }, + mips_linux_n32n64_sigframe_init, + micromips_linux_sigframe_validate }; /* *INDENT-OFF* */ @@ -802,6 +863,8 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { sigset_t sf_mask; }; + Pre-2.6.12 sigcontext: + struct sigcontext { unsigned int sc_regmask; [Unused] unsigned int sc_status; @@ -823,6 +886,30 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { unsigned long sc_sigset[4]; [kernel's sigset_t] }; + Post-2.6.12 sigcontext (SmartMIPS/DSP support added): + + struct sigcontext { + unsigned int sc_regmask; [Unused] + unsigned int sc_status; [Unused] + unsigned long long sc_pc; + unsigned long long sc_regs[32]; + unsigned long long sc_fpregs[32]; + unsigned int sc_acx; + unsigned int sc_fpc_csr; + unsigned int sc_fpc_eir; [Unused] + unsigned int sc_used_math; + unsigned int sc_dsp; + [Alignment hole of four bytes] + unsigned long long sc_mdhi; + unsigned long long sc_mdlo; + unsigned long sc_hi1; + unsigned long sc_lo1; + unsigned long sc_hi2; + unsigned long sc_lo2; + unsigned long sc_hi3; + unsigned long sc_lo3; + }; + The RT signal frames look like this: struct rt_sigframe { @@ -855,10 +942,17 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { #define SIGCONTEXT_REGS (2 * 8) #define SIGCONTEXT_FPREGS (34 * 8) #define SIGCONTEXT_FPCSR (66 * 8 + 4) +#define SIGCONTEXT_DSPCTL (68 * 8 + 0) #define SIGCONTEXT_HI (69 * 8) #define SIGCONTEXT_LO (70 * 8) #define SIGCONTEXT_CAUSE (71 * 8 + 0) #define SIGCONTEXT_BADVADDR (71 * 8 + 4) +#define SIGCONTEXT_HI1 (71 * 8 + 0) +#define SIGCONTEXT_LO1 (71 * 8 + 4) +#define SIGCONTEXT_HI2 (72 * 8 + 0) +#define SIGCONTEXT_LO2 (72 * 8 + 4) +#define SIGCONTEXT_HI3 (73 * 8 + 0) +#define SIGCONTEXT_LO3 (73 * 8 + 4) #define SIGCONTEXT_REG_SIZE 8 @@ -869,13 +963,14 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, CORE_ADDR func) { struct gdbarch *gdbarch = get_frame_arch (this_frame); - int ireg, reg_position; + int ireg; CORE_ADDR frame_sp = get_frame_sp (this_frame); CORE_ADDR sigcontext_base; const struct mips_regnum *regs = mips_regnum (gdbarch); CORE_ADDR regs_base; - if (self == &mips_linux_o32_sigframe) + if (self == &mips_linux_o32_sigframe + || self == µmips_linux_o32_sigframe) sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET; else sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET; @@ -898,53 +993,74 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, for (ireg = 1; ireg < 32; ireg++) trad_frame_set_reg_addr (this_cache, - ireg + MIPS_ZERO_REGNUM - + gdbarch_num_regs (gdbarch), - regs_base + SIGCONTEXT_REGS - + ireg * SIGCONTEXT_REG_SIZE); - - /* The way that floating point registers are saved, unfortunately, - depends on the architecture the kernel is built for. For the r3000 and - tx39, four bytes of each register are at the beginning of each of the - 32 eight byte slots. For everything else, the registers are saved - using double precision; only the even-numbered slots are initialized, - and the high bits are the odd-numbered register. Assume the latter - layout, since we can't tell, and it's much more common. Which bits are - the "high" bits depends on endianness. */ + (ireg + MIPS_ZERO_REGNUM + + gdbarch_num_regs (gdbarch)), + (regs_base + SIGCONTEXT_REGS + + ireg * SIGCONTEXT_REG_SIZE)); + for (ireg = 0; ireg < 32; ireg++) if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1)) trad_frame_set_reg_addr (this_cache, - ireg + regs->fp0 + - gdbarch_num_regs (gdbarch), - sigcontext_base + SIGCONTEXT_FPREGS + 4 - + (ireg & ~1) * SIGCONTEXT_REG_SIZE); + ireg + regs->fp0 + gdbarch_num_regs (gdbarch), + (sigcontext_base + SIGCONTEXT_FPREGS + 4 + + (ireg & ~1) * SIGCONTEXT_REG_SIZE)); else trad_frame_set_reg_addr (this_cache, - ireg + regs->fp0 - + gdbarch_num_regs (gdbarch), - sigcontext_base + SIGCONTEXT_FPREGS - + (ireg & ~1) * SIGCONTEXT_REG_SIZE); + ireg + regs->fp0 + gdbarch_num_regs (gdbarch), + (sigcontext_base + SIGCONTEXT_FPREGS + + (ireg & ~1) * SIGCONTEXT_REG_SIZE)); trad_frame_set_reg_addr (this_cache, regs->pc + gdbarch_num_regs (gdbarch), regs_base + SIGCONTEXT_PC); trad_frame_set_reg_addr (this_cache, - regs->fp_control_status - + gdbarch_num_regs (gdbarch), + (regs->fp_control_status + + gdbarch_num_regs (gdbarch)), sigcontext_base + SIGCONTEXT_FPCSR); + + if (regs->dspctl != -1) + trad_frame_set_reg_addr (this_cache, + regs->dspctl + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_DSPCTL); + trad_frame_set_reg_addr (this_cache, regs->hi + gdbarch_num_regs (gdbarch), regs_base + SIGCONTEXT_HI); trad_frame_set_reg_addr (this_cache, regs->lo + gdbarch_num_regs (gdbarch), regs_base + SIGCONTEXT_LO); - trad_frame_set_reg_addr (this_cache, - regs->cause + gdbarch_num_regs (gdbarch), - sigcontext_base + SIGCONTEXT_CAUSE); - trad_frame_set_reg_addr (this_cache, - regs->badvaddr + gdbarch_num_regs (gdbarch), - sigcontext_base + SIGCONTEXT_BADVADDR); + + if (regs->dspacc != -1) + { + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 0 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_HI1); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 1 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_LO1); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 2 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_HI2); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 3 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_LO2); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 4 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_HI3); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 5 + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_LO3); + } + else + { + trad_frame_set_reg_addr (this_cache, + regs->cause + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_CAUSE); + trad_frame_set_reg_addr (this_cache, + regs->badvaddr + gdbarch_num_regs (gdbarch), + sigcontext_base + SIGCONTEXT_BADVADDR); + } /* Choice of the bottom of the sigframe is somewhat arbitrary. */ trad_frame_set_id (this_cache, frame_id_build (frame_sp, func)); @@ -1022,9 +1138,16 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, #define N64_SIGCONTEXT_REGS (0 * 8) #define N64_SIGCONTEXT_FPREGS (32 * 8) #define N64_SIGCONTEXT_HI (64 * 8) +#define N64_SIGCONTEXT_HI1 (65 * 8) +#define N64_SIGCONTEXT_HI2 (66 * 8) +#define N64_SIGCONTEXT_HI3 (67 * 8) #define N64_SIGCONTEXT_LO (68 * 8) +#define N64_SIGCONTEXT_LO1 (69 * 8) +#define N64_SIGCONTEXT_LO2 (70 * 8) +#define N64_SIGCONTEXT_LO3 (71 * 8) #define N64_SIGCONTEXT_PC (72 * 8) -#define N64_SIGCONTEXT_FPCSR (73 * 8) +#define N64_SIGCONTEXT_FPCSR (73 * 8 + 0) +#define N64_SIGCONTEXT_DSPCTL (74 * 8 + 0) #define N64_SIGCONTEXT_REG_SIZE 8 @@ -1035,12 +1158,13 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, CORE_ADDR func) { struct gdbarch *gdbarch = get_frame_arch (this_frame); - int ireg, reg_position; + int ireg; CORE_ADDR frame_sp = get_frame_sp (this_frame); CORE_ADDR sigcontext_base; const struct mips_regnum *regs = mips_regnum (gdbarch); - if (self == &mips_linux_n32_rt_sigframe) + if (self == &mips_linux_n32_rt_sigframe + || self == µmips_linux_n32_rt_sigframe) sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET; else sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET; @@ -1053,26 +1177,26 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, for (ireg = 1; ireg < 32; ireg++) trad_frame_set_reg_addr (this_cache, - ireg + MIPS_ZERO_REGNUM - + gdbarch_num_regs (gdbarch), - sigcontext_base + N64_SIGCONTEXT_REGS - + ireg * N64_SIGCONTEXT_REG_SIZE); + (ireg + MIPS_ZERO_REGNUM + + gdbarch_num_regs (gdbarch)), + (sigcontext_base + N64_SIGCONTEXT_REGS + + ireg * N64_SIGCONTEXT_REG_SIZE)); for (ireg = 0; ireg < 32; ireg++) trad_frame_set_reg_addr (this_cache, - ireg + regs->fp0 - + gdbarch_num_regs (gdbarch), - sigcontext_base + N64_SIGCONTEXT_FPREGS - + ireg * N64_SIGCONTEXT_REG_SIZE); + ireg + regs->fp0 + gdbarch_num_regs (gdbarch), + (sigcontext_base + N64_SIGCONTEXT_FPREGS + + ireg * N64_SIGCONTEXT_REG_SIZE)); trad_frame_set_reg_addr (this_cache, regs->pc + gdbarch_num_regs (gdbarch), sigcontext_base + N64_SIGCONTEXT_PC); trad_frame_set_reg_addr (this_cache, - regs->fp_control_status - + gdbarch_num_regs (gdbarch), + (regs->fp_control_status + + gdbarch_num_regs (gdbarch)), sigcontext_base + N64_SIGCONTEXT_FPCSR); + trad_frame_set_reg_addr (this_cache, regs->hi + gdbarch_num_regs (gdbarch), sigcontext_base + N64_SIGCONTEXT_HI); @@ -1080,15 +1204,70 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, regs->lo + gdbarch_num_regs (gdbarch), sigcontext_base + N64_SIGCONTEXT_LO); + if (regs->dspacc != -1) + { + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 0 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_HI1); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 1 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_LO1); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 2 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_HI2); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 3 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_LO2); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 4 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_HI3); + trad_frame_set_reg_addr (this_cache, + regs->dspacc + 5 + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_LO3); + } + if (regs->dspctl != -1) + trad_frame_set_reg_addr (this_cache, + regs->dspctl + gdbarch_num_regs (gdbarch), + sigcontext_base + N64_SIGCONTEXT_DSPCTL); + /* Choice of the bottom of the sigframe is somewhat arbitrary. */ trad_frame_set_id (this_cache, frame_id_build (frame_sp, func)); } +/* Implement struct tramp_frame's "validate" method for standard MIPS code. */ + +static int +mips_linux_sigframe_validate (const struct tramp_frame *self, + struct frame_info *this_frame, + CORE_ADDR *pc) +{ + return mips_pc_is_mips (*pc); +} + +/* Implement struct tramp_frame's "validate" method for microMIPS code. */ + +static int +micromips_linux_sigframe_validate (const struct tramp_frame *self, + struct frame_info *this_frame, + CORE_ADDR *pc) +{ + if (mips_pc_is_micromips (get_frame_arch (this_frame), *pc)) + { + *pc = mips_unmake_compact_addr (*pc); + return 1; + } + else + return 0; +} + +/* Implement the "write_pc" gdbarch method. */ + static void mips_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch), pc); + struct gdbarch *gdbarch = regcache->arch (); + + mips_write_pc (regcache, pc); /* Clear the syscall restart flag. */ if (mips_linux_restart_reg_p (gdbarch)) @@ -1130,6 +1309,218 @@ mips_linux_syscall_next_pc (struct frame_info *frame) return pc + 4; } +/* Return the current system call's number present in the + v0 register. When the function fails, it returns -1. */ + +static LONGEST +mips_linux_get_syscall_number (struct gdbarch *gdbarch, + thread_info *thread) +{ + struct regcache *regcache = get_thread_regcache (thread); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int regsize = register_size (gdbarch, MIPS_V0_REGNUM); + /* The content of a register */ + gdb_byte buf[8]; + /* The result */ + LONGEST ret; + + /* Make sure we're in a known ABI */ + gdb_assert (tdep->mips_abi == MIPS_ABI_O32 + || tdep->mips_abi == MIPS_ABI_N32 + || tdep->mips_abi == MIPS_ABI_N64); + + gdb_assert (regsize <= sizeof (buf)); + + /* Getting the system call number from the register. + syscall number is in v0 or $2. */ + regcache->cooked_read (MIPS_V0_REGNUM, buf); + + ret = extract_signed_integer (buf, regsize, byte_order); + + return ret; +} + +/* Implementation of `gdbarch_gdb_signal_to_target', as defined in + gdbarch.h. */ + +static int +mips_gdb_signal_to_target (struct gdbarch *gdbarch, + enum gdb_signal signal) +{ + switch (signal) + { + case GDB_SIGNAL_EMT: + return MIPS_LINUX_SIGEMT; + + case GDB_SIGNAL_BUS: + return MIPS_LINUX_SIGBUS; + + case GDB_SIGNAL_SYS: + return MIPS_LINUX_SIGSYS; + + case GDB_SIGNAL_USR1: + return MIPS_LINUX_SIGUSR1; + + case GDB_SIGNAL_USR2: + return MIPS_LINUX_SIGUSR2; + + case GDB_SIGNAL_CHLD: + return MIPS_LINUX_SIGCHLD; + + case GDB_SIGNAL_PWR: + return MIPS_LINUX_SIGPWR; + + case GDB_SIGNAL_WINCH: + return MIPS_LINUX_SIGWINCH; + + case GDB_SIGNAL_URG: + return MIPS_LINUX_SIGURG; + + case GDB_SIGNAL_IO: + return MIPS_LINUX_SIGIO; + + case GDB_SIGNAL_POLL: + return MIPS_LINUX_SIGPOLL; + + case GDB_SIGNAL_STOP: + return MIPS_LINUX_SIGSTOP; + + case GDB_SIGNAL_TSTP: + return MIPS_LINUX_SIGTSTP; + + case GDB_SIGNAL_CONT: + return MIPS_LINUX_SIGCONT; + + case GDB_SIGNAL_TTIN: + return MIPS_LINUX_SIGTTIN; + + case GDB_SIGNAL_TTOU: + return MIPS_LINUX_SIGTTOU; + + case GDB_SIGNAL_VTALRM: + return MIPS_LINUX_SIGVTALRM; + + case GDB_SIGNAL_PROF: + return MIPS_LINUX_SIGPROF; + + case GDB_SIGNAL_XCPU: + return MIPS_LINUX_SIGXCPU; + + case GDB_SIGNAL_XFSZ: + return MIPS_LINUX_SIGXFSZ; + + /* GDB_SIGNAL_REALTIME_32 is not continuous in , + therefore we have to handle it here. */ + case GDB_SIGNAL_REALTIME_32: + return MIPS_LINUX_SIGRTMIN; + } + + if (signal >= GDB_SIGNAL_REALTIME_33 + && signal <= GDB_SIGNAL_REALTIME_63) + { + int offset = signal - GDB_SIGNAL_REALTIME_33; + + return MIPS_LINUX_SIGRTMIN + 1 + offset; + } + else if (signal >= GDB_SIGNAL_REALTIME_64 + && signal <= GDB_SIGNAL_REALTIME_127) + { + int offset = signal - GDB_SIGNAL_REALTIME_64; + + return MIPS_LINUX_SIGRT64 + offset; + } + + return linux_gdb_signal_to_target (gdbarch, signal); +} + +/* Translate signals based on MIPS signal values. + Adapted from gdb/gdbsupport/signals.c. */ + +static enum gdb_signal +mips_gdb_signal_from_target (struct gdbarch *gdbarch, int signal) +{ + switch (signal) + { + case MIPS_LINUX_SIGEMT: + return GDB_SIGNAL_EMT; + + case MIPS_LINUX_SIGBUS: + return GDB_SIGNAL_BUS; + + case MIPS_LINUX_SIGSYS: + return GDB_SIGNAL_SYS; + + case MIPS_LINUX_SIGUSR1: + return GDB_SIGNAL_USR1; + + case MIPS_LINUX_SIGUSR2: + return GDB_SIGNAL_USR2; + + case MIPS_LINUX_SIGCHLD: + return GDB_SIGNAL_CHLD; + + case MIPS_LINUX_SIGPWR: + return GDB_SIGNAL_PWR; + + case MIPS_LINUX_SIGWINCH: + return GDB_SIGNAL_WINCH; + + case MIPS_LINUX_SIGURG: + return GDB_SIGNAL_URG; + + /* No way to differentiate between SIGIO and SIGPOLL. + Therefore, we just handle the first one. */ + case MIPS_LINUX_SIGIO: + return GDB_SIGNAL_IO; + + case MIPS_LINUX_SIGSTOP: + return GDB_SIGNAL_STOP; + + case MIPS_LINUX_SIGTSTP: + return GDB_SIGNAL_TSTP; + + case MIPS_LINUX_SIGCONT: + return GDB_SIGNAL_CONT; + + case MIPS_LINUX_SIGTTIN: + return GDB_SIGNAL_TTIN; + + case MIPS_LINUX_SIGTTOU: + return GDB_SIGNAL_TTOU; + + case MIPS_LINUX_SIGVTALRM: + return GDB_SIGNAL_VTALRM; + + case MIPS_LINUX_SIGPROF: + return GDB_SIGNAL_PROF; + + case MIPS_LINUX_SIGXCPU: + return GDB_SIGNAL_XCPU; + + case MIPS_LINUX_SIGXFSZ: + return GDB_SIGNAL_XFSZ; + } + + if (signal >= MIPS_LINUX_SIGRTMIN && signal <= MIPS_LINUX_SIGRTMAX) + { + /* GDB_SIGNAL_REALTIME values are not contiguous, map parts of + the MIPS block to the respective GDB_SIGNAL_REALTIME blocks. */ + int offset = signal - MIPS_LINUX_SIGRTMIN; + + if (offset == 0) + return GDB_SIGNAL_REALTIME_32; + else if (offset < 32) + return (enum gdb_signal) (offset - 1 + + (int) GDB_SIGNAL_REALTIME_33); + else + return (enum gdb_signal) (offset - 32 + + (int) GDB_SIGNAL_REALTIME_64); + } + + return linux_gdb_signal_from_target (gdbarch, signal); +} + /* Initialize one of the GNU/Linux OS ABIs. */ static void @@ -1138,21 +1529,30 @@ mips_linux_init_abi (struct gdbarch_info info, { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum mips_abi abi = mips_abi (gdbarch); - struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; + struct tdesc_arch_data *tdesc_data = info.tdesc_data; + + linux_init_abi (info, gdbarch); + + /* Get the syscall number from the arch's register. */ + set_gdbarch_get_syscall_number (gdbarch, mips_linux_get_syscall_number); switch (abi) { case MIPS_ABI_O32: set_gdbarch_get_longjmp_target (gdbarch, - mips_linux_get_longjmp_target); + mips_linux_get_longjmp_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); + tramp_frame_prepend_unwinder (gdbarch, µmips_linux_o32_sigframe); + tramp_frame_prepend_unwinder (gdbarch, + µmips_linux_o32_rt_sigframe); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe); + set_xml_syscall_file_name (gdbarch, "syscalls/mips-o32-linux.xml"); break; case MIPS_ABI_N32: set_gdbarch_get_longjmp_target (gdbarch, - mips_linux_get_longjmp_target); + mips_linux_get_longjmp_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); set_gdbarch_long_double_bit (gdbarch, 128); @@ -1161,11 +1561,14 @@ mips_linux_init_abi (struct gdbarch_info info, except that the quiet/signalling NaN bit is reversed (GDB does not distinguish between quiet and signalling NaNs). */ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); + tramp_frame_prepend_unwinder (gdbarch, + µmips_linux_n32_rt_sigframe); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe); + set_xml_syscall_file_name (gdbarch, "syscalls/mips-n32-linux.xml"); break; case MIPS_ABI_N64: set_gdbarch_get_longjmp_target (gdbarch, - mips64_linux_get_longjmp_target); + mips64_linux_get_longjmp_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); set_gdbarch_long_double_bit (gdbarch, 128); @@ -1174,7 +1577,10 @@ mips_linux_init_abi (struct gdbarch_info info, except that the quiet/signalling NaN bit is reversed (GDB does not distinguish between quiet and signalling NaNs). */ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); + tramp_frame_prepend_unwinder (gdbarch, + µmips_linux_n64_rt_sigframe); tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe); + set_xml_syscall_file_name (gdbarch, "syscalls/mips-n64-linux.xml"); break; default: break; @@ -1186,7 +1592,7 @@ mips_linux_init_abi (struct gdbarch_info info, /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, - svr4_fetch_objfile_link_map); + svr4_fetch_objfile_link_map); /* Initialize this lazily, to avoid an initialization order dependency on solib-svr4.c's _initialize routine. */ @@ -1203,6 +1609,15 @@ mips_linux_init_abi (struct gdbarch_info info, set_gdbarch_core_read_description (gdbarch, mips_linux_core_read_description); + set_gdbarch_iterate_over_regset_sections + (gdbarch, mips_linux_iterate_over_regset_sections); + + set_gdbarch_gdb_signal_from_target (gdbarch, + mips_gdb_signal_from_target); + + set_gdbarch_gdb_signal_to_target (gdbarch, + mips_gdb_signal_to_target); + tdep->syscall_next_pc = mips_linux_syscall_next_pc; if (tdesc_data) @@ -1214,6 +1629,7 @@ mips_linux_init_abi (struct gdbarch_info info, described or not). */ gdb_assert (gdbarch_num_regs (gdbarch) <= MIPS_RESTART_REGNUM); set_gdbarch_num_regs (gdbarch, MIPS_RESTART_REGNUM + 1); + set_gdbarch_num_pseudo_regs (gdbarch, MIPS_RESTART_REGNUM + 1); /* If it's present, then assign it to the reserved number. */ feature = tdesc_find_feature (info.target_desc, @@ -1224,11 +1640,9 @@ mips_linux_init_abi (struct gdbarch_info info, } } -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_mips_linux_tdep; - +void _initialize_mips_linux_tdep (); void -_initialize_mips_linux_tdep (void) +_initialize_mips_linux_tdep () { const struct bfd_arch_info *arch_info; @@ -1241,5 +1655,9 @@ _initialize_mips_linux_tdep (void) mips_linux_init_abi); } - deprecated_add_core_fns (®set_core_fns); + /* Initialize the standard target descriptions. */ + initialize_tdesc_mips_linux (); + initialize_tdesc_mips_dsp_linux (); + initialize_tdesc_mips64_linux (); + initialize_tdesc_mips64_dsp_linux (); }