PR gdb/2103
authorDaniel Jacobowitz <drow@false.org>
Fri, 7 Sep 2007 12:13:45 +0000 (12:13 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 7 Sep 2007 12:13:45 +0000 (12:13 +0000)
* arm-tdep.c (arm_in_call_stub): Delete.
(arm_skip_stub): Handle from_arm and from_thumb stubs.

gdb/ChangeLog
gdb/arm-tdep.c

index 83b7ec9ce762d9bda3bb43a704ea87441ba0b416..980c50e59c0ad427e4ec48042cb118bb78e2ce64 100644 (file)
@@ -1,3 +1,9 @@
+2007-09-07  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       PR gdb/2103
+       * arm-tdep.c (arm_in_call_stub): Delete.
+       (arm_skip_stub): Handle from_arm and from_thumb stubs.
+
 2007-09-06  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * ppc-sysv-tdep.c (do_ppc_sysv_return_value): Handle other integer
index 4ce7183f302c22edfebfe3ffcbb2b31749329da8..b4d221184acca8ef61e967d3991a09d0da5ba760 100644 (file)
@@ -2358,38 +2358,24 @@ arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
   return 1;
 }
 
-/* Return non-zero if the PC is inside a thumb call thunk.  */
-
-int
-arm_in_call_stub (CORE_ADDR pc, char *name)
-{
-  CORE_ADDR start_addr;
-
-  /* Find the starting address of the function containing the PC.  If
-     the caller didn't give us a name, look it up at the same time.  */
-  if (0 == find_pc_partial_function (pc, name ? NULL : &name, 
-                                    &start_addr, NULL))
-    return 0;
-
-  return strncmp (name, "_call_via_r", 11) == 0;
-}
-
-/* If PC is in a Thumb call or return stub, return the address of the
-   target PC, which is in a register.  The thunk functions are called
-   _called_via_xx, where x is the register name.  The possible names
-   are r0-r9, sl, fp, ip, sp, and lr.  */
+/* Recognize GCC and GNU ld's trampolines.  If we are in a trampoline,
+   return the target PC.  Otherwise return 0.  */
 
 CORE_ADDR
 arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
 {
   char *name;
+  int namelen;
   CORE_ADDR start_addr;
 
   /* Find the starting address and name of the function containing the PC.  */
   if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
     return 0;
 
-  /* Call thunks always start with "_call_via_".  */
+  /* If PC is in a Thumb call or return stub, return the address of the
+     target PC, which is in a register.  The thunk functions are called
+     _call_via_xx, where x is the register name.  The possible names
+     are r0-r9, sl, fp, ip, sp, and lr.  */
   if (strncmp (name, "_call_via_", 10) == 0)
     {
       /* Use the name suffix to determine which register contains the
@@ -2399,12 +2385,49 @@ arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
        "r8", "r9", "sl", "fp", "ip", "sp", "lr"
       };
       int regno;
+      int offset = strlen (name) - 2;
 
       for (regno = 0; regno <= 14; regno++)
-       if (strcmp (&name[10], table[regno]) == 0)
+       if (strcmp (&name[offset], table[regno]) == 0)
          return get_frame_register_unsigned (frame, regno);
     }
 
+  /* GNU ld generates __foo_from_arm or __foo_from_thumb for
+     non-interworking calls to foo.  We could decode the stubs
+     to find the target but it's easier to use the symbol table.  */
+  namelen = strlen (name);
+  if (name[0] == '_' && name[1] == '_'
+      && ((namelen > 2 + strlen ("_from_thumb")
+          && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
+                      strlen ("_from_thumb")) == 0)
+         || (namelen > 2 + strlen ("_from_arm")
+             && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
+                         strlen ("_from_arm")) == 0)))
+    {
+      char *target_name;
+      int target_len = namelen - 2;
+      struct minimal_symbol *minsym;
+      struct objfile *objfile;
+      struct obj_section *sec;
+
+      if (name[namelen - 1] == 'b')
+       target_len -= strlen ("_from_thumb");
+      else
+       target_len -= strlen ("_from_arm");
+
+      target_name = alloca (target_len + 1);
+      memcpy (target_name, name + 2, target_len);
+      target_name[target_len] = '\0';
+
+      sec = find_pc_section (pc);
+      objfile = (sec == NULL) ? NULL : sec->objfile;
+      minsym = lookup_minimal_symbol (target_name, NULL, objfile);
+      if (minsym != NULL)
+       return SYMBOL_VALUE_ADDRESS (minsym);
+      else
+       return 0;
+    }
+
   return 0;                    /* not a stub */
 }