Imported Upstream version 1.2
[platform/upstream/libunwind.git] / src / x86_64 / Gstep.c
index 9fa0967..84b3728 100644 (file)
@@ -1,6 +1,6 @@
 /* libunwind - a platform-independent unwind library
    Copyright (C) 2002-2004 Hewlett-Packard Co
-       Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
    Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
 
@@ -45,8 +45,8 @@ is_plt_entry (struct dwarf_cursor *c)
     return 0;
 
   ret = (((w0 & 0xffff) == 0x25ff)
-        && (((w0 >> 48) & 0xff) == 0x68)
-        && (((w1 >> 24) & 0xff) == 0xe9));
+         && (((w0 >> 48) & 0xff) == 0x68)
+         && (((w1 >> 24) & 0xff) == 0xe9));
 
   Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
   return ret;
@@ -64,7 +64,7 @@ unw_step (unw_cursor_t *cursor)
 #endif
 
   Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
-        c, c->dwarf.ip, c->dwarf.cfa);
+         c, c->dwarf.ip, c->dwarf.cfa);
 
   /* Try DWARF-based unwinding... */
   c->sigcontext_format = X86_64_SCF_NONE;
@@ -83,26 +83,27 @@ unw_step (unw_cursor_t *cursor)
   if (likely (ret >= 0))
     {
       /* x86_64 ABI specifies that end of call-chain is marked with a
-        NULL RBP.  */
-      if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
-       {
-         c->dwarf.ip = 0;
-         ret = 0;
-       }
+         NULL RBP or undefined return address  */
+        if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])
+            || DWARF_IS_NULL_LOC(c->dwarf.loc[c->dwarf.ret_addr_column]))
+          {
+            c->dwarf.ip = 0;
+            ret = 0;
+          }
     }
   else
     {
       /* DWARF failed.  There isn't much of a usable frame-chain on x86-64,
-        but we do need to handle two special-cases:
+         but we do need to handle two special-cases:
 
-         (i) signal trampoline: Old kernels and older libcs don't
-             export the vDSO needed to get proper unwind info for the
-             trampoline.  Recognize that case by looking at the code
-             and filling in things by hand.
+          (i) signal trampoline: Old kernels and older libcs don't
+              export the vDSO needed to get proper unwind info for the
+              trampoline.  Recognize that case by looking at the code
+              and filling in things by hand.
 
-         (ii) PLT (shared-library) call-stubs: PLT stubs are invoked
-             via CALLQ.  Try this for all non-signal trampoline
-             code.  */
+          (ii) PLT (shared-library) call-stubs: PLT stubs are invoked
+              via CALLQ.  Try this for all non-signal trampoline
+              code.  */
 
       unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
       struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
@@ -114,114 +115,115 @@ unw_step (unw_cursor_t *cursor)
       Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
 
       if (unw_is_signal_frame (cursor))
-       {
+        {
           ret = unw_handle_signal_frame(cursor);
-         if (ret < 0)
-           {
-             Debug (2, "returning 0\n");
-             return 0;
-           }
-       }
+          if (ret < 0)
+            {
+              Debug (2, "returning 0\n");
+              return 0;
+            }
+        }
       else if (is_plt_entry (&c->dwarf))
-       {
+        {
           /* Like regular frame, CFA = RSP+8, RA = [CFA-8], no regs saved. */
-         Debug (2, "found plt entry\n");
+          Debug (2, "found plt entry\n");
           c->frame_info.cfa_reg_offset = 8;
           c->frame_info.cfa_reg_rsp = -1;
           c->frame_info.frame_type = UNW_X86_64_FRAME_STANDARD;
           c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
           c->dwarf.cfa += 8;
-       }
+        }
       else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
         {
-         for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
-           c->dwarf.loc[i] = DWARF_NULL_LOC;
-       }
+          for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+            c->dwarf.loc[i] = DWARF_NULL_LOC;
+        }
       else
-       {
-         unw_word_t rbp;
-
-         ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
-         if (ret < 0)
-           {
-             Debug (2, "returning %d [RBP=0x%lx]\n", ret,
-                    DWARF_GET_LOC (c->dwarf.loc[RBP]));
-             return ret;
-           }
-
-         if (!rbp)
-           {
-             /* Looks like we may have reached the end of the call-chain.  */
-             rbp_loc = DWARF_NULL_LOC;
-             rsp_loc = DWARF_NULL_LOC;
-             rip_loc = DWARF_NULL_LOC;
-           }
-         else
-           {
-             unw_word_t rbp1 = 0;
-             rbp_loc = DWARF_LOC(rbp, 0);
-             rsp_loc = DWARF_NULL_LOC;
-             rip_loc = DWARF_LOC (rbp + 8, 0);
-             ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
-             Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
-                    (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
-                    rbp, c->dwarf.cfa, rbp1);
-
-             /* Heuristic to determine incorrect guess.  For RBP to be a
-                valid frame it needs to be above current CFA, but don't
-                let it go more than a little.  Note that we can't deduce
-                anything about new RBP (rbp1) since it may not be a frame
-                pointer in the frame above.  Just check we get the value. */
+        {
+          unw_word_t rbp;
+
+          ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
+          if (ret < 0)
+            {
+              Debug (2, "returning %d [RBP=0x%lx]\n", ret,
+                     DWARF_GET_LOC (c->dwarf.loc[RBP]));
+              return ret;
+            }
+
+          if (!rbp)
+            {
+              /* Looks like we may have reached the end of the call-chain.  */
+              rbp_loc = DWARF_NULL_LOC;
+              rsp_loc = DWARF_NULL_LOC;
+              rip_loc = DWARF_NULL_LOC;
+            }
+          else
+            {
+              unw_word_t rbp1 = 0;
+              rbp_loc = DWARF_LOC(rbp, 0);
+              rsp_loc = DWARF_NULL_LOC;
+              rip_loc = DWARF_LOC (rbp + 8, 0);
+              ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
+              Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n",
+                     (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+                     rbp, c->dwarf.cfa, rbp1);
+
+              /* Heuristic to determine incorrect guess.  For RBP to be a
+                 valid frame it needs to be above current CFA, but don't
+                 let it go more than a little.  Note that we can't deduce
+                 anything about new RBP (rbp1) since it may not be a frame
+                 pointer in the frame above.  Just check we get the value. */
               if (ret < 0
-                 || rbp <= c->dwarf.cfa
-                 || (rbp - c->dwarf.cfa) > 0x4000)
-               {
+                  || rbp < c->dwarf.cfa
+                  || (rbp - c->dwarf.cfa) > 0x4000)
+                {
                   rip_loc = DWARF_NULL_LOC;
                   rbp_loc = DWARF_NULL_LOC;
-               }
+                }
 
               c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
               c->frame_info.cfa_reg_rsp = 0;
               c->frame_info.cfa_reg_offset = 16;
               c->frame_info.rbp_cfa_offset = -16;
-             c->dwarf.cfa += 16;
-           }
+              c->dwarf.cfa += 16;
+            }
 
-         /* Mark all registers unsaved */
-         for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
-           c->dwarf.loc[i] = DWARF_NULL_LOC;
+          /* Mark all registers unsaved */
+          for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+            c->dwarf.loc[i] = DWARF_NULL_LOC;
 
           c->dwarf.loc[RBP] = rbp_loc;
           c->dwarf.loc[RSP] = rsp_loc;
           c->dwarf.loc[RIP] = rip_loc;
-       }
+          c->dwarf.use_prev_instr = 1;
+        }
 
       c->dwarf.ret_addr_column = RIP;
 
       if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
         {
-         ret = 0;
-         Debug (2, "NULL %%rbp loc, returning %d\n", ret);
-         return ret;
+          ret = 0;
+          Debug (2, "NULL %%rbp loc, returning %d\n", ret);
+          return ret;
         }
       if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP]))
-       {
-         ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
-         Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
-                    (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
-                    (unsigned long long) c->dwarf.ip);
-         if (ret < 0)
-           {
-             Debug (2, "returning %d\n", ret);
-             return ret;
-           }
-         ret = 1;
-       }
+        {
+          ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
+          Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
+                     (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
+                     (unsigned long long) c->dwarf.ip);
+          if (ret < 0)
+            {
+              Debug (2, "returning %d\n", ret);
+              return ret;
+            }
+          ret = 1;
+        }
       else
-       c->dwarf.ip = 0;
+        c->dwarf.ip = 0;
 
       if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa)
-       return -UNW_EBADFRAME;
+        return -UNW_EBADFRAME;
     }
   Debug (2, "returning %d\n", ret);
   return ret;