#include "gtest/gtest.h"
#include <vector>
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/UnwindAssembly.h"
#include "lldb/Utility/ArchSpec.h"
#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
#include "llvm/Support/TargetSelect.h"
using namespace lldb;
using namespace lldb_private;
class TestArm64InstEmulation : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
protected:
};
void TestArm64InstEmulation::SetUpTestCase() {
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
DisassemblerLLVMC::Initialize();
EmulateInstructionARM64::Initialize();
}
void TestArm64InstEmulation::TearDownTestCase() {
DisassemblerLLVMC::Terminate();
EmulateInstructionARM64::Terminate();
}
TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xfd, 0x7b, 0xbf, 0xa9,
0xfd, 0x03, 0x00, 0x91,
0xff, 0x43, 0x00, 0xd1,
0xbf, 0x03, 0x00, 0x91,
0xfd, 0x7b, 0xc1, 0xa8,
0xc0, 0x03, 0x5f, 0xd6,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
row_sp = unwind_plan.GetRowForFunctionOffset(4);
EXPECT_EQ(4ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(8);
EXPECT_EQ(8ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(20);
EXPECT_EQ(20ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
}
TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xf6, 0x57, 0xbd, 0xa9,
0xf4, 0x4f, 0x01, 0xa9,
0xfd, 0x7b, 0x02, 0xa9,
0xfd, 0x83, 0x00, 0x91,
0xff, 0x43, 0x00, 0xd1,
0x1f, 0x20, 0x03, 0xd5,
0xbf, 0x83, 0x00, 0xd1,
0xfd, 0x7b, 0x42, 0xa9,
0xf4, 0x4f, 0x41, 0xa9,
0xf6, 0x57, 0xc3, 0xa8,
0x01, 0x16, 0x09, 0x14,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(4);
EXPECT_EQ(4ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-40, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-48, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(8);
EXPECT_EQ(8ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-24, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-32, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(12);
EXPECT_EQ(12ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(32);
EXPECT_EQ(32ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
row_sp = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_EQ(36ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
row_sp = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(40ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
}
TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0x08, 0x3c, 0x0f, 0x53,
0x68, 0x00, 0x00, 0x39,
0x08, 0x3c, 0x40, 0xd2,
0x1f, 0x00, 0x71, 0xf2,
0x3f, 0x01, 0x0c, 0xeb,
0x81, 0x00, 0x00, 0x54,
0x5f, 0x00, 0x00, 0xb9,
0xe0, 0x03, 0x00, 0x32,
0xc0, 0x03, 0x5f, 0xd6,
0x89, 0x01, 0x09, 0xca,
0x08, 0x05, 0x00, 0x11,
0x48, 0x00, 0x00, 0xb9,
0xe0, 0x03, 0x00, 0x32,
0xc0, 0x03, 0x5f, 0xd6,
0x00, 0x00, 0x80, 0x52,
0xc0, 0x03, 0x5f, 0xd6,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(0);
EXPECT_EQ(0ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(32);
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x23_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x24_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x25_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc));
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc));
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsSame());
row_sp = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(52);
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(56);
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(60);
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
}
TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xfc, 0x6f, 0xba, 0xa9,
0xfa, 0x67, 0x01, 0xa9,
0xf8, 0x5f, 0x02, 0xa9,
0xf6, 0x57, 0x03, 0xa9,
0xf4, 0x4f, 0x04, 0xa9,
0xfd, 0x7b, 0x05, 0xa9,
0xfd, 0x43, 0x01, 0x91,
0xff, 0xc3, 0x00, 0xd1,
0xf8, 0x53, 0x01, 0xa9,
0xf4, 0x4f, 0x41, 0xa9,
0xbf, 0x43, 0x01, 0xd1,
0xfd, 0x7b, 0x45, 0xa9,
0xf4, 0x4f, 0x44, 0xa9,
0xf6, 0x57, 0x43, 0xa9,
0xf8, 0x5f, 0x42, 0xa9,
0xfa, 0x67, 0x41, 0xa9,
0xfc, 0x6f, 0xc6, 0xa8,
0xc0, 0x03, 0x5f, 0xd6,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(36);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-32, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-32, regloc.GetOffset());
}
TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xef, 0x3b, 0xba, 0x6d,
0xed, 0x33, 0x01, 0x6d,
0xeb, 0x2b, 0x02, 0x6d,
0xe9, 0x23, 0x03, 0x6d,
0xfc, 0x6f, 0x04, 0xa9,
0xfd, 0x7b, 0x05, 0xa9,
0xfd, 0x43, 0x01, 0x91,
0xff, 0x43, 0x04, 0xd1,
0xbf, 0x43, 0x01, 0xd1,
0xfd, 0x7b, 0x45, 0xa9,
0xfc, 0x6f, 0x44, 0xa9,
0xe9, 0x23, 0x43, 0x6d,
0xeb, 0x2b, 0x42, 0x6d,
0xed, 0x33, 0x41, 0x6d,
0xef, 0x3b, 0xc6, 0x6c,
0xc0, 0x03, 0x5f, 0xd6,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d15_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-96, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d14_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-88, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d13_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-80, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d12_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-72, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d11_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-64, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d10_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-56, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d9_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-48, regloc.GetOffset());
EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d8_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-40, regloc.GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(60);
EXPECT_EQ(60ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
}
TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) {
ArchSpec arch("arm64-apple-ios10");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xf4, 0x4f, 0xbe, 0xa9,
0xfd, 0x7b, 0x01, 0xa9,
0xfd, 0x43, 0x00, 0x91,
0xff, 0x43, 0x00, 0xd1,
0xeb, 0x00, 0x00, 0x54,
0x1f, 0x20, 0x03, 0xd5,
0xe0, 0x03, 0x13, 0xaa,
0xbf, 0x43, 0x00, 0xd1,
0xfd, 0x7b, 0x41, 0xa9,
0xf4, 0x4f, 0xc2, 0xa8,
0xc0, 0x03, 0x5f, 0xd6,
0x1f, 0x20, 0x03, 0xd5,
0xff, 0x43, 0x00, 0xd1,
0x1f, 0x20, 0x03, 0xd5,
0xe0, 0x03, 0x13, 0xaa,
0xbf, 0x43, 0x00, 0xd1,
0xfd, 0x7b, 0x41, 0xa9,
0xf4, 0x4f, 0xc2, 0xa8,
0xc0, 0x03, 0x5f, 0xd6,
0x1f, 0x20, 0x03, 0xd5,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(40);
EXPECT_EQ(40ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(44);
EXPECT_EQ(44ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(60);
EXPECT_EQ(44ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
row_sp = unwind_plan.GetRowForFunctionOffset(64);
EXPECT_EQ(64ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(32, row_sp->GetCFAValue().GetOffset());
}
TEST_F(TestArm64InstEmulation, TestCFAResetToSP) {
ArchSpec arch("arm64-apple-ios15");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);
UnwindPlan::RowSP row_sp;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::RegisterLocation regloc;
uint8_t data[] = {
0xff, 0x83, 0x00, 0xd1,
0xfd, 0x7b, 0x01, 0xa9,
0xfd, 0x43, 0x00, 0x91,
0xfd, 0x7b, 0x41, 0xa9,
0xff, 0x83, 0x00, 0x91,
0xc0, 0x03, 0x5f, 0xd6,
};
sample_range = AddressRange(0x1000, sizeof(data));
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));
row_sp = unwind_plan.GetRowForFunctionOffset(12);
EXPECT_EQ(12ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
row_sp = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16ull, row_sp->GetOffset());
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
}