X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fmips-linux-tdep.c;h=76bbef2da7affca99807b2f104a3ab002bc08cb0;hb=2d92b4e1632aaedb76f94c43b04ca0551f66204b;hp=20ada7b9477ba7e0df26df93751fab89515d6647;hpb=12c266ea569cae11221236dd5844f4136465ec88;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 20ada7b947..76bbef2da7 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux on MIPS processors. - Copyright 2001, 2002 Free Software Foundation, Inc. + Copyright 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -27,6 +27,9 @@ #include "mips-tdep.h" #include "gdb_string.h" #include "gdb_assert.h" +#include "frame.h" +#include "trad-frame.h" +#include "tramp-frame.h" /* Copied from . */ #define ELF_NGREG 45 @@ -85,8 +88,9 @@ mips_linux_get_longjmp_target (CORE_ADDR *pc) return 1; } -/* Transform the bits comprising a 32-bit register to the right - size for supply_register(). This is needed when MIPS_REGSIZE is 8. */ +/* Transform the bits comprising a 32-bit register to the right size + for supply_register(). This is needed when mips_isa_regsize() is + 8. */ static void supply_32bit_reg (int regnum, const void *addr) @@ -111,13 +115,18 @@ supply_gregset (elf_gregset_t *gregsetp) for (regi = EF_REG0; regi <= EF_REG31; regi++) supply_32bit_reg ((regi - EF_REG0), (char *)(regp + regi)); - supply_32bit_reg (LO_REGNUM, (char *)(regp + EF_LO)); - supply_32bit_reg (HI_REGNUM, (char *)(regp + EF_HI)); + supply_32bit_reg (mips_regnum (current_gdbarch)->lo, + (char *)(regp + EF_LO)); + supply_32bit_reg (mips_regnum (current_gdbarch)->hi, + (char *)(regp + EF_HI)); - supply_32bit_reg (PC_REGNUM, (char *)(regp + EF_CP0_EPC)); - supply_32bit_reg (BADVADDR_REGNUM, (char *)(regp + EF_CP0_BADVADDR)); + supply_32bit_reg (mips_regnum (current_gdbarch)->pc, + (char *)(regp + EF_CP0_EPC)); + supply_32bit_reg (mips_regnum (current_gdbarch)->badvaddr, + (char *)(regp + EF_CP0_BADVADDR)); supply_32bit_reg (PS_REGNUM, (char *)(regp + EF_CP0_STATUS)); - supply_32bit_reg (CAUSE_REGNUM, (char *)(regp + EF_CP0_CAUSE)); + supply_32bit_reg (mips_regnum (current_gdbarch)->cause, + (char *)(regp + EF_CP0_CAUSE)); /* Fill inaccessible registers with zero. */ supply_register (UNUSED_REGNUM, zerobuf); @@ -139,12 +148,12 @@ fill_gregset (elf_gregset_t *gregsetp, int regno) memset (regp, 0, sizeof (elf_gregset_t)); for (regi = 0; regi < 32; regi++) fill_gregset (gregsetp, regi); - fill_gregset (gregsetp, LO_REGNUM); - fill_gregset (gregsetp, HI_REGNUM); - fill_gregset (gregsetp, PC_REGNUM); - fill_gregset (gregsetp, BADVADDR_REGNUM); + fill_gregset (gregsetp, mips_regnum (current_gdbarch)->lo); + fill_gregset (gregsetp, mips_regnum (current_gdbarch)->hi); + fill_gregset (gregsetp, mips_regnum (current_gdbarch)->pc); + fill_gregset (gregsetp, mips_regnum (current_gdbarch)->badvaddr); fill_gregset (gregsetp, PS_REGNUM); - fill_gregset (gregsetp, CAUSE_REGNUM); + fill_gregset (gregsetp, mips_regnum (current_gdbarch)->cause); return; } @@ -156,28 +165,20 @@ fill_gregset (elf_gregset_t *gregsetp, int regno) return; } - regaddr = -1; - switch (regno) - { - case LO_REGNUM: - regaddr = EF_LO; - break; - case HI_REGNUM: - regaddr = EF_HI; - break; - case PC_REGNUM: - regaddr = EF_CP0_EPC; - break; - case BADVADDR_REGNUM: - regaddr = EF_CP0_BADVADDR; - break; - case PS_REGNUM: - regaddr = EF_CP0_STATUS; - break; - case CAUSE_REGNUM: - regaddr = EF_CP0_CAUSE; - break; - } + if (regno == mips_regnum (current_gdbarch)->lo) + regaddr = EF_LO; + else if (regno == mips_regnum (current_gdbarch)->hi) + regaddr = EF_HI; + else if (regno == mips_regnum (current_gdbarch)->pc) + regaddr = EF_CP0_EPC; + else if (regno == mips_regnum (current_gdbarch)->badvaddr) + regaddr = EF_CP0_BADVADDR; + else if (regno == PS_REGNUM) + regaddr = EF_CP0_STATUS; + else if (regno == mips_regnum (current_gdbarch)->cause) + regaddr = EF_CP0_CAUSE; + else + regaddr = -1; if (regaddr != -1) { @@ -200,10 +201,12 @@ supply_fpregset (elf_fpregset_t *fpregsetp) supply_register (FP0_REGNUM + regi, (char *)(*fpregsetp + regi)); - supply_register (FCRCS_REGNUM, (char *)(*fpregsetp + 32)); + supply_register (mips_regnum (current_gdbarch)->fp_control_status, + (char *)(*fpregsetp + 32)); - /* FIXME: how can we supply FCRIR_REGNUM? The ABI doesn't tell us. */ - supply_register (FCRIR_REGNUM, zerobuf); + /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */ + supply_register (mips_regnum (current_gdbarch)->fp_implementation_revision, + zerobuf); } /* Likewise, pack one or all floating point registers into an @@ -220,7 +223,7 @@ fill_fpregset (elf_fpregset_t *fpregsetp, int regno) to = (char *) (*fpregsetp + regno - FP0_REGNUM); memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (regno - FP0_REGNUM)); } - else if (regno == FCRCS_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) { from = (char *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)]; to = (char *) (*fpregsetp + 32); @@ -232,7 +235,7 @@ fill_fpregset (elf_fpregset_t *fpregsetp, int regno) for (regi = 0; regi < 32; regi++) fill_fpregset (fpregsetp, FP0_REGNUM + regi); - fill_fpregset(fpregsetp, FCRCS_REGNUM); + fill_fpregset(fpregsetp, mips_regnum (current_gdbarch)->fp_control_status); } } @@ -249,21 +252,22 @@ mips_linux_register_addr (int regno, CORE_ADDR blockend) if (regno < 32) regaddr = regno; - else if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32)) - regaddr = FPR_BASE + (regno - FP0_REGNUM); - else if (regno == PC_REGNUM) + else if ((regno >= mips_regnum (current_gdbarch)->fp0) + && (regno < mips_regnum (current_gdbarch)->fp0 + 32)) + regaddr = FPR_BASE + (regno - mips_regnum (current_gdbarch)->fp0); + else if (regno == mips_regnum (current_gdbarch)->pc) regaddr = PC; - else if (regno == CAUSE_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->cause) regaddr = CAUSE; - else if (regno == BADVADDR_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->badvaddr) regaddr = BADVADDR; - else if (regno == LO_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->lo) regaddr = MMLO; - else if (regno == HI_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->hi) regaddr = MMHI; - else if (regno == FCRCS_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) regaddr = FPC_CSR; - else if (regno == FCRIR_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) regaddr = FPC_EIR; else error ("Unknowable register number %d.", regno); @@ -386,13 +390,18 @@ mips64_supply_gregset (mips64_elf_gregset_t *gregsetp) for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++) supply_register ((regi - MIPS64_EF_REG0), (char *)(regp + regi)); - supply_register (LO_REGNUM, (char *)(regp + MIPS64_EF_LO)); - supply_register (HI_REGNUM, (char *)(regp + MIPS64_EF_HI)); + supply_register (mips_regnum (current_gdbarch)->lo, + (char *)(regp + MIPS64_EF_LO)); + supply_register (mips_regnum (current_gdbarch)->hi, + (char *)(regp + MIPS64_EF_HI)); - supply_register (PC_REGNUM, (char *)(regp + MIPS64_EF_CP0_EPC)); - supply_register (BADVADDR_REGNUM, (char *)(regp + MIPS64_EF_CP0_BADVADDR)); + supply_register (mips_regnum (current_gdbarch)->pc, + (char *)(regp + MIPS64_EF_CP0_EPC)); + supply_register (mips_regnum (current_gdbarch)->badvaddr, + (char *)(regp + MIPS64_EF_CP0_BADVADDR)); supply_register (PS_REGNUM, (char *)(regp + MIPS64_EF_CP0_STATUS)); - supply_register (CAUSE_REGNUM, (char *)(regp + MIPS64_EF_CP0_CAUSE)); + supply_register (mips_regnum (current_gdbarch)->cause, + (char *)(regp + MIPS64_EF_CP0_CAUSE)); /* Fill inaccessible registers with zero. */ supply_register (UNUSED_REGNUM, zerobuf); @@ -414,12 +423,12 @@ mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno) memset (regp, 0, sizeof (mips64_elf_gregset_t)); for (regi = 0; regi < 32; regi++) mips64_fill_gregset (gregsetp, regi); - mips64_fill_gregset (gregsetp, LO_REGNUM); - mips64_fill_gregset (gregsetp, HI_REGNUM); - mips64_fill_gregset (gregsetp, PC_REGNUM); - mips64_fill_gregset (gregsetp, BADVADDR_REGNUM); + mips64_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->lo); + mips64_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->hi); + mips64_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->pc); + mips64_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->badvaddr); mips64_fill_gregset (gregsetp, PS_REGNUM); - mips64_fill_gregset (gregsetp, CAUSE_REGNUM); + mips64_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->cause); return; } @@ -431,28 +440,20 @@ mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno) return; } - regaddr = -1; - switch (regno) - { - case LO_REGNUM: - regaddr = MIPS64_EF_LO; - break; - case HI_REGNUM: - regaddr = MIPS64_EF_HI; - break; - case PC_REGNUM: - regaddr = MIPS64_EF_CP0_EPC; - break; - case BADVADDR_REGNUM: - regaddr = MIPS64_EF_CP0_BADVADDR; - break; - case PS_REGNUM: - regaddr = MIPS64_EF_CP0_STATUS; - break; - case CAUSE_REGNUM: - regaddr = MIPS64_EF_CP0_CAUSE; - break; - } + if (regno == mips_regnum (current_gdbarch)->lo) + regaddr = MIPS64_EF_LO; + else if (regno == mips_regnum (current_gdbarch)->hi) + regaddr = MIPS64_EF_HI; + else if (regno == mips_regnum (current_gdbarch)->pc) + regaddr = MIPS64_EF_CP0_EPC; + else if (regno == mips_regnum (current_gdbarch)->badvaddr) + regaddr = MIPS64_EF_CP0_BADVADDR; + else if (regno == PS_REGNUM) + regaddr = MIPS64_EF_CP0_STATUS; + else if (regno == mips_regnum (current_gdbarch)->cause) + regaddr = MIPS64_EF_CP0_CAUSE; + else + regaddr = -1; if (regaddr != -1) { @@ -475,10 +476,12 @@ mips64_supply_fpregset (mips64_elf_fpregset_t *fpregsetp) supply_register (FP0_REGNUM + regi, (char *)(*fpregsetp + regi)); - supply_register (FCRCS_REGNUM, (char *)(*fpregsetp + 32)); + supply_register (mips_regnum (current_gdbarch)->fp_control_status, + (char *)(*fpregsetp + 32)); - /* FIXME: how can we supply FCRIR_REGNUM? The ABI doesn't tell us. */ - supply_register (FCRIR_REGNUM, zerobuf); + /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */ + supply_register (mips_regnum (current_gdbarch)->fp_implementation_revision, + zerobuf); } /* Likewise, pack one or all floating point registers into an @@ -495,7 +498,7 @@ mips64_fill_fpregset (mips64_elf_fpregset_t *fpregsetp, int regno) to = (char *) (*fpregsetp + regno - FP0_REGNUM); memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (regno - FP0_REGNUM)); } - else if (regno == FCRCS_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) { from = (char *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)]; to = (char *) (*fpregsetp + 32); @@ -507,7 +510,8 @@ mips64_fill_fpregset (mips64_elf_fpregset_t *fpregsetp, int regno) for (regi = 0; regi < 32; regi++) mips64_fill_fpregset (fpregsetp, FP0_REGNUM + regi); - mips64_fill_fpregset(fpregsetp, FCRCS_REGNUM); + mips64_fill_fpregset(fpregsetp, + mips_regnum (current_gdbarch)->fp_control_status); } } @@ -525,21 +529,22 @@ mips64_linux_register_addr (int regno, CORE_ADDR blockend) if (regno < 32) regaddr = regno; - else if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32)) + else if ((regno >= mips_regnum (current_gdbarch)->fp0) + && (regno < mips_regnum (current_gdbarch)->fp0 + 32)) regaddr = MIPS64_FPR_BASE + (regno - FP0_REGNUM); - else if (regno == PC_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->pc) regaddr = MIPS64_PC; - else if (regno == CAUSE_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->cause) regaddr = MIPS64_CAUSE; - else if (regno == BADVADDR_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->badvaddr) regaddr = MIPS64_BADVADDR; - else if (regno == LO_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->lo) regaddr = MIPS64_MMLO; - else if (regno == HI_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->hi) regaddr = MIPS64_MMHI; - else if (regno == FCRCS_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_control_status) regaddr = MIPS64_FPC_CSR; - else if (regno == FCRIR_REGNUM) + else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision) regaddr = MIPS64_FPC_EIR; else error ("Unknowable register number %d.", regno); @@ -666,7 +671,7 @@ static void set_mips_linux_register_addr (struct gdbarch *gdbarch, CORE_ADDR (*register_addr_ptr) (int, CORE_ADDR)) { - set_gdbarch_data (gdbarch, register_addr_data, register_addr_ptr); + deprecated_set_gdbarch_data (gdbarch, register_addr_data, register_addr_ptr); } static void * @@ -675,6 +680,432 @@ init_register_addr_data (struct gdbarch *gdbarch) return 0; } +/* 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: + + 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. */ + +static int +mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) +{ + unsigned char buf[28], *p; + ULONGEST insn, insn1; + int n64 = (mips_abi (current_gdbarch) == MIPS_ABI_N64); + + read_memory (pc - 12, buf, 28); + + if (n64) + { + /* ld t9,0x8010(gp) */ + insn1 = 0xdf998010; + } + else + { + /* lw t9,0x8010(gp) */ + insn1 = 0x8f998010; + } + + p = buf + 12; + while (p >= buf) + { + insn = extract_unsigned_integer (p, 4); + if (insn == insn1) + break; + p -= 4; + } + if (p < buf) + return 0; + + insn = extract_unsigned_integer (p + 4, 4); + if (n64) + { + /* daddu t7,ra */ + if (insn != 0x03e0782d) + return 0; + } + else + { + /* addu t7,ra */ + if (insn != 0x03e07821) + return 0; + } + + insn = extract_unsigned_integer (p + 8, 4); + /* jalr t9,ra */ + if (insn != 0x0320f809) + return 0; + + insn = extract_unsigned_integer (p + 12, 4); + if (n64) + { + /* daddiu t8,zero,0 */ + if ((insn & 0xffff0000) != 0x64180000) + return 0; + } + else + { + /* addiu t8,zero,0 */ + if ((insn & 0xffff0000) != 0x24180000) + return 0; + } + + return (insn & 0xffff); +} + +/* Return non-zero iff PC belongs to the dynamic linker resolution code + or to a stub. */ + +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. */ + if (in_solib_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)) + return 1; + + return 0; +} + +/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c, + 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, and then pass control to the resolved + function. */ + +static CORE_ADDR +mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + struct minimal_symbol *resolver; + + resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL); + + if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc) + return frame_pc_unwind (get_current_frame ()); + + return 0; +} + +/* Signal trampoline support. There are four supported layouts for a + signal frame: o32 sigframe, o32 rt_sigframe, n32 rt_sigframe, and + n64 rt_sigframe. We handle them all independently; not the most + 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 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 trad_frame_cache *this_cache, + CORE_ADDR func); + +#define MIPS_NR_LINUX 4000 +#define MIPS_NR_N64_LINUX 5000 +#define MIPS_NR_N32_LINUX 6000 + +#define MIPS_NR_sigreturn MIPS_NR_LINUX + 119 +#define MIPS_NR_rt_sigreturn MIPS_NR_LINUX + 193 +#define MIPS_NR_N64_rt_sigreturn MIPS_NR_N64_LINUX + 211 +#define MIPS_NR_N32_rt_sigreturn MIPS_NR_N32_LINUX + 211 + +#define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + MIPS_NR_sigreturn +#define MIPS_INST_LI_V0_RT_SIGRETURN 0x24020000 + MIPS_NR_rt_sigreturn +#define MIPS_INST_LI_V0_N64_RT_SIGRETURN 0x24020000 + MIPS_NR_N64_rt_sigreturn +#define MIPS_INST_LI_V0_N32_RT_SIGRETURN 0x24020000 + MIPS_NR_N32_rt_sigreturn +#define MIPS_INST_SYSCALL 0x0000000c + +struct tramp_frame mips_linux_o32_sigframe = { + 4, + { MIPS_INST_LI_V0_SIGRETURN, MIPS_INST_SYSCALL, TRAMP_SENTINEL_INSN }, + mips_linux_o32_sigframe_init +}; + +struct tramp_frame mips_linux_o32_rt_sigframe = { + 4, + { MIPS_INST_LI_V0_RT_SIGRETURN, MIPS_INST_SYSCALL, TRAMP_SENTINEL_INSN }, + mips_linux_o32_sigframe_init +}; + +struct tramp_frame mips_linux_n32_rt_sigframe = { + 4, + { MIPS_INST_LI_V0_N32_RT_SIGRETURN, MIPS_INST_SYSCALL, TRAMP_SENTINEL_INSN }, + mips_linux_n32n64_sigframe_init +}; + +struct tramp_frame mips_linux_n64_rt_sigframe = { + 4, + { MIPS_INST_LI_V0_N64_RT_SIGRETURN, MIPS_INST_SYSCALL, TRAMP_SENTINEL_INSN }, + mips_linux_n32n64_sigframe_init +}; + +/* *INDENT-OFF* */ +/* The unwinder for o32 signal frames. The legacy structures look + like this: + + struct sigframe { + u32 sf_ass[4]; [argument save space for o32] + u32 sf_code[2]; [signal trampoline] + struct sigcontext sf_sc; + sigset_t sf_mask; + }; + + struct sigcontext { + unsigned int sc_regmask; [Unused] + unsigned int sc_status; + unsigned long long sc_pc; + unsigned long long sc_regs[32]; + unsigned long long sc_fpregs[32]; + unsigned int sc_ownedfp; + unsigned int sc_fpc_csr; + unsigned int sc_fpc_eir; [Unused] + unsigned int sc_used_math; + unsigned int sc_ssflags; [Unused] + [Alignment hole of four bytes] + unsigned long long sc_mdhi; + unsigned long long sc_mdlo; + + unsigned int sc_cause; [Unused] + unsigned int sc_badvaddr; [Unused] + + unsigned long sc_sigset[4]; [kernel's sigset_t] + }; + + 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] + struct siginfo rs_info; + struct ucontext rs_uc; + }; + + struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + [Alignment hole of four bytes] + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; + }; */ +/* *INDENT-ON* */ + +#define SIGFRAME_CODE_OFFSET (4 * 4) +#define SIGFRAME_SIGCONTEXT_OFFSET (6 * 4) + +#define RTSIGFRAME_SIGINFO_SIZE 128 +#define STACK_T_SIZE (3 * 4) +#define UCONTEXT_SIGCONTEXT_OFFSET (2 * 4 + STACK_T_SIZE + 4) +#define RTSIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \ + + RTSIGFRAME_SIGINFO_SIZE \ + + UCONTEXT_SIGCONTEXT_OFFSET) + +#define SIGCONTEXT_PC (1 * 8) +#define SIGCONTEXT_REGS (2 * 8) +#define SIGCONTEXT_FPREGS (34 * 8) +#define SIGCONTEXT_FPCSR (66 * 8 + 4) +#define SIGCONTEXT_HI (69 * 8) +#define SIGCONTEXT_LO (70 * 8) +#define SIGCONTEXT_CAUSE (71 * 8 + 0) +#define SIGCONTEXT_BADVADDR (71 * 8 + 4) + +#define SIGCONTEXT_REG_SIZE 8 + +static void +mips_linux_o32_sigframe_init (const struct tramp_frame *self, + struct frame_info *next_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func) +{ + int ireg, reg_position; + CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET; + const struct mips_regnum *regs = mips_regnum (current_gdbarch); + + if (self == &mips_linux_o32_sigframe) + sigcontext_base += SIGFRAME_SIGCONTEXT_OFFSET; + else + sigcontext_base += 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 per-frame basis, but + right now we don't; the kernel saves eight bytes but we only want + four. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + sigcontext_base += 4; + +#if 0 + trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM + NUM_REGS, + sigcontext_base + SIGCONTEXT_REGS); +#endif + + for (ireg = 1; ireg < 32; ireg++) + trad_frame_set_reg_addr (this_cache, ireg + ZERO_REGNUM + NUM_REGS, + sigcontext_base + SIGCONTEXT_REGS + + ireg * SIGCONTEXT_REG_SIZE); + + for (ireg = 0; ireg < 32; ireg++) + trad_frame_set_reg_addr (this_cache, ireg + regs->fp0 + NUM_REGS, + sigcontext_base + SIGCONTEXT_FPREGS + + ireg * SIGCONTEXT_REG_SIZE); + + trad_frame_set_reg_addr (this_cache, regs->pc + NUM_REGS, + sigcontext_base + SIGCONTEXT_PC); + + trad_frame_set_reg_addr (this_cache, regs->fp_control_status + NUM_REGS, + sigcontext_base + SIGCONTEXT_FPCSR); + trad_frame_set_reg_addr (this_cache, regs->hi + NUM_REGS, + sigcontext_base + SIGCONTEXT_HI); + trad_frame_set_reg_addr (this_cache, regs->lo + NUM_REGS, + sigcontext_base + SIGCONTEXT_LO); + trad_frame_set_reg_addr (this_cache, regs->cause + NUM_REGS, + sigcontext_base + SIGCONTEXT_CAUSE); + trad_frame_set_reg_addr (this_cache, regs->badvaddr + NUM_REGS, + 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)); +} + +/* *INDENT-OFF* */ +/* For N32/N64 things look different. There is no non-rt signal frame. + + struct rt_sigframe_n32 { + u32 rs_ass[4]; [ argument save space for o32 ] + u32 rs_code[2]; [ signal trampoline ] + struct siginfo rs_info; + struct ucontextn32 rs_uc; + }; + + struct ucontextn32 { + u32 uc_flags; + s32 uc_link; + stack32_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; [ mask last for extensibility ] + }; + + struct rt_sigframe_n32 { + u32 rs_ass[4]; [ argument save space for o32 ] + u32 rs_code[2]; [ signal trampoline ] + struct siginfo rs_info; + struct ucontext rs_uc; + }; + + struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; [ mask last for extensibility ] + }; + + And the sigcontext is different (this is for both n32 and n64): + + struct sigcontext { + unsigned long long sc_regs[32]; + unsigned long long sc_fpregs[32]; + unsigned long long sc_mdhi; + unsigned long long sc_mdlo; + 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; + }; */ +/* *INDENT-ON* */ + +#define N32_STACK_T_SIZE STACK_T_SIZE +#define N64_STACK_T_SIZE (2 * 8 + 4) +#define N32_UCONTEXT_SIGCONTEXT_OFFSET (2 * 4 + N32_STACK_T_SIZE + 4) +#define N64_UCONTEXT_SIGCONTEXT_OFFSET (2 * 8 + N64_STACK_T_SIZE + 4) +#define N32_SIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \ + + RTSIGFRAME_SIGINFO_SIZE \ + + N32_UCONTEXT_SIGCONTEXT_OFFSET) +#define N64_SIGFRAME_SIGCONTEXT_OFFSET (SIGFRAME_SIGCONTEXT_OFFSET \ + + RTSIGFRAME_SIGINFO_SIZE \ + + N64_UCONTEXT_SIGCONTEXT_OFFSET) + +#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_REG_SIZE 8 + +static void +mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, + struct frame_info *next_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func) +{ + int ireg, reg_position; + CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET; + const struct mips_regnum *regs = mips_regnum (current_gdbarch); + + if (self == &mips_linux_n32_rt_sigframe) + sigcontext_base += N32_SIGFRAME_SIGCONTEXT_OFFSET; + else + sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET; + +#if 0 + trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_REGS); +#endif + + for (ireg = 1; ireg < 32; ireg++) + trad_frame_set_reg_addr (this_cache, ireg + ZERO_REGNUM + NUM_REGS, + 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 + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_FPREGS + + ireg * N64_SIGCONTEXT_REG_SIZE); + + trad_frame_set_reg_addr (this_cache, regs->pc + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_PC); + + trad_frame_set_reg_addr (this_cache, regs->fp_control_status + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_FPCSR); + trad_frame_set_reg_addr (this_cache, regs->hi + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_HI); + trad_frame_set_reg_addr (this_cache, regs->lo + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_LO); + trad_frame_set_reg_addr (this_cache, regs->cause + NUM_REGS, + sigcontext_base + N64_SIGCONTEXT_CAUSE); + trad_frame_set_reg_addr (this_cache, regs->badvaddr + NUM_REGS, + sigcontext_base + N64_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)); +} + +/* Initialize one of the GNU/Linux OS ABIs. */ + static void mips_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -689,6 +1120,8 @@ mips_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_solib_svr4_fetch_link_map_offsets (gdbarch, mips_linux_svr4_fetch_link_map_offsets); set_mips_linux_register_addr (gdbarch, mips_linux_register_addr); + tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe); + tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe); break; case MIPS_ABI_N32: set_gdbarch_get_longjmp_target (gdbarch, @@ -696,6 +1129,7 @@ mips_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_solib_svr4_fetch_link_map_offsets (gdbarch, mips_linux_svr4_fetch_link_map_offsets); set_mips_linux_register_addr (gdbarch, mips64_linux_register_addr); + tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe); break; case MIPS_ABI_N64: set_gdbarch_get_longjmp_target (gdbarch, @@ -703,11 +1137,18 @@ mips_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_solib_svr4_fetch_link_map_offsets (gdbarch, mips64_linux_svr4_fetch_link_map_offsets); set_mips_linux_register_addr (gdbarch, mips64_linux_register_addr); + tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe); break; default: internal_error (__FILE__, __LINE__, "can't handle ABI"); break; } + + set_gdbarch_skip_solib_resolver (gdbarch, mips_linux_skip_resolver); + + /* This overrides the MIPS16 stub support from mips-tdep. But no + one uses MIPS16 on GNU/Linux yet, so this isn't much of a loss. */ + set_gdbarch_in_solib_call_trampoline (gdbarch, mips_linux_in_dynsym_stub); } void @@ -716,7 +1157,7 @@ _initialize_mips_linux_tdep (void) const struct bfd_arch_info *arch_info; register_addr_data = - register_gdbarch_data (init_register_addr_data); + gdbarch_data_register_post_init (init_register_addr_data); for (arch_info = bfd_lookup_arch (bfd_arch_mips, 0); arch_info != NULL; @@ -726,5 +1167,5 @@ _initialize_mips_linux_tdep (void) mips_linux_init_abi); } - add_core_fns (®set_core_fns); + deprecated_add_core_fns (®set_core_fns); }