summaryrefslogtreecommitdiffstats
path: root/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp')
-rw-r--r--lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
index ccf065ca4b7..f8308c30465 100644
--- a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -2723,3 +2723,125 @@ TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
}
+
+
+// Test mid-function epilogues - the unwind state post-prologue
+// should be re-instated.
+
+TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
+ AddressRange sample_range;
+ UnwindPlan unwind_plan(eRegisterKindLLDB);
+ std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
+ std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
+
+ uint8_t data[] = {
+ 0x55, // <+0>: pushq %rbp
+ 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp
+ 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
+ 0x90, // <+8>: nop // prologue set up
+
+ 0x74, 0x7, // <+9>: je 7 <+18>
+ 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
+ 0x5d, // <+15>: popq %rbp
+ 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed
+
+ 0x90, // <+18>: nop // prologue setup back
+
+ 0x74, 0x7, // <+19>: je 6 <+27>
+ 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
+ 0x5d, // <+25>: popq %rbp
+ 0xc3, // <+26>: retq // epilogue completed
+
+ 0x90, // <+27>: nop // prologue setup back
+
+ 0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
+ 0x5d, // <+32>: popq %rbp
+ 0xc3, // <+33>: retq // epilogue completed
+
+ };
+
+ sample_range = AddressRange(0x1000, sizeof(data));
+
+ int wordsize = 4;
+ EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Check that we've unwound the stack after the first mid-function epilogue
+ // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(16);
+ EXPECT_EQ(16ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
+
+ // Check that we've reinstated the stack frame setup
+ // unwind instructions after a jmpq *%eax
+ // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(18);
+ EXPECT_EQ(18ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
+
+ // Check that we've reinstated the stack frame setup
+ // unwind instructions after a mid-function retq
+ // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(27);
+ EXPECT_EQ(27ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
+
+ // After last instruction in the function, verify that
+ // the stack frame has been unwound
+ // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
+ row_sp = unwind_plan.GetRowForFunctionOffset(33);
+ EXPECT_EQ(33ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
+
+
+ unwind_plan.Clear();
+
+ wordsize = 8;
+ EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
+ data, sizeof(data), sample_range, unwind_plan));
+
+ // Check that we've unwound the stack after the first mid-function epilogue
+ // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(16);
+ EXPECT_EQ(16ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
+
+ // Check that we've reinstated the stack frame setup
+ // unwind instructions after a jmpq *%eax
+ // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
+ row_sp = unwind_plan.GetRowForFunctionOffset(18);
+ EXPECT_EQ(18ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
+
+ // Check that we've reinstated the stack frame setup
+ // unwind instructions after a mid-function retq
+ // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
+ row_sp = unwind_plan.GetRowForFunctionOffset(27);
+ EXPECT_EQ(27ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
+
+ // After last instruction in the function, verify that
+ // the stack frame has been unwound
+ // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
+ row_sp = unwind_plan.GetRowForFunctionOffset(33);
+ EXPECT_EQ(33ull, row_sp->GetOffset());
+ EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
+ EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
+ EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
+
+
+}
OpenPOWER on IntegriCloud