X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fmips-linux-tdep.c;h=5924b30984db3d95f2219f18082da3c3b1de7c98;hb=8ea5bce59057ef1906bf1180843c0900b191dcab;hp=046e086e74c0ee5efdb1c02cb6ccefb2566d6eef;hpb=2ba9393420ffee43397a14781dc1f59982fe5876;p=binutils-gdb.git diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 046e086e74c..5924b30984d 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 (C) 2001, 2002, 2004, 2005, 2006, 2007 + Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GDB. @@ -37,6 +37,7 @@ #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; @@ -54,6 +55,7 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) { CORE_ADDR jb_addr; struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); char buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT]; jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM); @@ -64,7 +66,8 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) return 0; *pc = extract_unsigned_integer (buf, - gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT, + byte_order); return 1; } @@ -76,10 +79,11 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) static void supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr) { + struct gdbarch *gdbarch = get_regcache_arch (regcache); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); gdb_byte buf[MAX_REGISTER_SIZE]; - store_signed_integer (buf, - register_size (get_regcache_arch (regcache), 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); } @@ -257,6 +261,7 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) { CORE_ADDR jb_addr; struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); void *buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8; @@ -268,7 +273,8 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) return 0; *pc = extract_unsigned_integer (buf, - gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT); + gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT, + byte_order); return 1; } @@ -279,7 +285,7 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) /* Supply a 64-bit register. */ -void +static void supply_64bit_reg (struct regcache *regcache, int regnum, const gdb_byte *buf) { @@ -342,6 +348,7 @@ 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 *dst; @@ -387,9 +394,10 @@ mips64_fill_gregset (const struct regcache *regcache, LONGEST val; regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (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); } } @@ -439,6 +447,7 @@ 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 (gdbarch)) @@ -467,9 +476,10 @@ mips64_fill_fpregset (const struct regcache *regcache, LONGEST val; regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (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 (gdbarch)->fp_implementation_revision) { @@ -477,9 +487,10 @@ mips64_fill_fpregset (const struct regcache *regcache, LONGEST val; regcache_raw_collect (regcache, regno, buf); - val = extract_signed_integer (buf, register_size (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) { @@ -603,7 +614,8 @@ 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); + 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); @@ -621,7 +633,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) 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; @@ -629,7 +641,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) 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 */ @@ -643,12 +655,12 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) 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 */ @@ -666,13 +678,13 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name) } /* 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; @@ -688,8 +700,8 @@ mips_linux_in_dynsym_resolve_code (CORE_ADDR pc) 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. */ @@ -701,9 +713,9 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) 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 @@ -712,12 +724,12 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) 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); @@ -785,7 +797,7 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { 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; }; @@ -815,7 +827,7 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { 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; }; @@ -830,7 +842,6 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { }; */ /* *INDENT-ON* */ -#define SIGFRAME_CODE_OFFSET (4 * 4) #define SIGFRAME_SIGCONTEXT_OFFSET (6 * 4) #define RTSIGFRAME_SIGINFO_SIZE 128 @@ -853,20 +864,21 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = { 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 (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); int ireg, reg_position; - CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET; + 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; + 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 @@ -935,9 +947,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, 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* */ @@ -945,7 +955,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, 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; }; @@ -958,7 +968,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, 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; @@ -979,15 +989,23 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, 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 @@ -1004,30 +1022,28 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, #define N64_SIGCONTEXT_REGS (0 * 8) #define N64_SIGCONTEXT_FPREGS (32 * 8) #define N64_SIGCONTEXT_HI (64 * 8) -#define N64_SIGCONTEXT_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 (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); int ireg, reg_position; - CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET; + 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; + 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, @@ -1063,17 +1079,9 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self, trad_frame_set_reg_addr (this_cache, regs->lo + gdbarch_num_regs (gdbarch), sigcontext_base + N64_SIGCONTEXT_LO); - trad_frame_set_reg_addr (this_cache, - regs->cause + gdbarch_num_regs (gdbarch), - sigcontext_base + N64_SIGCONTEXT_CAUSE); - trad_frame_set_reg_addr (this_cache, - regs->badvaddr + gdbarch_num_regs (gdbarch), - 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)); + trad_frame_set_id (this_cache, frame_id_build (frame_sp, func)); } static void @@ -1102,6 +1110,26 @@ mips_linux_restart_reg_p (struct gdbarch *gdbarch) 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 @@ -1149,11 +1177,9 @@ mips_linux_init_abi (struct gdbarch_info info, 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); @@ -1177,6 +1203,8 @@ mips_linux_init_abi (struct gdbarch_info info, 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; @@ -1196,6 +1224,9 @@ mips_linux_init_abi (struct gdbarch_info info, } } +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_mips_linux_tdep; + void _initialize_mips_linux_tdep (void) {