/* Target-dependent code for GNU/Linux on MIPS processors.
- Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2001-2019 Free Software Foundation, Inc.
This file is part of GDB.
#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 "common/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 <arch/mips/include/uapi/asm/signal.h>,
+ 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
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;
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. */
{
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);
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. */
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;
if (regno > 0 && regno < 32)
{
dst = regp + regno + EF_REG0;
- regcache_raw_collect (regcache, regno, dst);
+ regcache->raw_collect (regno, dst);
return;
}
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)
-{
- 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);
-
- 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)
+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);
- 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;
+ gdb_assert (len >= sizeof (mips_elf_gregset_t));
- 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. */
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);
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. */
{
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));
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. */
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;
{
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);
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);
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)
{
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);
+}
-/* 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 mips_linux_gregset =
+ {
+ NULL, mips_supply_gregset_wrapper, mips_fill_gregset_wrapper
+ };
+
+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,
/* 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);
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;
+
}
insn = extract_unsigned_integer (p + 8, 4, byte_order);
return 0;
}
- return (insn & 0xffff);
+ return 1;
}
/* Return non-zero iff PC belongs to the dynamic linker resolution
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;
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);
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
#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* */
struct sigframe {
u32 sf_ass[4]; [argument save space for o32]
- u32 sf_code[2]; [signal trampoline]
+ u32 sf_code[2]; [signal trampoline or fill]
struct sigcontext sf_sc;
sigset_t sf_mask;
};
+ Pre-2.6.12 sigcontext:
+
struct sigcontext {
unsigned int sc_regmask; [Unused]
unsigned int sc_status;
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 {
u32 rs_ass[4]; [argument save space for o32]
- u32 rs_code[2] [signal trampoline]
+ u32 rs_code[2] [signal trampoline or fill]
struct siginfo rs_info;
struct ucontext rs_uc;
};
}; */
/* *INDENT-ON* */
-#define SIGFRAME_CODE_OFFSET (4 * 4)
#define SIGFRAME_SIGCONTEXT_OFFSET (6 * 4)
#define RTSIGFRAME_SIGINFO_SIZE 128
#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
CORE_ADDR func)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
- int ireg, reg_position;
- CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
+ 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)
- sigcontext_base += SIGFRAME_SIGCONTEXT_OFFSET;
+ if (self == &mips_linux_o32_sigframe
+ || self == µmips_linux_o32_sigframe)
+ sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET;
else
- sigcontext_base += RTSIGFRAME_SIGCONTEXT_OFFSET;
+ sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET;
/* I'm not proud of this hack. Eventually we will have the
infrastructure to indicate the size of saved registers on a
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 (func - SIGFRAME_CODE_OFFSET,
- func));
+ trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
}
/* *INDENT-OFF* */
struct rt_sigframe_n32 {
u32 rs_ass[4]; [ argument save space for o32 ]
- u32 rs_code[2]; [ signal trampoline ]
+ u32 rs_code[2]; [ signal trampoline or fill ]
struct siginfo rs_info;
struct ucontextn32 rs_uc;
};
#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
CORE_ADDR func)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
- int ireg, reg_position;
- CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
+ 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)
- sigcontext_base += N32_SIGFRAME_SIGCONTEXT_OFFSET;
+ if (self == &mips_linux_n32_rt_sigframe
+ || self == µmips_linux_n32_rt_sigframe)
+ sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET;
else
- sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET;
+ sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET;
if (mips_linux_restart_reg_p (gdbarch))
trad_frame_set_reg_addr (this_cache,
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);
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 (func - SIGFRAME_CODE_OFFSET,
- func));
+ 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))
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 <gdb/signals.def>,
+ 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/common/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
{
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);
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);
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;
/* 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. */
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)
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,
}
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_mips_linux_tdep;
-
void
_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 ();
}