diff options
Diffstat (limited to 'lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp')
-rw-r--r-- | lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp | 122 |
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()); + + +} |