mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 12:26:52 +08:00
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> llvm-svn: 282683
This commit is contained in:
@@ -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<x86AssemblyInspectionEngine> Geti386Inspector() {
|
||||
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, TestSimple64bitFrameFunction) {
|
||||
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, TestSimple32bitFrameFunction) {
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user