Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
"LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},

{0x3f200c00, 0x3c000400, No_VFP,
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
"LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>], #<simm>"},
{0x3f200c00, 0x3c000c00, No_VFP,
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
"LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>, #<simm>]!"},
{0x3f000000, 0x3d000000, No_VFP,
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
"LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>{, #<pimm>}]"},

{0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
"B <label>"},
{0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
Expand Down Expand Up @@ -930,9 +940,29 @@ template <EmulateInstructionARM64::AddrMode a_mode>
bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
uint32_t size = Bits32(opcode, 31, 30);
uint32_t opc = Bits32(opcode, 23, 22);
uint32_t vr = Bit32(opcode, 26);
uint32_t n = Bits32(opcode, 9, 5);
uint32_t t = Bits32(opcode, 4, 0);

MemOp memop;
if (vr) {
// opc<1> == 1 && size != 0 is an undefined encoding.
if (Bit32(opc, 1) == 1 && size != 0)
return false;
// opc<1> == 1 && size == 0 encode the 128-bit variant.
if (Bit32(opc, 1) == 1)
size = 4;
memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
} else {
if (Bit32(opc, 1) == 0) {
memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
} else {
memop = MemOp_LOAD;
if (size == 2 && Bit32(opc, 0) == 1)
return false;
}
}

bool wback;
bool postindex;
uint64_t offset;
Expand All @@ -955,16 +985,6 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
break;
}

MemOp memop;

if (Bit32(opc, 1) == 0) {
memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
} else {
memop = MemOp_LOAD;
if (size == 2 && Bit32(opc, 0) == 1)
return false;
}

Status error;
bool success = false;
uint64_t address;
Expand All @@ -989,7 +1009,8 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
return false;

std::optional<RegisterInfo> reg_info_Rt =
GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
vr ? GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t)
: GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
if (!reg_info_Rt)
return false;

Expand Down
108 changes: 108 additions & 0 deletions lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,3 +856,111 @@ TEST_F(TestArm64InstEmulation, TestCFAResetToSP) {
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
}

TEST_F(TestArm64InstEmulation, TestPrologueStartsWithStrD8) {
ArchSpec arch("aarch64");
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
static_cast<UnwindAssemblyInstEmulation *>(
UnwindAssemblyInstEmulation::CreateInstance(arch)));
ASSERT_NE(nullptr, engine);

const UnwindPlan::Row *row;
AddressRange sample_range;
UnwindPlan unwind_plan(eRegisterKindLLDB);
UnwindPlan::Row::AbstractRegisterLocation regloc;

// The sample function is built with 'clang --target aarch64 -O1':
//
// int bar(float x);
// int foo(float x) {
// return bar(x) + bar(x);
// }
//
// The function uses one floating point register and spills it with
// 'str d8, [sp, #-0x20]!'.

// clang-format off
uint8_t data[] = {
// prologue
0xe8, 0x0f, 0x1e, 0xfc, // 0: fc1e0fe8 str d8, [sp, #-0x20]!
0xfd, 0xfb, 0x00, 0xa9, // 4: a900fbfd stp x29, x30, [sp, #0x8]
0xf3, 0x0f, 0x00, 0xf9, // 8: f9000ff3 str x19, [sp, #0x18]
0xfd, 0x23, 0x00, 0x91, // 12: 910023fd add x29, sp, #0x8

// epilogue
0xfd, 0xfb, 0x40, 0xa9, // 16: a940fbfd ldp x29, x30, [sp, #0x8]
0xf3, 0x0f, 0x40, 0xf9, // 20: f9400ff3 ldr x19, [sp, #0x18]
0xe8, 0x07, 0x42, 0xfc, // 24: fc4207e8 ldr d8, [sp], #0x20
0xc0, 0x03, 0x5f, 0xd6, // 28: d65f03c0 ret
};
// clang-format on

// UnwindPlan we expect:
// 0: CFA=sp +0 =>
// 4: CFA=sp+32 => d8=[CFA-32]
// 8: CFA=sp+32 => fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]
// 12: CFA=sp+32 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]
// 16: CFA=fp+24 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]
// 20: CFA=sp+32 => x19=[CFA-8] fp=<same> lr=<same> d8=[CFA-32]
// 24: CFA=sp+32 => x19=<same> fp=<same> lr=<same> d8=[CFA-32]
// 28: CFA=sp +0 => x19=<same> fp=<same> lr=<same> d8=<same>

sample_range = AddressRange(0x1000, sizeof(data));

EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
sample_range, data, sizeof(data), unwind_plan));

// 4: CFA=sp+32 => d8=[CFA-32]
row = unwind_plan.GetRowForFunctionOffset(4);
EXPECT_EQ(4, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(32, row->GetCFAValue().GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(fpu_d8_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-32, regloc.GetOffset());

// 16: CFA=fp+24 => x19=[CFA-8] fp=[CFA-24] lr=[CFA-16] d8=[CFA-32]
row = unwind_plan.GetRowForFunctionOffset(16);
EXPECT_EQ(16, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(24, row->GetCFAValue().GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(gpr_x19_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-8, regloc.GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-24, regloc.GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(gpr_lr_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-16, regloc.GetOffset());

EXPECT_TRUE(row->GetRegisterInfo(fpu_d8_arm64, regloc));
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
EXPECT_EQ(-32, regloc.GetOffset());

// 28: CFA=sp +0 => x19=<same> fp=<same> lr=<same> d8=<same>
row = unwind_plan.GetRowForFunctionOffset(28);
EXPECT_EQ(28, row->GetOffset());
EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true);
EXPECT_EQ(0, row->GetCFAValue().GetOffset());

if (row->GetRegisterInfo(gpr_x19_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row->GetRegisterInfo(gpr_fp_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row->GetRegisterInfo(gpr_lr_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
if (row->GetRegisterInfo(fpu_d8_arm64, regloc)) {
EXPECT_TRUE(regloc.IsSame());
}
}
Loading