[Lldb-commits] [lldb] r283186 - Finish adding the individual instruction tests to the x86 unwinder

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 3 22:10:06 PDT 2016


Author: jmolenda
Date: Tue Oct  4 00:10:06 2016
New Revision: 283186

URL: http://llvm.org/viewvc/llvm-project?rev=283186&view=rev
Log:
Finish adding the individual instruction tests to the x86 unwinder
unittests.  If I have time, I'd like to see if I can write some
tests of the eh_frame augmentation which is a wholly separate code
path (it seems like maybe it should be rolled into the main instruction
scanning codepath, to be honest, and operate on the generated
UnwindPlan instead of bothering with raw instructions at all).  

Outside the eh_frame augmentation, I'm comfortable that this unwind
generator is being tested well now.


Modified:
    lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
    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/Platform/MacOSX/PlatformRemoteiOS.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp?rev=283186&r1=283185&r2=283186&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp Tue Oct  4 00:10:06 2016
@@ -748,6 +748,10 @@ Error PlatformRemoteiOS::GetSharedModule
 
     size_t num_module_search_paths = module_search_paths_ptr->GetSize();
     for (size_t i = 0; i < num_module_search_paths; ++i) {
+      Log *log_verbose = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
+                                                    LIBLLDB_LOG_VERBOSE);
+      if (log_verbose)
+          log_verbose->Printf ("PlatformRemoteiOS::GetSharedModule searching for binary in search-path %s", module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str());
       // Create a new FileSpec with this module_search_paths_ptr
       // plus just the filename ("UIFoundation"), then the parent
       // dir plus filename ("UIFoundation.framework/UIFoundation")

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=283186&r1=283185&r2=283186&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp Tue Oct  4 00:10:06 2016
@@ -346,6 +346,20 @@ bool x86AssemblyInspectionEngine::push_e
   return false;
 }
 
+// instructions only valid in 32-bit mode:
+// 0x0e - push cs
+// 0x16 - push ss
+// 0x1e - push ds
+// 0x06 - push es
+bool x86AssemblyInspectionEngine::push_misc_reg_p() {
+  uint8_t p = *m_cur_insn;
+  if (m_wordsize == 4) {
+    if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06)
+      return true;
+  }
+  return false;
+}
+
 // pushq %rbx
 // pushl %ebx
 bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {
@@ -462,6 +476,19 @@ bool x86AssemblyInspectionEngine::pop_rb
   return (*p == 0x5d);
 }
 
+// instructions valid only in 32-bit mode:
+// 0x1f - pop ds
+// 0x07 - pop es
+// 0x17 - pop ss
+bool x86AssemblyInspectionEngine::pop_misc_reg_p() {
+  uint8_t p = *m_cur_insn;
+  if (m_wordsize == 4) {
+    if (p == 0x1f || p == 0x07 || p == 0x17)
+      return true;
+  }
+  return false;
+}
+
 // leave [0xc9]
 bool x86AssemblyInspectionEngine::leave_pattern_p() {
   uint8_t *p = m_cur_insn;
@@ -725,6 +752,15 @@ bool x86AssemblyInspectionEngine::GetNon
       }
     }
 
+    else if (pop_misc_reg_p()) {
+      current_sp_bytes_offset_from_cfa -= m_wordsize;
+      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
+        row->GetCFAValue().SetIsRegisterPlusOffset(
+            m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa);
+        row_updated = true;
+      }
+    }
+
     // The LEAVE instruction moves the value from rbp into rsp and pops
     // a value off the stack into rbp (restoring the caller's rbp value).
     // It is the opposite of ENTER, or 'push rbp, mov rsp rbp'.
@@ -788,7 +824,8 @@ bool x86AssemblyInspectionEngine::GetNon
       in_epilogue = true;
     }
 
-    else if (push_extended_pattern_p() || push_imm_pattern_p()) {
+    else if (push_extended_pattern_p() || push_imm_pattern_p() ||
+             push_misc_reg_p()) {
       current_sp_bytes_offset_from_cfa += m_wordsize;
       if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
         row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
@@ -1026,6 +1063,16 @@ bool x86AssemblyInspectionEngine::Augmen
         continue;
       }
 
+      if (pop_misc_reg_p()) {
+        row->SetOffset(offset);
+        row->GetCFAValue().IncOffset(-m_wordsize);
+
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+        unwind_plan.InsertRow(new_row);
+        unwind_plan_updated = true;
+        continue;
+      }
+
       // push imm
       if (push_imm_pattern_p()) {
         row->SetOffset(offset);
@@ -1037,7 +1084,7 @@ bool x86AssemblyInspectionEngine::Augmen
       }
 
       // push extended
-      if (push_extended_pattern_p()) {
+      if (push_extended_pattern_p() || push_misc_reg_p()) {
         row->SetOffset(offset);
         row->GetCFAValue().IncOffset(m_wordsize);
         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));

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=283186&r1=283185&r2=283186&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h Tue Oct  4 00:10:06 2016
@@ -97,6 +97,7 @@ private:
   bool push_0_pattern_p();
   bool push_imm_pattern_p();
   bool push_extended_pattern_p();
+  bool push_misc_reg_p();
   bool mov_rsp_rbp_pattern_p();
   bool sub_rsp_pattern_p(int &amount);
   bool add_rsp_pattern_p(int &amount);
@@ -104,6 +105,7 @@ private:
   bool push_reg_p(int &regno);
   bool pop_reg_p(int &regno);
   bool pop_rbp_pattern_p();
+  bool pop_misc_reg_p();
   bool leave_pattern_p();
   bool call_next_insn_pattern_p();
   bool mov_reg_to_local_stack_frame_p(int &regno, int &rbp_offset);

Modified: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp?rev=283186&r1=283185&r2=283186&view=diff
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp (original)
+++ lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp Tue Oct  4 00:10:06 2016
@@ -1002,6 +1002,7 @@ TEST_F(Testx86AssemblyInspectionEngine,
 
   uint8_t data[] = {
       0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
+      0x6a, 0x7d,                   // pushl $0x7d
       0x90                          // nop
   };
 
@@ -1013,22 +1014,32 @@ TEST_F(Testx86AssemblyInspectionEngine,
       data, sizeof(data), sample_range, unwind_plan));
 
   row_sp = unwind_plan.GetRowForFunctionOffset(5);
-
   EXPECT_EQ(5, row_sp->GetOffset());
   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
   EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
 
+  row_sp = unwind_plan.GetRowForFunctionOffset(7);
+  EXPECT_EQ(7, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
+
   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
   EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
       data, sizeof(data), sample_range, unwind_plan));
 
   row_sp = unwind_plan.GetRowForFunctionOffset(5);
-
   EXPECT_EQ(5, row_sp->GetOffset());
   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(7);
+  EXPECT_EQ(7, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
 }
 
 // We treat 'pushq $0' / 'pushl $0' specially - this shows up
@@ -1070,8 +1081,10 @@ TEST_F(Testx86AssemblyInspectionEngine,
   UnwindPlan::RowSP row_sp;
 
   uint8_t data[] = {
-      0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
-      0x90                    // nop
+      0xff, 0x74, 0x24, 0x20,             // pushl 0x20(%esp)
+      0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl  0xf001ce(%esi)
+      0xff, 0x30,                         // pushl  (%eax)
+      0x90                                // nop
   };
 
   AddressRange sample_range(0x1000, sizeof(data));
@@ -1093,11 +1106,22 @@ TEST_F(Testx86AssemblyInspectionEngine,
       data, sizeof(data), sample_range, unwind_plan));
 
   row_sp = unwind_plan.GetRowForFunctionOffset(4);
-
   EXPECT_EQ(4, row_sp->GetOffset());
   EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
   EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(10);
+  EXPECT_EQ(10, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(12);
+  EXPECT_EQ(12, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
 }
 
 TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
@@ -1240,6 +1264,205 @@ TEST_F(Testx86AssemblyInspectionEngine,
   EXPECT_EQ(-16, regloc.GetOffset());
 }
 
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x50, // pushl %eax
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
+}
+
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x51, // pushl %ecx
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
+}
+
+// The ABI is hardcoded in x86AssemblyInspectionEngine such that
+// eax, ecx, edx are all considered volatile and push/pops of them are
+// not tracked (except to keep track of stack pointer movement)
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x52, // pushl %edx
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x53, // pushl %ebx
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x55, // pushl %ebp
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x56, // pushl %esi
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-8, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x57, // pushl %edi
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(1);
+  EXPECT_EQ(1, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-8, regloc.GetOffset());
+}
+
 TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
   UnwindPlan::Row::RegisterLocation regloc;
   UnwindPlan::RowSP row_sp;
@@ -1440,7 +1663,7 @@ TEST_F(Testx86AssemblyInspectionEngine,
   std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
 
   uint8_t data1[] = {
-      0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %esp
+      0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
       0x90                                // nop
   };
 
@@ -1471,3 +1694,444 @@ TEST_F(Testx86AssemblyInspectionEngine,
   EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
   EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
 }
+
+// FIXME add test for lea_rsp_pattern_p
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x53, // pushq %rbx
+      0x5b, // popq %rbx
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x55, // pushq %rbp
+      0x5d, // popq %rbp
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x41, 0x54, // pushq %r12
+      0x41, 0x5c, // popq %r12
+      0x90        // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(4);
+  EXPECT_EQ(4, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x41, 0x55, // pushq %r13
+      0x41, 0x5d, // popq %r13
+      0x90        // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(4);
+  EXPECT_EQ(4, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x41, 0x56, // pushq %r14
+      0x41, 0x5e, // popq %r14
+      0x90        // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(4);
+  EXPECT_EQ(4, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x41, 0x57, // pushq %r15
+      0x41, 0x5f, // popq %r15
+      0x90        // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(4);
+  EXPECT_EQ(4, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x53, // pushl %ebx
+      0x5b, // popl %ebx
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x55, // pushl %ebp
+      0x5d, // popl %ebp
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x56, // pushl %esi
+      0x5e, // popl %esi
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x57, // pushl %edi
+      0x5f, // popl %edi
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
+}
+
+// We don't track these registers, but make sure the CFA address is updated
+// if we're defining the CFA in term of esp.
+TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x0e, // push cs
+      0x16, // push ss
+      0x1e, // push ds
+      0x06, // push es
+
+      0x07, // pop es
+      0x1f, // pop ds
+      0x17, // pop ss
+
+      0x90 // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(4);
+  EXPECT_EQ(4, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(7);
+  EXPECT_EQ(7, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x55, // push %rbp/ebp
+      0xc9, // leave
+      0x90  // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(2);
+  EXPECT_EQ(2, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+// In i386, which lacks pc-relative addressing, a common code sequence
+// is to call the next instruction (i.e. call imm32, value of 0) which
+// pushes the addr of the next insn on the stack, and then pop that value
+// into a register (the "pic base" register).
+TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
+      0x90                          // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(5);
+  EXPECT_EQ(5, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+  EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+  uint8_t data[] = {
+      0x55,                                     // pushq %rbp
+      0x48, 0x89, 0xe5,                         // movq %rsp, %rbp
+      0x4c, 0x89, 0x75, 0xc0,                   // movq   %r14, -0x40(%rbp)
+      0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq   %r15, -0x5d8(%rbp)
+      0x48, 0x89, 0x5d, 0xb8,                   // movq %rbx, -0x48(%rbp)
+      0x90                                      // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(19);
+  EXPECT_EQ(19, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-80, regloc.GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-1512, regloc.GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-88, regloc.GetOffset());
+}
+
+TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
+  UnwindPlan::Row::RegisterLocation regloc;
+  UnwindPlan::RowSP row_sp;
+  AddressRange sample_range;
+  UnwindPlan unwind_plan(eRegisterKindLLDB);
+  std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x55,                               // pushq %ebp
+      0x89, 0xe5,                         // movq %esp, %ebp
+      0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
+      0x89, 0x75, 0xe0,                   // movl %esi, -0x20(%ebp)
+      0x90                                      // nop
+  };
+
+  sample_range = AddressRange(0x1000, sizeof(data));
+
+  EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+      data, sizeof(data), sample_range, unwind_plan));
+
+  row_sp = unwind_plan.GetRowForFunctionOffset(12);
+  EXPECT_EQ(12, row_sp->GetOffset());
+  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+  EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-344, regloc.GetOffset());
+
+  EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
+  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
+  EXPECT_EQ(-40, regloc.GetOffset());
+}




More information about the lldb-commits mailing list