/* Target-dependent code for GNU/Linux on MIPS processors.
- Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007
+ Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GDB.
#include "symtab.h"
#include "target-descriptions.h"
#include "mips-linux-tdep.h"
+#include "glibc-tdep.h"
static struct target_so_ops mips_svr4_so_ops;
mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
CORE_ADDR jb_addr;
- char buf[gdbarch_ptr_bit (current_gdbarch) / TARGET_CHAR_BIT];
+ 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];
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,
- buf,
- gdbarch_ptr_bit (current_gdbarch) / TARGET_CHAR_BIT))
+ buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
return 0;
*pc = extract_unsigned_integer (buf,
- gdbarch_ptr_bit (current_gdbarch)
- / TARGET_CHAR_BIT);
+ gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
+ byte_order);
return 1;
}
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 (current_gdbarch, regnum),
- extract_signed_integer (addr, 4));
+ store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
+ extract_signed_integer (addr, 4, byte_order));
regcache_raw_supply (regcache, regnum, buf);
}
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);
for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++)
supply_32bit_reg (regcache, regi - EF_REG0, regp + regi);
- if (mips_linux_restart_reg_p (current_gdbarch))
+ if (mips_linux_restart_reg_p (gdbarch))
supply_32bit_reg (regcache, MIPS_RESTART_REGNUM, regp + EF_REG0);
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
- regp + EF_LO);
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
- regp + EF_HI);
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->lo, regp + EF_LO);
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->hi, regp + EF_HI);
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->pc,
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->pc,
regp + EF_CP0_EPC);
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->badvaddr,
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
regp + EF_CP0_BADVADDR);
supply_32bit_reg (regcache, MIPS_PS_REGNUM, regp + EF_CP0_STATUS);
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->cause,
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->cause,
regp + EF_CP0_CAUSE);
/* Fill inaccessible registers with zero. */
mips_fill_gregset (const struct regcache *regcache,
mips_elf_gregset_t *gregsetp, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int regaddr, regi;
mips_elf_greg_t *regp = *gregsetp;
void *dst;
memset (regp, 0, sizeof (mips_elf_gregset_t));
for (regi = 1; regi < 32; regi++)
mips_fill_gregset (regcache, gregsetp, regi);
- mips_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->lo);
- mips_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->hi);
- mips_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->pc);
- mips_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->badvaddr);
+ mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo);
+ mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi);
+ mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc);
+ mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->badvaddr);
mips_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
- mips_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->cause);
+ mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause);
mips_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
return;
}
return;
}
- if (regno == mips_regnum (current_gdbarch)->lo)
- regaddr = EF_LO;
- else if (regno == mips_regnum (current_gdbarch)->hi)
+ if (regno == mips_regnum (gdbarch)->lo)
+ regaddr = EF_LO;
+ else if (regno == mips_regnum (gdbarch)->hi)
regaddr = EF_HI;
- else if (regno == mips_regnum (current_gdbarch)->pc)
+ else if (regno == mips_regnum (gdbarch)->pc)
regaddr = EF_CP0_EPC;
- else if (regno == mips_regnum (current_gdbarch)->badvaddr)
+ else if (regno == mips_regnum (gdbarch)->badvaddr)
regaddr = EF_CP0_BADVADDR;
else if (regno == MIPS_PS_REGNUM)
regaddr = EF_CP0_STATUS;
- else if (regno == mips_regnum (current_gdbarch)->cause)
+ else if (regno == mips_regnum (gdbarch)->cause)
regaddr = EF_CP0_CAUSE;
- else if (mips_linux_restart_reg_p (current_gdbarch)
+ else if (mips_linux_restart_reg_p (gdbarch)
&& regno == MIPS_RESTART_REGNUM)
regaddr = EF_REG0;
else
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];
for (regi = 0; regi < 32; regi++)
regcache_raw_supply (regcache,
- gdbarch_fp0_regnum (current_gdbarch) + regi,
+ gdbarch_fp0_regnum (gdbarch) + regi,
*fpregsetp + regi);
regcache_raw_supply (regcache,
- mips_regnum (current_gdbarch)->fp_control_status,
+ 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 (current_gdbarch)->fp_implementation_revision,
+ mips_regnum (gdbarch)->fp_implementation_revision,
zerobuf);
}
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 (current_gdbarch))
- && (regno < gdbarch_fp0_regnum (current_gdbarch) + 32))
+ if ((regno >= gdbarch_fp0_regnum (gdbarch))
+ && (regno < gdbarch_fp0_regnum (gdbarch) + 32))
{
- to = (char *) (*fpregsetp + regno - gdbarch_fp0_regnum (current_gdbarch));
+ to = (char *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
regcache_raw_collect (regcache, regno, to);
}
- else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ else if (regno == mips_regnum (gdbarch)->fp_control_status)
{
to = (char *) (*fpregsetp + 32);
regcache_raw_collect (regcache, regno, to);
for (regi = 0; regi < 32; regi++)
mips_fill_fpregset (regcache, fpregsetp,
- gdbarch_fp0_regnum (current_gdbarch) + regi);
+ gdbarch_fp0_regnum (gdbarch) + regi);
mips_fill_fpregset (regcache, fpregsetp,
- mips_regnum (current_gdbarch)->fp_control_status);
+ mips_regnum (gdbarch)->fp_control_status);
}
}
mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
CORE_ADDR jb_addr;
- void *buf = alloca (gdbarch_ptr_bit (current_gdbarch) / TARGET_CHAR_BIT);
- int element_size = gdbarch_ptr_bit (current_gdbarch) == 32 ? 4 : 8;
+ 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);
+ int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8;
jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
if (target_read_memory (jb_addr + MIPS64_LINUX_JB_PC * element_size,
buf,
- gdbarch_ptr_bit (current_gdbarch) / TARGET_CHAR_BIT))
+ gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
return 0;
*pc = extract_unsigned_integer (buf,
- gdbarch_ptr_bit (current_gdbarch)
- / TARGET_CHAR_BIT);
+ gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
+ byte_order);
return 1;
}
/* Supply a 64-bit register. */
-void
+static void
supply_64bit_reg (struct regcache *regcache, int regnum,
const gdb_byte *buf)
{
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
- && register_size (current_gdbarch, regnum) == 4)
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
+ && register_size (gdbarch, regnum) == 4)
regcache_raw_supply (regcache, regnum, buf + 4);
else
regcache_raw_supply (regcache, regnum, buf);
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);
supply_64bit_reg (regcache, regi - MIPS64_EF_REG0,
(const gdb_byte *)(regp + regi));
- if (mips_linux_restart_reg_p (current_gdbarch))
+ if (mips_linux_restart_reg_p (gdbarch))
supply_64bit_reg (regcache, MIPS_RESTART_REGNUM,
(const gdb_byte *)(regp + MIPS64_EF_REG0));
- supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
+ supply_64bit_reg (regcache, mips_regnum (gdbarch)->lo,
(const gdb_byte *) (regp + MIPS64_EF_LO));
- supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
+ supply_64bit_reg (regcache, mips_regnum (gdbarch)->hi,
(const gdb_byte *) (regp + MIPS64_EF_HI));
- supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->pc,
+ supply_64bit_reg (regcache, mips_regnum (gdbarch)->pc,
(const gdb_byte *) (regp + MIPS64_EF_CP0_EPC));
- supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->badvaddr,
+ supply_64bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
(const gdb_byte *) (regp + MIPS64_EF_CP0_BADVADDR));
supply_64bit_reg (regcache, MIPS_PS_REGNUM,
(const gdb_byte *) (regp + MIPS64_EF_CP0_STATUS));
- supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->cause,
+ supply_64bit_reg (regcache, mips_regnum (gdbarch)->cause,
(const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE));
/* Fill inaccessible registers with zero. */
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);
int regaddr, regi;
mips64_elf_greg_t *regp = *gregsetp;
- void *src, *dst;
+ void *dst;
if (regno == -1)
{
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,
- mips_regnum (current_gdbarch)->lo);
- mips64_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->hi);
- mips64_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->pc);
- mips64_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->badvaddr);
+ 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_PS_REGNUM);
- mips64_fill_gregset (regcache, gregsetp,
- mips_regnum (current_gdbarch)->cause);
+ mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause);
mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
return;
}
if (regno > 0 && regno < 32)
regaddr = regno + MIPS64_EF_REG0;
- else if (regno == mips_regnum (current_gdbarch)->lo)
+ else if (regno == mips_regnum (gdbarch)->lo)
regaddr = MIPS64_EF_LO;
- else if (regno == mips_regnum (current_gdbarch)->hi)
+ else if (regno == mips_regnum (gdbarch)->hi)
regaddr = MIPS64_EF_HI;
- else if (regno == mips_regnum (current_gdbarch)->pc)
+ else if (regno == mips_regnum (gdbarch)->pc)
regaddr = MIPS64_EF_CP0_EPC;
- else if (regno == mips_regnum (current_gdbarch)->badvaddr)
+ else if (regno == mips_regnum (gdbarch)->badvaddr)
regaddr = MIPS64_EF_CP0_BADVADDR;
else if (regno == MIPS_PS_REGNUM)
regaddr = MIPS64_EF_CP0_STATUS;
- else if (regno == mips_regnum (current_gdbarch)->cause)
+ else if (regno == mips_regnum (gdbarch)->cause)
regaddr = MIPS64_EF_CP0_CAUSE;
- else if (mips_linux_restart_reg_p (current_gdbarch)
+ else if (mips_linux_restart_reg_p (gdbarch)
&& regno == MIPS_RESTART_REGNUM)
regaddr = MIPS64_EF_REG0;
else
LONGEST val;
regcache_raw_collect (regcache, regno, buf);
- val = extract_signed_integer (buf,
- register_size (current_gdbarch, regno));
+ val = extract_signed_integer (buf, register_size (gdbarch, regno),
+ byte_order);
dst = regp + regaddr;
- store_signed_integer (dst, 8, val);
+ store_signed_integer (dst, 8, byte_order, val);
}
}
mips64_supply_fpregset (struct regcache *regcache,
const mips64_elf_fpregset_t *fpregsetp)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int regi;
/* See mips_linux_o32_sigframe_init for a description of the
peculiar FP register layout. */
- if (register_size (current_gdbarch,
- gdbarch_fp0_regnum (current_gdbarch)) == 4)
+ 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));
- if ((gdbarch_byte_order (current_gdbarch)
- == BFD_ENDIAN_BIG) != (regi & 1))
+ if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
reg_ptr += 4;
regcache_raw_supply (regcache,
- gdbarch_fp0_regnum (current_gdbarch) + regi,
+ gdbarch_fp0_regnum (gdbarch) + regi,
reg_ptr);
}
else
for (regi = 0; regi < 32; regi++)
regcache_raw_supply (regcache,
- gdbarch_fp0_regnum (current_gdbarch) + regi,
+ gdbarch_fp0_regnum (gdbarch) + regi,
(const char *)(*fpregsetp + regi));
- supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->fp_control_status,
+ supply_32bit_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
(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 (current_gdbarch)->fp_implementation_revision,
+ mips_regnum (gdbarch)->fp_implementation_revision,
(const gdb_byte *)(*fpregsetp + 32) + 4);
}
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);
gdb_byte *to;
- if ((regno >= gdbarch_fp0_regnum (current_gdbarch))
- && (regno < gdbarch_fp0_regnum (current_gdbarch) + 32))
+ 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 (current_gdbarch, regno) == 4)
+ if (register_size (gdbarch, regno) == 4)
{
- int regi = regno - gdbarch_fp0_regnum (current_gdbarch);
+ int regi = regno - gdbarch_fp0_regnum (gdbarch);
to = (gdb_byte *) (*fpregsetp + (regi & ~1));
- if ((gdbarch_byte_order (current_gdbarch)
- == BFD_ENDIAN_BIG) != (regi & 1))
+ if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
to += 4;
regcache_raw_collect (regcache, regno, to);
}
else
{
- to = (gdb_byte *) (*fpregsetp + regno
- - gdbarch_fp0_regnum (current_gdbarch));
+ to = (gdb_byte *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
regcache_raw_collect (regcache, regno, to);
}
}
- else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ 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 (current_gdbarch, regno));
+ val = extract_signed_integer (buf, register_size (gdbarch, regno),
+ byte_order);
to = (gdb_byte *) (*fpregsetp + 32);
- store_signed_integer (to, 4, val);
+ store_signed_integer (to, 4, byte_order, val);
}
- else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ 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 (current_gdbarch, regno));
+ val = extract_signed_integer (buf, register_size (gdbarch, regno),
+ byte_order);
to = (gdb_byte *) (*fpregsetp + 32) + 4;
- store_signed_integer (to, 4, val);
+ store_signed_integer (to, 4, byte_order, val);
}
else if (regno == -1)
{
for (regi = 0; regi < 32; regi++)
mips64_fill_fpregset (regcache, fpregsetp,
- gdbarch_fp0_regnum (current_gdbarch) + regi);
+ gdbarch_fp0_regnum (gdbarch) + regi);
mips64_fill_fpregset (regcache, fpregsetp,
- mips_regnum (current_gdbarch)->fp_control_status);
+ mips_regnum (gdbarch)->fp_control_status);
mips64_fill_fpregset (regcache, fpregsetp,
- (mips_regnum (current_gdbarch)
- ->fp_implementation_revision));
+ (mips_regnum (gdbarch)
+ ->fp_implementation_revision));
}
}
NULL /* next */
};
+static const struct target_desc *
+mips_linux_core_read_description (struct gdbarch *gdbarch,
+ struct target_ops *target,
+ bfd *abfd)
+{
+ asection *section = bfd_get_section_by_name (abfd, ".reg");
+ if (! section)
+ return NULL;
+
+ switch (bfd_section_size (abfd, section))
+ {
+ case sizeof (mips_elf_gregset_t):
+ return mips_tdesc_gp32;
+
+ case sizeof (mips64_elf_gregset_t):
+ return mips_tdesc_gp64;
+
+ default:
+ return NULL;
+ }
+}
+
/* 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
{
unsigned char buf[28], *p;
ULONGEST insn, insn1;
- int n64 = (mips_abi (current_gdbarch) == MIPS_ABI_N64);
+ int n64 = (mips_abi (target_gdbarch) == MIPS_ABI_N64);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
read_memory (pc - 12, buf, 28);
p = buf + 12;
while (p >= buf)
{
- insn = extract_unsigned_integer (p, 4);
+ insn = extract_unsigned_integer (p, 4, byte_order);
if (insn == insn1)
break;
p -= 4;
if (p < buf)
return 0;
- insn = extract_unsigned_integer (p + 4, 4);
+ insn = extract_unsigned_integer (p + 4, 4, byte_order);
if (n64)
{
/* daddu t7,ra */
return 0;
}
- insn = extract_unsigned_integer (p + 8, 4);
+ insn = extract_unsigned_integer (p + 8, 4, byte_order);
/* jalr t9,ra */
if (insn != 0x0320f809)
return 0;
- insn = extract_unsigned_integer (p + 12, 4);
+ insn = extract_unsigned_integer (p + 12, 4, byte_order);
if (n64)
{
/* daddiu t8,zero,0 */
}
/* Return non-zero iff PC belongs to the dynamic linker resolution
- code or to a stub. */
+ code, a PLT entry, or a lazy binding stub. */
static int
mips_linux_in_dynsym_resolve_code (CORE_ADDR pc)
{
/* Check whether PC is in the dynamic linker. This also checks
- whether it is in the .plt section, which MIPS does not use. */
+ whether it is in the .plt section, used by non-PIC executables. */
if (svr4_in_dynsym_resolve_code (pc))
return 1;
and glibc_skip_solib_resolver in glibc-tdep.c. The normal glibc
implementation of this triggers at "fixup" from the same objfile as
"_dl_runtime_resolve"; MIPS GNU/Linux can trigger at
- "__dl_runtime_resolve" directly. An unresolved PLT entry will
- point to _dl_runtime_resolve, which will first call
+ "__dl_runtime_resolve" directly. An unresolved lazy binding
+ stub will point to _dl_runtime_resolve, which will first call
__dl_runtime_resolve, and then pass control to the resolved
function. */
resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL);
if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc)
- return frame_pc_unwind (get_current_frame ());
+ return frame_unwind_caller_pc (get_current_frame ());
- return 0;
+ return glibc_skip_solib_resolver (gdbarch, pc);
}
/* Signal trampoline support. There are four supported layouts for a
efficient way, but simplest. First, declare all the unwinders. */
static void mips_linux_o32_sigframe_init (const struct tramp_frame *self,
- struct frame_info *next_frame,
+ struct frame_info *this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
- struct frame_info *next_frame,
+ struct frame_info *this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
static void
mips_linux_o32_sigframe_init (const struct tramp_frame *self,
- struct frame_info *next_frame,
+ struct frame_info *this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
int ireg, reg_position;
CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
- const struct mips_regnum *regs = mips_regnum (current_gdbarch);
+ const struct mips_regnum *regs = mips_regnum (gdbarch);
CORE_ADDR regs_base;
if (self == &mips_linux_o32_sigframe)
per-frame basis, but right now we don't; the kernel saves eight
bytes but we only want four. Use regs_base to access any
64-bit fields. */
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
regs_base = sigcontext_base + 4;
else
regs_base = sigcontext_base;
- if (mips_linux_restart_reg_p (current_gdbarch))
+ if (mips_linux_restart_reg_p (gdbarch))
trad_frame_set_reg_addr (this_cache,
(MIPS_RESTART_REGNUM
- + gdbarch_num_regs (current_gdbarch)),
+ + gdbarch_num_regs (gdbarch)),
regs_base + SIGCONTEXT_REGS);
for (ireg = 1; ireg < 32; ireg++)
trad_frame_set_reg_addr (this_cache,
ireg + MIPS_ZERO_REGNUM
- + gdbarch_num_regs (current_gdbarch),
+ + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_REGS
+ ireg * SIGCONTEXT_REG_SIZE);
layout, since we can't tell, and it's much more common. Which bits are
the "high" bits depends on endianness. */
for (ireg = 0; ireg < 32; ireg++)
- if ((gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1))
+ if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1))
trad_frame_set_reg_addr (this_cache,
ireg + regs->fp0 +
- gdbarch_num_regs (current_gdbarch),
+ 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 (current_gdbarch),
+ + 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 (current_gdbarch),
+ regs->pc + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_PC);
trad_frame_set_reg_addr (this_cache,
regs->fp_control_status
- + gdbarch_num_regs (current_gdbarch),
+ + gdbarch_num_regs (gdbarch),
sigcontext_base + SIGCONTEXT_FPCSR);
trad_frame_set_reg_addr (this_cache,
- regs->hi + gdbarch_num_regs (current_gdbarch),
+ regs->hi + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_HI);
trad_frame_set_reg_addr (this_cache,
- regs->lo + gdbarch_num_regs (current_gdbarch),
+ regs->lo + gdbarch_num_regs (gdbarch),
regs_base + SIGCONTEXT_LO);
trad_frame_set_reg_addr (this_cache,
- regs->cause + gdbarch_num_regs (current_gdbarch),
+ regs->cause + gdbarch_num_regs (gdbarch),
sigcontext_base + SIGCONTEXT_CAUSE);
trad_frame_set_reg_addr (this_cache,
- regs->badvaddr + gdbarch_num_regs (current_gdbarch),
+ regs->badvaddr + gdbarch_num_regs (gdbarch),
sigcontext_base + SIGCONTEXT_BADVADDR);
/* Choice of the bottom of the sigframe is somewhat arbitrary. */
sigset_t uc_sigmask; [ mask last for extensibility ]
};
- struct rt_sigframe_n32 {
+ struct rt_sigframe {
u32 rs_ass[4]; [ argument save space for o32 ]
u32 rs_code[2]; [ signal trampoline ]
struct siginfo rs_info;
unsigned long long sc_regs[32];
unsigned long long sc_fpregs[32];
unsigned long long sc_mdhi;
+ unsigned long long sc_hi1;
+ unsigned long long sc_hi2;
+ unsigned long long sc_hi3;
unsigned long long sc_mdlo;
+ unsigned long long sc_lo1;
+ unsigned long long sc_lo2;
+ unsigned long long sc_lo3;
unsigned long long sc_pc;
- unsigned int sc_status;
unsigned int sc_fpc_csr;
- unsigned int sc_fpc_eir;
unsigned int sc_used_math;
- unsigned int sc_cause;
- unsigned int sc_badvaddr;
- }; */
+ unsigned int sc_dsp;
+ unsigned int sc_reserved;
+ };
+
+ That is the post-2.6.12 definition of the 64-bit sigcontext; before
+ then, there were no hi1-hi3 or lo1-lo3. Cause and badvaddr were
+ included too. */
/* *INDENT-ON* */
#define N32_STACK_T_SIZE STACK_T_SIZE
#define N64_SIGCONTEXT_REGS (0 * 8)
#define N64_SIGCONTEXT_FPREGS (32 * 8)
#define N64_SIGCONTEXT_HI (64 * 8)
-#define N64_SIGCONTEXT_LO (65 * 8)
-#define N64_SIGCONTEXT_PC (66 * 8)
-#define N64_SIGCONTEXT_FPCSR (67 * 8 + 1 * 4)
-#define N64_SIGCONTEXT_FIR (67 * 8 + 2 * 4)
-#define N64_SIGCONTEXT_CAUSE (67 * 8 + 4 * 4)
-#define N64_SIGCONTEXT_BADVADDR (67 * 8 + 5 * 4)
+#define N64_SIGCONTEXT_LO (68 * 8)
+#define N64_SIGCONTEXT_PC (72 * 8)
+#define N64_SIGCONTEXT_FPCSR (73 * 8)
#define N64_SIGCONTEXT_REG_SIZE 8
static void
mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
- struct frame_info *next_frame,
+ struct frame_info *this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
int ireg, reg_position;
CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
- const struct mips_regnum *regs = mips_regnum (current_gdbarch);
+ const struct mips_regnum *regs = mips_regnum (gdbarch);
if (self == &mips_linux_n32_rt_sigframe)
sigcontext_base += N32_SIGFRAME_SIGCONTEXT_OFFSET;
else
sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET;
- if (mips_linux_restart_reg_p (current_gdbarch))
+ if (mips_linux_restart_reg_p (gdbarch))
trad_frame_set_reg_addr (this_cache,
(MIPS_RESTART_REGNUM
- + gdbarch_num_regs (current_gdbarch)),
+ + gdbarch_num_regs (gdbarch)),
sigcontext_base + N64_SIGCONTEXT_REGS);
for (ireg = 1; ireg < 32; ireg++)
trad_frame_set_reg_addr (this_cache,
ireg + MIPS_ZERO_REGNUM
- + gdbarch_num_regs (current_gdbarch),
+ + 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 (current_gdbarch),
+ + 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 (current_gdbarch),
+ 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 (current_gdbarch),
+ + gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_FPCSR);
trad_frame_set_reg_addr (this_cache,
- regs->hi + gdbarch_num_regs (current_gdbarch),
+ regs->hi + gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_HI);
trad_frame_set_reg_addr (this_cache,
- regs->lo + gdbarch_num_regs (current_gdbarch),
+ regs->lo + gdbarch_num_regs (gdbarch),
sigcontext_base + N64_SIGCONTEXT_LO);
- trad_frame_set_reg_addr (this_cache,
- regs->cause + gdbarch_num_regs (current_gdbarch),
- sigcontext_base + N64_SIGCONTEXT_CAUSE);
- trad_frame_set_reg_addr (this_cache,
- regs->badvaddr + gdbarch_num_regs (current_gdbarch),
- sigcontext_base + N64_SIGCONTEXT_BADVADDR);
/* Choice of the bottom of the sigframe is somewhat arbitrary. */
trad_frame_set_id (this_cache,
static void
mips_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- regcache_cooked_write_unsigned (regcache,
- gdbarch_pc_regnum (current_gdbarch), pc);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch), pc);
/* Clear the syscall restart flag. */
- if (mips_linux_restart_reg_p (current_gdbarch))
+ if (mips_linux_restart_reg_p (gdbarch))
regcache_cooked_write_unsigned (regcache, MIPS_RESTART_REGNUM, 0);
}
return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0;
}
+/* When FRAME is at a syscall instruction, return the PC of the next
+ instruction to be executed. */
+
+static CORE_ADDR
+mips_linux_syscall_next_pc (struct frame_info *frame)
+{
+ CORE_ADDR pc = get_frame_pc (frame);
+ ULONGEST v0 = get_frame_register_unsigned (frame, MIPS_V0_REGNUM);
+
+ /* If we are about to make a sigreturn syscall, use the unwinder to
+ decode the signal frame. */
+ if (v0 == MIPS_NR_sigreturn
+ || v0 == MIPS_NR_rt_sigreturn
+ || v0 == MIPS_NR_N64_rt_sigreturn
+ || v0 == MIPS_NR_N32_rt_sigreturn)
+ return frame_unwind_caller_pc (get_current_frame ());
+
+ return pc + 4;
+}
+
/* Initialize one of the GNU/Linux OS ABIs. */
static void
tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
break;
default:
- internal_error (__FILE__, __LINE__, _("can't handle ABI"));
break;
}
- set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
set_gdbarch_skip_solib_resolver (gdbarch, mips_linux_skip_resolver);
set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
set_gdbarch_write_pc (gdbarch, mips_linux_write_pc);
+ set_gdbarch_core_read_description (gdbarch,
+ mips_linux_core_read_description);
+
+ tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+
if (tdesc_data)
{
const struct tdesc_feature *feature;
}
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_mips_linux_tdep;
+
void
_initialize_mips_linux_tdep (void)
{