[Lldb-commits] [lldb] r306666 - [UnwindAssembly/x86] Add support for "lea imm(%ebp), %esp" pattern

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 29 05:40:13 PDT 2017


Author: labath
Date: Thu Jun 29 05:40:13 2017
New Revision: 306666

URL: http://llvm.org/viewvc/llvm-project?rev=306666&view=rev
Log:
[UnwindAssembly/x86] Add support for "lea imm(%ebp), %esp" pattern

Summary:
The instruction pattern:
and $-16, %esp
sub $imm, %esp
...
lea imm(%ebp), %esp

appears when the compiler is realigning the stack (for example in
main(), or almost everywhere with -mstackrealign switch). The "and"
instruction is very difficult to model, but that's not necessary, as
these frames are always %ebp-based (the compiler also needs a way to
restore the original %esp). Therefore the plans we were generating for
these function were almost correct already. The only place we were doing
it wrong were the last instructions of the epilogue (usually just
"ret"), where we had to revert to %esp-based unwinding, as the %ebp had
been popped already.

This was wrong because our "distance of esp from cfa" counter had picked
up the "sub" instruction (and incremented the counter) but it had not
seen that the register was reset by the "lea" instruction.

This patch fixes that shortcoming, and adds a test for handling
functions like this.

I have not been able to tickle the compiler into producing a 64-bit
function with this pattern, but I don't see a reason why it couldn't
produce it, if it chose to, so I add a x86_64 test as well.

Reviewers: jasonmolenda, tberghammer

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D34750

Modified:
    lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
    lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
    lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp

Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp?rev=306666&r1=306665&r2=306666&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp Thu Jun 29 05:40:13 2017
@@ -452,6 +452,33 @@ bool x86AssemblyInspectionEngine::lea_rs
   return false;
 }
 
+// lea -0x28(%ebp), %esp
+// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
+bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+
+  // Check opcode
+  if (*p != 0x8d)
+    return false;
+  ++p;
+
+  // 8 bit displacement
+  if (*p == 0x65) {
+    amount = (int8_t)p[1];
+    return true;
+  }
+
+  // 32 bit displacement
+  if (*p == 0xa5) {
+    amount = (int32_t)extract_4(p + 1);
+    return true;
+  }
+
+  return false;
+}
+
 // popq %rbx
 // popl %ebx
 bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
@@ -843,6 +870,12 @@ bool x86AssemblyInspectionEngine::GetNon
         in_epilogue = true;
     }
 
+    else if (lea_rbp_rsp_pattern_p(stack_offset) &&
+             row->GetCFAValue().GetRegisterNumber() == m_lldb_fp_regnum) {
+      current_sp_bytes_offset_from_cfa =
+          row->GetCFAValue().GetOffset() - stack_offset;
+    }
+
     else if (ret_pattern_p() && prologue_completed_row.get()) {
       // Reinstate the saved prologue setup for any instructions
       // that come after the ret instruction

Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h?rev=306666&r1=306665&r2=306666&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h Thu Jun 29 05:40:13 2017
@@ -102,6 +102,7 @@ private:
   bool sub_rsp_pattern_p(int &amount);
   bool add_rsp_pattern_p(int &amount);
   bool lea_rsp_pattern_p(int &amount);
+  bool lea_rbp_rsp_pattern_p(int &amount);
   bool push_reg_p(int &regno);
   bool pop_reg_p(int &regno);
   bool pop_rbp_pattern_p();

Modified: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp?rev=306666&r1=306665&r2=306666&view=diff
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp (original)
+++ lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp Thu Jun 29 05:40:13 2017
@@ -18,6 +18,7 @@
 #include "lldb/Core/AddressRange.h"
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/StreamString.h"
 
 #include "llvm/Support/TargetSelect.h"
 
@@ -130,6 +131,15 @@ std::unique_ptr<x86AssemblyInspectionEng
   return engine;
 }
 
+namespace lldb_private {
+static std::ostream &operator<<(std::ostream &OS,
+                                const UnwindPlan::Row::CFAValue &CFA) {
+  StreamString S;
+  CFA.Dump(S, nullptr, nullptr);
+  return OS << S.GetData();
+}
+} // namespace lldb_private
+
 TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
   std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
 
@@ -2337,3 +2347,71 @@ TEST_F(Testx86AssemblyInspectionEngine,
 
   EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
 }
+
+TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x55,             // pushl %ebp
+      0x89, 0xe5,       // movl %esp, %ebp
+      0x53,             // pushl %ebx
+      0x83, 0xe4, 0xf0, // andl $-16, %esp
+      0x83, 0xec, 0x10, // subl $16, %esp
+      0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
+      0x5b,             // popl %ebx
+      0x5d,             // popl %ebp
+      0xc3,             // retl
+  };
+
+  AddressRange sample_range(0x1000, sizeof(data));
+  UnwindPlan plan(eRegisterKindLLDB);
+  ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
+                                                           sample_range, plan));
+
+  UnwindPlan::Row::CFAValue esp_plus_4, esp_plus_8, ebp_plus_8;
+  esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
+  esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
+  ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
+
+  EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
+  EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
+  for (size_t i = 3; i < sizeof(data) - 2; ++i)
+    EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
+        << "i: " << i;
+  EXPECT_EQ(esp_plus_4,
+            plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x55,                                     // pushq %rbp
+      0x48, 0x89, 0xe5,                         // movq %rsp, %rbp
+      0x53,                                     // pushl %rbx
+      0x48, 0x83, 0xe4, 0xf0,                   // andq $-16, %rsp
+      0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
+      0x48, 0x8d, 0x65, 0xf8,                   // leaq -8(%rbp), %rsp
+      0x5b,                                     // popq %rbx
+      0x5d,                                     // popq %rbp
+      0xc3,                                     // retq
+  };
+
+  AddressRange sample_range(0x1000, sizeof(data));
+  UnwindPlan plan(eRegisterKindLLDB);
+  ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
+                                                           sample_range, plan));
+
+  UnwindPlan::Row::CFAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
+  rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
+  rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
+  rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
+
+  EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
+  EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
+  for (size_t i = 4; i < sizeof(data) - 2; ++i)
+    EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
+        << "i: " << i;
+  EXPECT_EQ(rsp_plus_8,
+            plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
+}




More information about the lldb-commits mailing list