summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp4
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp51
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h2
-rw-r--r--lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp676
4 files changed, 725 insertions, 8 deletions
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
index 889c501a646..6abd6e93104 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp
@@ -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")
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 9131acaab5b..e731a5a02ab 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -346,6 +346,20 @@ bool x86AssemblyInspectionEngine::push_extended_pattern_p() {
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_rbp_pattern_p() {
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::GetNonCallSiteUnwindPlanFromAssembly(
}
}
+ 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::GetNonCallSiteUnwindPlanFromAssembly(
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::AugmentUnwindPlanFromCallSite(
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::AugmentUnwindPlanFromCallSite(
}
// 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));
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
index f6bf83dacb1..0294f5a0c28 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
@@ -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);
diff --git a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
index 2f610e98bfb..42fc4db2ade 100644
--- a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -1002,6 +1002,7 @@ TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
uint8_t data[] = {
0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
+ 0x6a, 0x7d, // pushl $0x7d
0x90 // nop
};
@@ -1013,22 +1014,32 @@ TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
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, TestPushExtended) {
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, TestPushExtended) {
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, TestPushRBX) {
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, TestAddESP) {
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, TestAddESP) {
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());
+}
OpenPOWER on IntegriCloud