[Lldb-commits] [lldb] r157454 - /lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp

Jason Molenda jmolenda at apple.com
Thu May 24 18:54:06 PDT 2012


Author: jmolenda
Date: Thu May 24 20:54:06 2012
New Revision: 157454

URL: http://llvm.org/viewvc/llvm-project?rev=157454&view=rev
Log:
Add support for function with stack frame checks added by the compiler;
these functions will end in the sequence

  mov %rbp, %rsp
  ret
  call __stack_chk_fail

instead of the usual mov, ret.  The x86 assembly profiler only looked
for functions ending in 'ret' and added the Unwind row describing how to
set the CFA based on that -- the addition of the call insn (which is jumped
to earlier in the function body) threw off that inspection.

Resolves the need to "step" twice to get out of these functions when doing
source-level stepping.

<rdar://problem/11469705>


Modified:
    lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp

Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp?rev=157454&r1=157453&r2=157454&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp Thu May 24 20:54:06 2012
@@ -676,40 +676,69 @@
     }
     
     // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
-    // epilogue.  If this function is built -fomit-frame-pointer (so the CFA is defined in terms of the
-    // stack pointer) we'd need to profile every instruction which causes rsp to change to backtrace
-    // all the time.  But assuming the CFA is in terms of rbp most of the time, this one additional Row
-    // will be sufficient.
+    // epilogue.  We're looking for the sequence
 
-    if (m_func_bounds.GetByteSize() > 2)
+    //  [ 0x5d ] mov %rbp, %rsp
+    //  [ 0xc3 ] ret
+    //  [ 0xe8 xx xx xx xx ] call __stack_chk_fail  (this is sometimes the final insn in the function)
+
+    // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
+    // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
+
+    uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
+    Address end_of_fun(m_func_bounds.GetBaseAddress());
+    end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+    
+    if (m_func_bounds.GetByteSize() > 7)
     {
-        Address last_insn (m_func_bounds.GetBaseAddress());
-        last_insn.SetOffset (last_insn.GetOffset() + m_func_bounds.GetByteSize() - 1);
-        uint8_t bytebuf[1];
-        if (target->ReadMemory (last_insn, prefer_file_cache, bytebuf, 1, error) != -1)
+        uint8_t bytebuf[7];
+        Address last_seven_bytes(end_of_fun);
+        last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
+        if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, error) != -1)
         {
-            if (bytebuf[0] == 0xc3)   // ret aka retq
+            if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3)  // mov, ret
             {
-                // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
-                UnwindPlan::Row epi_row;
-                UnwindPlan::Row::RegisterLocation epi_regloc;
-
-                // When the ret instruction is about to be executed, here's our state
-                epi_row.SetOffset (m_func_bounds.GetByteSize() - 1);
-                epi_row.SetCFARegister (m_lldb_sp_regnum);
-                epi_row.SetCFAOffset (m_wordsize);
-               
-                // caller's stack pointer value before the call insn is the CFA address
-                epi_regloc.SetIsCFAPlusOffset (0);
-                epi_row.SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
-
-                // saved instruction pointer can be found at CFA - wordsize
-                epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
-                epi_row.SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
-
-                unwind_plan.AppendRow (epi_row);
+                ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+            }
+            else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call
+            {
+                ret_insn_offset = m_func_bounds.GetByteSize() - 6;
             }
         }
+    } else if (m_func_bounds.GetByteSize() > 2)
+    {
+        uint8_t bytebuf[2];
+        Address last_two_bytes(end_of_fun);
+        last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
+        if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, error) != -1)
+        {
+            if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret
+            {
+                ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+            }
+        }
+    }
+
+    if (ret_insn_offset != LLDB_INVALID_ADDRESS)
+    {
+        // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
+        UnwindPlan::Row epi_row;
+        UnwindPlan::Row::RegisterLocation epi_regloc;
+
+        // When the ret instruction is about to be executed, here's our state
+        epi_row.SetOffset (ret_insn_offset);
+        epi_row.SetCFARegister (m_lldb_sp_regnum);
+        epi_row.SetCFAOffset (m_wordsize);
+       
+        // caller's stack pointer value before the call insn is the CFA address
+        epi_regloc.SetIsCFAPlusOffset (0);
+        epi_row.SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
+
+        // saved instruction pointer can be found at CFA - wordsize
+        epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
+        epi_row.SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+
+        unwind_plan.AppendRow (epi_row);
     }
     
     unwind_plan.SetSourceName ("assembly insn profiling");





More information about the lldb-commits mailing list