Add unit tests for specific instruction patterns that the x86

assembly inspection class is designed to detect.  This is only about
half of the instructions that it needs to recognize - I'll complete
this in a separate checkin.

The larger full-function style test cases I'd checked in previously
covered nearly all of these already, but I wanted simpler test cases
too, so if they fail in the future, it will be easier to spot the
issue.

llvm-svn: 283010
This commit is contained in:
Jason Molenda 2016-10-01 04:50:25 +00:00
parent 29baf9c0e1
commit 56f0497bb8
1 changed files with 519 additions and 0 deletions

View File

@ -952,3 +952,522 @@ TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x55, // pushq $rbp
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->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_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
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_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->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(16, 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());
}
// We treat 'pushq $0' / 'pushl $0' specially - this shows up
// in the first function called in a new thread and it needs to
// put a 0 as the saved pc. We pretend it didn't change the CFA.
TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x6a, 0x00, // pushq $0
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data, sizeof(data), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(2);
// We're verifying that no row was created for the 'pushq $0'
EXPECT_EQ(0, row_sp->GetOffset());
std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
data, sizeof(data), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(2);
// We're verifying that no row was created for the 'pushq $0'
EXPECT_EQ(0, row_sp->GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->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(16, 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(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());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x41, 0x57, // pushq %r15
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
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(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x41, 0x56, // pushq %r14
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
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(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x41, 0x55, // pushq %r13
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
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(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x41, 0x54, // pushq %r13
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
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(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data[] = {
0x53, // pushq %rbx
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->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_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
uint8_t data64_1[] = {
0x48, 0x8b, 0xec, // movq %rsp, %rbp
0x90 // nop
};
AddressRange sample_range(0x1000, sizeof(data64_1));
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data64_1, sizeof(data64_1), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(3);
EXPECT_EQ(3, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
uint8_t data64_2[] = {
0x48, 0x89, 0xe5, // movq %rsp, %rbp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data64_2));
unwind_plan.Clear();
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data64_2, sizeof(data64_2), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(3);
EXPECT_EQ(3, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
uint8_t data32_1[] = {
0x8b, 0xec, // movl %rsp, %rbp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data32_1));
unwind_plan.Clear();
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data32_1, sizeof(data32_1), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(2);
EXPECT_EQ(2, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
uint8_t data32_2[] = {
0x89, 0xe5, // movl %rsp, %rbp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data32_2));
unwind_plan.Clear();
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data32_2, sizeof(data32_2), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(2);
EXPECT_EQ(2, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
uint8_t data1[] = {
0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data1));
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data1, sizeof(data1), sample_range, unwind_plan));
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(264, row_sp->GetCFAValue().GetOffset());
uint8_t data2[] = {
0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data2));
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data2, sizeof(data2), 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(24, row_sp->GetCFAValue().GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
uint8_t data1[] = {
0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $esp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data1));
EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
data1, sizeof(data1), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(6);
EXPECT_EQ(6, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
uint8_t data2[] = {
0x83, 0xec, 0x10, // subq $0x10, %esp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data2));
EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
data2, sizeof(data2), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(3);
EXPECT_EQ(3, 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());
}
TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
uint8_t data1[] = {
0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data1));
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data1, sizeof(data1), sample_range, unwind_plan));
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 - 256, row_sp->GetCFAValue().GetOffset());
uint8_t data2[] = {
0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data2));
EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
data2, sizeof(data2), 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 - 16, row_sp->GetCFAValue().GetOffset());
}
TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
UnwindPlan::Row::RegisterLocation regloc;
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
uint8_t data1[] = {
0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %esp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data1));
EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
data1, sizeof(data1), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(6);
EXPECT_EQ(6, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
uint8_t data2[] = {
0x83, 0xc4, 0x10, // addq $0x10, %esp
0x90 // nop
};
sample_range = AddressRange(0x1000, sizeof(data2));
EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
data2, sizeof(data2), sample_range, unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(3);
EXPECT_EQ(3, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
}