Hello,

The attached patch adds support for unwinding the vsyscall region and adds more generic support for frameless functions.

Regards,
Jonathan Byrd
Senior Application Developer
Allinea Software Ltd.
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c
index 84b3728..29bd56a 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
 #include "unwind_i.h"
 #include <signal.h>
+#include <asm/vsyscall.h>
 
 /* Recognise PLT entries such as:
      3bdf0: ff 25 e2 49 13 00 jmpq   *0x1349e2(%rip)
@@ -52,6 +53,18 @@ is_plt_entry (struct dwarf_cursor *c)
   return ret;
 }
 
+static int
+is_vsyscall (struct dwarf_cursor *c)
+{
+#if defined(VSYSCALL_START) && defined(VSYSCALL_END)
+    return c->ip >= VSYSCALL_START && c->ip < VSYSCALL_END;
+#else
+    /* Linux 3.16 removes `VSYSCALL_START` and `VSYSCALL_END`.  Assume
+     * that no-one is using vsyscall on newer systems. */
+    return 0;
+#endif
+}
+
 PROTECTED int
 unw_step (unw_cursor_t *cursor)
 {
@@ -106,7 +119,6 @@ unw_step (unw_cursor_t *cursor)
               code.  */
 
       unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
-      struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
 
       /* We could get here because of missing/bad unwind information.
          Validate all addresses before dereferencing. */
@@ -133,6 +145,40 @@ unw_step (unw_cursor_t *cursor)
           c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
           c->dwarf.cfa += 8;
         }
+      else if (is_vsyscall (&c->dwarf))
+	{
+	  int frameless;
+	  unw_word_t rbp;
+	  Debug (2, "in vsyscall region\n");
+	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
+	  frameless = (ret < 0) || (rbp != c->dwarf.cfa);
+	  Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) frameless = %d\n",
+		 (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+		 rbp, c->dwarf.cfa, frameless);
+	  if (frameless)
+	    {
+	      c->frame_info.cfa_reg_offset = 8;
+	      c->frame_info.cfa_reg_rsp = -1;
+	      c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+	      c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+	      c->dwarf.cfa += 8;
+	    }
+	  else
+	    {
+	     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;
+
+	     /* Mark all registers unsaved */
+	     for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+		c->dwarf.loc[i] = DWARF_NULL_LOC;
+	     c->dwarf.loc[RBP] = DWARF_LOC(rbp, 0);
+	     c->dwarf.loc[RSP] = DWARF_NULL_LOC;
+	     c->dwarf.loc[RIP] = DWARF_LOC (rbp + 8, 0);
+	   }
+	}
       else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
         {
           for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
@@ -140,62 +186,67 @@ unw_step (unw_cursor_t *cursor)
         }
       else
         {
+          int frameless;
           unw_word_t rbp;
 
           ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
-          if (ret < 0)
+          if (is_vsyscall (&c->dwarf))
             {
-              Debug (2, "returning %d [RBP=0x%lx]\n", ret,
-                     DWARF_GET_LOC (c->dwarf.loc[RBP]));
-              return ret;
-            }
-
+	      Debug (2, "in vsyscall region\n");
+	      /* The vsyscalls don't use the stack so we can use a stricter check.  */
+	      frameless = (ret < 0) || (rbp != c->dwarf.cfa);
+	    }
+	  else
+	    {
+            /* 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. */
+            frameless = (ret < 0) || (rbp < c->dwarf.cfa) || ((rbp - c->dwarf.cfa) > 0x4000);
+        }
           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;
+                /* Looks like we may have reached the end of the call-chain.  */
+                /* Mark all registers unsaved */
+                for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+                    c->dwarf.loc[i] = DWARF_NULL_LOC;
             }
+          else if (frameless)
+              {
+                  Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) (frameless)\n",
+                         (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+                         rbp, c->dwarf.cfa);
+
+                  c->frame_info.cfa_reg_offset = 8;
+                  c->frame_info.cfa_reg_rsp = -1;
+                  c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+                  c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+                  c->dwarf.cfa += 8;
+              }
           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)
-                {
-                  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;
-            }
-
-          /* 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;
+              {
+                  unw_word_t rbp1 = 0;
+                  struct dwarf_loc rbp_loc = DWARF_LOC(rbp, 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);
+
+                  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.use_prev_instr = 1;
+                  /* 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] = DWARF_NULL_LOC;
+                  c->dwarf.loc[RIP] = DWARF_LOC (rbp + 8, 0);
+              }
         }
 
       c->dwarf.ret_addr_column = RIP;
_______________________________________________
Libunwind-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/libunwind-devel

Reply via email to