Author: jmolenda Date: Wed Sep 28 23:01:43 2016 New Revision: 282683 URL: http://llvm.org/viewvc/llvm-project?rev=282683&view=rev Log: Add a unit test for an x86_64 assembly inspection of a large stack frame with lots of spilled registers.
While writing the i386 version of this test, it looks like I found a bug in the 32-bit instruction profiler code. I may ned to fix the assembly inspection engine before I can finish writing that test, so I'm only committing the 64-bit one tonight. <rdar://problem/28509178> Modified: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp Modified: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp?rev=282683&r1=282682&r2=282683&view=diff ============================================================================== --- lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp (original) +++ lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp Wed Sep 28 23:01:43 2016 @@ -43,27 +43,28 @@ protected: // names should match the constants below. These will be the eRegisterKindLLDB // register numbers. -const char *x86_64_reg_names[] = {"rax", "rcx", "rdx", "rsp", "rbp", "rsi", - "rdi", "r8", "r9", "r10", "r11", "r12", - "r13", "r14", "r15", "rip"}; +const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp", + "rsi", "rdi", "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", "rip"}; enum x86_64_regs { k_rax = 0, - k_rcx = 1, - k_rdx = 2, - k_rsp = 3, - k_rbp = 4, - k_rsi = 5, - k_rdi = 6, - k_r8 = 7, - k_r9 = 8, - k_r10 = 9, - k_r11 = 10, - k_r12 = 11, - k_r13 = 12, - k_r14 = 13, - k_r15 = 14, - k_rip = 15 + k_rbx = 1, + k_rcx = 2, + k_rdx = 3, + k_rsp = 4, + k_rbp = 5, + k_rsi = 6, + k_rdi = 7, + k_r8 = 8, + k_r9 = 9, + k_r10 = 10, + k_r11 = 11, + k_r12 = 12, + k_r13 = 13, + k_r14 = 14, + k_r15 = 15, + k_rip = 16 }; // names should match the constants below. These will be the eRegisterKindLLDB @@ -133,6 +134,7 @@ std::unique_ptr<x86AssemblyInspectionEng TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) { std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); + // 'int main() { }' compiled for x86_64-apple-macosx with clang uint8_t data[] = { 0x55, // offset 0 -- pushq %rbp 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp @@ -208,6 +210,7 @@ TEST_F(Testx86AssemblyInspectionEngine, TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) { std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector(); + // 'int main() { }' compiled for i386-apple-macosx with clang uint8_t data[] = { 0x55, // offset 0 -- pushl %ebp 0x89, 0xe5, // offset 1 -- movl %esp, %ebp @@ -279,3 +282,159 @@ TEST_F(Testx86AssemblyInspectionEngine, EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); EXPECT_TRUE(regloc.GetOffset() == -4); } + +TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) { + std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector(); + + // this source file: + // + // #include <stdio.h> + // int main (int argc, char **argv) + // { + // + // const int arrsize = 60; + // int buf[arrsize * arrsize]; + // int accum = argc; + // for (int i = 0; i < arrsize; i++) + // for (int j = 0; j < arrsize; j++) + // { + // if (i > 0 && j > 0) + // { + // int n = buf[(i-1) * (j-1)] * 2; + // int m = buf[(i-1) * (j-1)] / 2; + // int j = buf[(i-1) * (j-1)] + 2; + // int k = buf[(i-1) * (j-1)] - 2; + // printf ("%d ", n + m + j + k); + // buf[(i-1) * (j-1)] += n - m + j - k; + // } + // buf[i*j] = accum++; + // } + // + // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize * + // arrsize) - 3]); + // } + // + // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx + + uint8_t data[] = { + 0x55, // offset 0 -- pushq %rbp + 0x41, 0x57, // offset 1 -- pushq %r15 + 0x41, 0x56, // offset 3 -- pushq %r14 + 0x41, 0x55, // offset 5 -- pushq %r13 + 0x41, 0x54, // offset 7 -- pushq %r12 + 0x53, // offset 9 -- pushq %rbx + 0x48, 0x81, 0xec, 0x68, 0x38, 0x00, + 0x00, // offset 10 -- subq $0x3868, %rsp + + // .... + + 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00, + 0x00, // offset 17 -- addq $0x3868, %rsp + 0x5b, // offset 24 -- popq %rbx + 0x41, 0x5c, // offset 25 -- popq %r12 + 0x41, 0x5d, // offset 27 -- popq %r13 + 0x41, 0x5e, // offset 29 -- popq %r14 + 0x41, 0x5f, // offset 31 -- popq %r15 + 0x5d, // offset 33 -- popq %rbp + 0xc3, // offset 34 -- retq + 0xe8, 0x00, 0x00, 0x00, 0x00 // offset 35 -- callq whatever + }; + + AddressRange sample_range(0x1000, sizeof(data)); + + UnwindPlan unwind_plan(eRegisterKindLLDB); + EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( + data, sizeof(data), sample_range, unwind_plan)); + + // Unwind rules should look like + // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] + // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] + // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8] + // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24] + // rip=[CFA-8 + // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32] + // r15=[CFA-24] rip=[CFA-8] + // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40] + // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] + // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] + // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + + // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] + // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40] + // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32] + // r15=[CFA-24] rip=[CFA-8] + // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24] + // rip=[CFA-8] + // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8] + // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8] + // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] + + UnwindPlan::Row::RegisterLocation regloc; + + // grab the Row for when the prologue has finished executing: + // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] + // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8] + + UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17); + + EXPECT_TRUE(row_sp->GetOffset() == 17); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_TRUE(row_sp->GetCFAValue().GetOffset() == 14496); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -8); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -16); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -24); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -32); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -40); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -48); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -56); + + // grab the Row for when the epiloge has finished executing: + // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8] + + row_sp = unwind_plan.GetRowForFunctionOffset(34); + + EXPECT_TRUE(row_sp->GetOffset() == 34); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_TRUE(row_sp->GetCFAValue().GetOffset() == 8); + + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_TRUE(regloc.GetOffset() == -8); + + // these could be set to IsSame and be valid -- meaning that the + // register value is the same as the caller's -- but I'd rather + // they not be mentioned at all. + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc) == false); + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc) == false); + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc) == false); + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc) == false); + EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc) == false); + EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc) == false); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits