From db5f024eccfb16178a57402ef3d9d50f5944df41 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 2 Oct 2008 15:48:06 +0000 Subject: * mips-linux-tdep.c (mips_linux_in_dynsym_resolve_code): Update comments. (mips_linux_skip_resolver): Also use glibc_skip_solib_resolver. (mips_linux_init_abi): Do not override skip_trampoline_code. * configure.tgt (mips*-*-linux*): Add glibc-tdep.o. * mips-tdep.c (mips32_scan_prologue): Stop scanning at branches. (mips_stub_frame_sniffer): Use the stub frame sniffer for PIC stubs. (mips_skip_mips16_trampoline_code): Rename from mips_skip_trampoline_code. (mips_skip_pic_trampoline_code, mips_skip_trampoline_code): New. * infrun.c (handle_inferior_event): Do not pass zero to in_solib_dynsym_resolve_code. --- gdb/ChangeLog | 15 ++++++++ gdb/configure.tgt | 2 +- gdb/infrun.c | 2 +- gdb/mips-linux-tdep.c | 12 +++---- gdb/mips-tdep.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 119 insertions(+), 9 deletions(-) (limited to 'gdb') diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bb0d830..c0f47c4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,18 @@ +2008-10-02 Daniel Jacobowitz + + * mips-linux-tdep.c (mips_linux_in_dynsym_resolve_code): Update + comments. + (mips_linux_skip_resolver): Also use glibc_skip_solib_resolver. + (mips_linux_init_abi): Do not override skip_trampoline_code. + * configure.tgt (mips*-*-linux*): Add glibc-tdep.o. + * mips-tdep.c (mips32_scan_prologue): Stop scanning at branches. + (mips_stub_frame_sniffer): Use the stub frame sniffer for PIC stubs. + (mips_skip_mips16_trampoline_code): Rename from + mips_skip_trampoline_code. + (mips_skip_pic_trampoline_code, mips_skip_trampoline_code): New. + * infrun.c (handle_inferior_event): Do not pass zero to + in_solib_dynsym_resolve_code. + 2008-10-02 Pierre Muller Pedro Alves diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 3b965fc..b4ce7ac 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -297,7 +297,7 @@ mips*-sgi-irix6*) ;; mips*-*-linux*) # Target: Linux/MIPS - gdb_target_obs="mips-tdep.o mips-linux-tdep.o \ + gdb_target_obs="mips-tdep.o mips-linux-tdep.o glibc-tdep.o \ corelow.o solib.o solib-svr4.o symfile-mem.o" gdb_sim=../sim/mips/libsim.a build_gdbserver=yes diff --git a/gdb/infrun.c b/gdb/infrun.c index 4b4df8f..abaceee 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3136,7 +3136,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); if (real_stop_pc != 0) ecs->stop_func_start = real_stop_pc; - if (in_solib_dynsym_resolve_code (ecs->stop_func_start)) + if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc)) { struct symtab_and_line sr_sal; init_sal (&sr_sal); diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 78f33a6..eb23228 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -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; @@ -666,13 +667,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 +689,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. */ @@ -703,7 +704,7 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc) return frame_pc_unwind (get_current_frame ()); - return 0; + return glibc_skip_solib_resolver (gdbarch, pc); } /* Signal trampoline support. There are four supported layouts for a @@ -1171,7 +1172,6 @@ mips_linux_init_abi (struct gdbarch_info info, 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); diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 3a3a78a..8304a02 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -1897,6 +1897,7 @@ mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc, CORE_ADDR end_prologue_addr = 0; int seen_sp_adjust = 0; int load_immediate_bytes = 0; + int in_delay_slot = 0; struct gdbarch *gdbarch = get_frame_arch (this_frame); int regsize_is_64_bits = (mips_abi_regsize (gdbarch) == 8); @@ -2054,7 +2055,18 @@ restart: instructions? */ if (end_prologue_addr == 0) end_prologue_addr = cur_pc; + + /* Check for branches and jumps. For now, only jump to + register are caught (i.e. returns). */ + if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8) + in_delay_slot = 1; } + + /* If the previous instruction was a jump, we must have reached + the end of the prologue by now. Stop scanning so that we do + not go past the function return. */ + if (in_delay_slot) + break; } if (this_cache != NULL) @@ -2256,6 +2268,7 @@ mips_stub_frame_sniffer (const struct frame_unwind *self, gdb_byte dummy[4]; struct obj_section *s; CORE_ADDR pc = get_frame_address_in_block (this_frame); + struct minimal_symbol *msym; /* Use the stub unwinder for unreadable code. */ if (target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0) @@ -2272,6 +2285,14 @@ mips_stub_frame_sniffer (const struct frame_unwind *self, ".MIPS.stubs") == 0) return 1; + /* Calling a PIC function from a non-PIC function passes through a + stub. The stub for foo is named ".pic.foo". */ + msym = lookup_minimal_symbol_by_pc (pc); + if (msym != NULL + && SYMBOL_LINKAGE_NAME (msym) != NULL + && strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) == 0) + return 1; + return 0; } @@ -5045,7 +5066,7 @@ mips_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) gory details. */ static CORE_ADDR -mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +mips_skip_mips16_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { char *name; CORE_ADDR start_addr; @@ -5124,6 +5145,80 @@ mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) return 0; /* not a stub */ } +/* If the current PC is the start of a non-PIC-to-PIC stub, return the + PC of the stub target. The stub just loads $t9 and jumps to it, + so that $t9 has the correct value at function entry. */ + +static CORE_ADDR +mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +{ + struct minimal_symbol *msym; + int i; + gdb_byte stub_code[16]; + int32_t stub_words[4]; + + /* The stub for foo is named ".pic.foo", and is either two + instructions inserted before foo or a three instruction sequence + which jumps to foo. */ + msym = lookup_minimal_symbol_by_pc (pc); + if (msym == NULL + || SYMBOL_VALUE_ADDRESS (msym) != pc + || SYMBOL_LINKAGE_NAME (msym) == NULL + || strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) != 0) + return 0; + + /* A two-instruction header. */ + if (MSYMBOL_SIZE (msym) == 8) + return pc + 8; + + /* A three-instruction (plus delay slot) trampoline. */ + if (MSYMBOL_SIZE (msym) == 16) + { + if (target_read_memory (pc, stub_code, 16) != 0) + return 0; + for (i = 0; i < 4; i++) + stub_words[i] = extract_unsigned_integer (stub_code + i * 4, 4); + + /* A stub contains these instructions: + lui t9, %hi(target) + j target + addiu t9, t9, %lo(target) + nop + + This works even for N64, since stubs are only generated with + -msym32. */ + if ((stub_words[0] & 0xffff0000U) == 0x3c190000 + && (stub_words[1] & 0xfc000000U) == 0x08000000 + && (stub_words[2] & 0xffff0000U) == 0x27390000 + && stub_words[3] == 0x00000000) + return (((stub_words[0] & 0x0000ffff) << 16) + + (stub_words[2] & 0x0000ffff)); + } + + /* Not a recognized stub. */ + return 0; +} + +static CORE_ADDR +mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +{ + CORE_ADDR target_pc; + + target_pc = mips_skip_mips16_trampoline_code (frame, pc); + if (target_pc) + return target_pc; + + target_pc = find_solib_trampoline_target (frame, pc); + if (target_pc) + return target_pc; + + target_pc = mips_skip_pic_trampoline_code (frame, pc); + if (target_pc) + return target_pc; + + return 0; +} + /* Convert a dbx stab register number (from `r' declaration) to a GDB [1 * gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM. */ -- cgit v1.1