* mips-linux-tdep.c (mips_linux_in_dynsym_resolve_code): Update
authorDaniel Jacobowitz <drow@false.org>
Thu, 2 Oct 2008 15:48:06 +0000 (15:48 +0000)
committerDaniel Jacobowitz <drow@false.org>
Thu, 2 Oct 2008 15:48:06 +0000 (15:48 +0000)
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
gdb/configure.tgt
gdb/infrun.c
gdb/mips-linux-tdep.c
gdb/mips-tdep.c

index bb0d830c1df0294e92f8f2d0639b38f427d496d4..c0f47c408f4408ca16f38414521988d3b23d758c 100644 (file)
@@ -1,3 +1,18 @@
+2008-10-02  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * 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  <muller@ics.u-strasbg.fr>
            Pedro Alves  <pedro@codesourcery.com>
 
index 3b965fc79d49bcb2d3e0eff3f4b3e68c6c9d4ef2..b4ce7acc89c8cad94412693da45553f500d48f5f 100644 (file)
@@ -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
index 4b4df8fabafa0aa0ac89db88bf60f8604a3e84a5..abaceeead3c988524e0631566d349288d476f832 100644 (file)
@@ -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);
index 78f33a6653681586ac6d816e52e192ed72db9ef5..eb232289d6ff34ed913cfe2b117dc8e2b84258f3 100644 (file)
@@ -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);
index 3a3a78ace597b8e2e259fc22fe96a16931be958e..8304a02e27bc064b0488da09afcf8d44facc9ecc 100644 (file)
@@ -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.  */