[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-24 15:23:27 +08:00
|
|
|
//===-- TestArm64InstEmulation.cpp ----------------------------------------===//
|
2016-10-11 10:24:00 +08:00
|
|
|
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-10-11 10:24:00 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#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"
|
2017-11-14 00:16:33 +08:00
|
|
|
#include "lldb/Utility/ArchSpec.h"
|
2016-10-11 10:24:00 +08:00
|
|
|
|
2020-01-22 07:14:28 +08:00
|
|
|
#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
|
2016-10-11 10:24:00 +08:00
|
|
|
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
|
2016-11-01 09:26:54 +08:00
|
|
|
#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
|
2016-10-11 10:24:00 +08:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
|
|
class TestArm64InstEmulation : public testing::Test {
|
|
|
|
public:
|
2016-10-11 19:05:34 +08:00
|
|
|
static void SetUpTestCase();
|
|
|
|
static void TearDownTestCase();
|
2016-10-11 10:24:00 +08:00
|
|
|
|
|
|
|
// virtual void SetUp() override { }
|
|
|
|
// virtual void TearDown() override { }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
};
|
|
|
|
|
2016-10-11 19:05:34 +08:00
|
|
|
void TestArm64InstEmulation::SetUpTestCase() {
|
2016-10-11 10:24:00 +08:00
|
|
|
llvm::InitializeAllTargets();
|
|
|
|
llvm::InitializeAllAsmPrinters();
|
|
|
|
llvm::InitializeAllTargetMCs();
|
|
|
|
llvm::InitializeAllDisassemblers();
|
|
|
|
DisassemblerLLVMC::Initialize();
|
|
|
|
EmulateInstructionARM64::Initialize();
|
|
|
|
}
|
|
|
|
|
2016-10-11 19:05:34 +08:00
|
|
|
void TestArm64InstEmulation::TearDownTestCase() {
|
2016-10-11 10:24:00 +08:00
|
|
|
DisassemblerLLVMC::Terminate();
|
|
|
|
EmulateInstructionARM64::Terminate();
|
|
|
|
}
|
|
|
|
|
2016-10-11 11:44:48 +08:00
|
|
|
TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {
|
2017-10-31 18:56:03 +08:00
|
|
|
ArchSpec arch("arm64-apple-ios10");
|
2018-01-22 15:22:13 +08:00
|
|
|
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
2016-10-11 10:24:00 +08:00
|
|
|
static_cast<UnwindAssemblyInstEmulation *>(
|
2018-01-22 15:22:13 +08:00
|
|
|
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
2016-10-12 10:46:22 +08:00
|
|
|
ASSERT_NE(nullptr, engine);
|
2016-10-11 10:24:00 +08:00
|
|
|
|
|
|
|
UnwindPlan::RowSP row_sp;
|
|
|
|
AddressRange sample_range;
|
|
|
|
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
|
|
|
UnwindPlan::Row::RegisterLocation regloc;
|
|
|
|
|
2016-10-11 11:44:48 +08:00
|
|
|
// 'int main() { }' compiled for arm64-apple-ios with clang
|
2016-10-11 10:24:00 +08:00
|
|
|
uint8_t data[] = {
|
|
|
|
0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd : stp x29, x30, [sp, #-0x10]!
|
|
|
|
0xfd, 0x03, 0x00, 0x91, // 0x910003fd : mov x29, sp
|
|
|
|
0xff, 0x43, 0x00, 0xd1, // 0xd10043ff : sub sp, sp, #0x10
|
|
|
|
|
|
|
|
0xbf, 0x03, 0x00, 0x91, // 0x910003bf : mov sp, x29
|
|
|
|
0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd : ldp x29, x30, [sp], #16
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 : ret
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
|
|
|
|
// row[0]: 0: CFA=sp +0 =>
|
|
|
|
// row[1]: 4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[2]: 8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[2]: 16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[3]: 20: CFA=sp +0 => fp= <same> lr= <same>
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
// CFA=sp +0
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(0);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(0ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
// CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(4);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(4ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-16, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-8, regloc.GetOffset());
|
|
|
|
|
|
|
|
// CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(8);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(8ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-16, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-8, regloc.GetOffset());
|
|
|
|
|
|
|
|
// CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(16);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(16ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-16, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-8, regloc.GetOffset());
|
|
|
|
|
|
|
|
// CFA=sp +0 => fp= <same> lr= <same>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(20);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(20ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 10:24:00 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
}
|
2016-10-11 11:44:48 +08:00
|
|
|
|
|
|
|
TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
|
2017-10-31 18:56:03 +08:00
|
|
|
ArchSpec arch("arm64-apple-ios10");
|
2018-01-22 15:22:13 +08:00
|
|
|
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
2016-10-11 11:44:48 +08:00
|
|
|
static_cast<UnwindAssemblyInstEmulation *>(
|
2018-01-22 15:22:13 +08:00
|
|
|
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
2016-10-12 10:46:22 +08:00
|
|
|
ASSERT_NE(nullptr, engine);
|
2016-10-11 11:44:48 +08:00
|
|
|
|
|
|
|
UnwindPlan::RowSP row_sp;
|
|
|
|
AddressRange sample_range;
|
|
|
|
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
|
|
|
UnwindPlan::Row::RegisterLocation regloc;
|
|
|
|
|
|
|
|
// disassembly of -[NSPlaceholderString initWithBytes:length:encoding:]
|
|
|
|
// from Foundation for iOS.
|
|
|
|
uint8_t data[] = {
|
|
|
|
0xf6, 0x57, 0xbd, 0xa9, // 0: 0xa9bd57f6 stp x22, x21, [sp, #-48]!
|
|
|
|
0xf4, 0x4f, 0x01, 0xa9, // 4: 0xa9014ff4 stp x20, x19, [sp, #16]
|
|
|
|
0xfd, 0x7b, 0x02, 0xa9, // 8: 0xa9027bfd stp x29, x30, [sp, #32]
|
|
|
|
0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32
|
|
|
|
0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16
|
|
|
|
|
|
|
|
// [... function body ...]
|
|
|
|
0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
|
|
|
|
|
|
|
|
0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32
|
|
|
|
0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32]
|
|
|
|
0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16]
|
|
|
|
0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48
|
|
|
|
0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b 0x18f640524 ; symbol stub
|
|
|
|
// for: CFStringCreateWithBytes
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
// 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
|
|
|
|
// [... function body ...]
|
|
|
|
|
|
|
|
// 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
|
|
|
|
// <same> lr= <same>
|
|
|
|
// 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
|
|
|
|
// <same> lr= <same>
|
|
|
|
// 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
|
|
|
|
// lr= <same>
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(0);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(0ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
// 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(4);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(4ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-40, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-48, regloc.GetOffset());
|
|
|
|
|
|
|
|
// 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(8);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(8ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-24, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-32, regloc.GetOffset());
|
|
|
|
|
|
|
|
// 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(12);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(12ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-16, regloc.GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-8, regloc.GetOffset());
|
|
|
|
|
|
|
|
// 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(16);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(16ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
// 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// fp=[CFA-16] lr=[CFA-8]
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(28);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(28ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
// 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
|
|
|
|
// <same> lr= <same>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(32);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(32ull, row_sp->GetOffset());
|
2016-10-11 11:44:48 +08:00
|
|
|
|
|
|
|
// I'd prefer if these restored registers were cleared entirely instead of set
|
|
|
|
// to IsSame...
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
|
|
|
|
// 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
|
|
|
|
// <same> lr= <same>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(36);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(36ull, row_sp->GetOffset());
|
2016-10-11 11:44:48 +08:00
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
|
|
|
|
// 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
|
|
|
|
// lr= <same>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(40);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(40ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
|
2016-10-11 11:44:48 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
|
|
|
}
|
2016-10-12 10:46:22 +08:00
|
|
|
|
|
|
|
TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {
|
2017-10-31 18:56:03 +08:00
|
|
|
ArchSpec arch("arm64-apple-ios10");
|
2018-01-22 15:22:13 +08:00
|
|
|
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
2016-10-12 10:46:22 +08:00
|
|
|
static_cast<UnwindAssemblyInstEmulation *>(
|
2018-01-22 15:22:13 +08:00
|
|
|
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
2016-10-12 10:46:22 +08:00
|
|
|
ASSERT_NE(nullptr, engine);
|
|
|
|
|
|
|
|
UnwindPlan::RowSP row_sp;
|
|
|
|
AddressRange sample_range;
|
|
|
|
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
|
|
|
UnwindPlan::Row::RegisterLocation regloc;
|
|
|
|
|
|
|
|
// disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u>
|
|
|
|
// from JavaScriptcore for iOS.
|
|
|
|
uint8_t data[] = {
|
|
|
|
0x08, 0x3c, 0x0f, 0x53, // 0: 0x530f3c08 ubfx w8, w0, #15, #1
|
|
|
|
0x68, 0x00, 0x00, 0x39, // 4: 0x39000068 strb w8, [x3]
|
|
|
|
0x08, 0x3c, 0x40, 0xd2, // 8: 0xd2403c08 eor x8, x0, #0xffff
|
|
|
|
0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst x0, #0x8000
|
|
|
|
|
|
|
|
// [...]
|
|
|
|
|
|
|
|
0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp x9, x12
|
|
|
|
0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34
|
|
|
|
0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str wzr, [x2]
|
|
|
|
0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr w0, wzr, #0x1
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret
|
|
|
|
0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor x9, x12, x9
|
|
|
|
|
|
|
|
// [...]
|
2016-10-12 11:53:01 +08:00
|
|
|
|
2016-10-12 10:46:22 +08:00
|
|
|
0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add w8, w8, #0x1
|
|
|
|
0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str w8, [x2]
|
|
|
|
0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr w0, wzr, #0x1
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret
|
|
|
|
0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov w0, #0x0
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
// (possibly with additional rows at offsets 36 and 56 saying the same thing)
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(0);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(0ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(32);
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
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_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
|
|
|
|
EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
|
2016-10-12 10:46:22 +08:00
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(36);
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(52);
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(56);
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(60);
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
|
2016-10-12 10:46:22 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
|
|
|
}
|
|
|
|
|
2016-10-12 11:53:01 +08:00
|
|
|
TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
|
2017-10-31 18:56:03 +08:00
|
|
|
ArchSpec arch("arm64-apple-ios10");
|
2018-01-22 15:22:13 +08:00
|
|
|
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
2016-10-12 11:53:01 +08:00
|
|
|
static_cast<UnwindAssemblyInstEmulation *>(
|
2018-01-22 15:22:13 +08:00
|
|
|
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
2016-10-12 11:53:01 +08:00
|
|
|
ASSERT_NE(nullptr, engine);
|
|
|
|
|
|
|
|
UnwindPlan::RowSP row_sp;
|
|
|
|
AddressRange sample_range;
|
|
|
|
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
|
|
|
UnwindPlan::Row::RegisterLocation regloc;
|
|
|
|
|
|
|
|
// disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS.
|
|
|
|
uint8_t data[] = {
|
|
|
|
|
|
|
|
0xfc, 0x6f, 0xba, 0xa9, // 0: 0xa9ba6ffc stp x28, x27, [sp, #-0x60]!
|
|
|
|
0xfa, 0x67, 0x01, 0xa9, // 4: 0xa90167fa stp x26, x25, [sp, #0x10]
|
|
|
|
0xf8, 0x5f, 0x02, 0xa9, // 8: 0xa9025ff8 stp x24, x23, [sp, #0x20]
|
|
|
|
0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp x22, x21, [sp, #0x30]
|
|
|
|
0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp x20, x19, [sp, #0x40]
|
|
|
|
0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
|
|
|
|
0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
|
|
|
|
0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub sp, sp, #0x30
|
|
|
|
|
|
|
|
// mid-function, store x20 & x24 on the stack at a different location.
|
|
|
|
// this should not show up in the unwind plan; caller's values are not
|
|
|
|
// being saved to stack.
|
|
|
|
0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp x24, x20, [sp, #0x10]
|
|
|
|
|
|
|
|
// mid-function, copy x20 and x19 off of the stack -- but not from
|
|
|
|
// their original locations. unwind plan should ignore this.
|
|
|
|
0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp x20, x19, [sp, #0x10]
|
|
|
|
|
|
|
|
// epilogue
|
|
|
|
0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub sp, x29, #0x50
|
|
|
|
0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp x29, x30, [sp, #0x50]
|
|
|
|
0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp x20, x19, [sp, #0x40]
|
|
|
|
0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp x22, x21, [sp, #0x30]
|
|
|
|
0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp x24, x23, [sp, #0x20]
|
|
|
|
0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp x26, x25, [sp, #0x10]
|
|
|
|
0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp x28, x27, [sp], #0x60
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
// 4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
|
|
|
|
// x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
|
|
|
|
// x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
|
|
|
|
// x28=[CFA-96]
|
|
|
|
// 24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
|
|
|
|
// x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// 28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
|
|
|
|
// x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
|
|
|
|
// 44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
|
|
|
|
// x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// 48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
|
|
|
|
// x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
|
|
|
|
// x28=[CFA-96]
|
|
|
|
// 52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
|
|
|
|
// x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
|
|
|
|
// x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 60: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 64: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
|
|
|
|
// 68: CFA=sp +0 =>
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(36);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(28ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
|
2016-10-12 11:53:01 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
|
2016-10-12 11:53:01 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-32, regloc.GetOffset());
|
2016-10-12 10:46:22 +08:00
|
|
|
|
2016-10-12 11:53:01 +08:00
|
|
|
row_sp = unwind_plan.GetRowForFunctionOffset(40);
|
2016-10-18 02:22:03 +08:00
|
|
|
EXPECT_EQ(28ull, row_sp->GetOffset());
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
|
2016-10-12 11:53:01 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
|
|
|
EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
|
|
|
|
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
|
2016-10-12 11:53:01 +08:00
|
|
|
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
|
|
|
EXPECT_EQ(-32, regloc.GetOffset());
|
|
|
|
}
|
2016-11-01 09:26:54 +08:00
|
|
|
|
|
|
|
TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
|
2017-10-31 18:56:03 +08:00
|
|
|
ArchSpec arch("arm64-apple-ios10");
|
2018-01-22 15:22:13 +08:00
|
|
|
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
2016-11-01 09:26:54 +08:00
|
|
|
static_cast<UnwindAssemblyInstEmulation *>(
|
2018-01-22 15:22:13 +08:00
|
|
|
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
2016-11-01 09:26:54 +08:00
|
|
|
ASSERT_NE(nullptr, engine);
|
|
|
|
|
|
|
|
UnwindPlan::RowSP row_sp;
|
|
|
|
AddressRange sample_range;
|
|
|
|
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
|
|
|
UnwindPlan::Row::RegisterLocation regloc;
|
|
|
|
|
|
|
|
// this file built with clang for iOS arch arm64 optimization -Os
|
|
|
|
// #include <stdio.h>
|
|
|
|
// double foo(double in) {
|
|
|
|
// double arr[32];
|
|
|
|
// for (int i = 0; i < 32; i++)
|
|
|
|
// arr[i] = in + i;
|
|
|
|
// for (int i = 2; i < 30; i++)
|
|
|
|
// arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) /
|
|
|
|
// ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i]
|
|
|
|
// * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) /
|
|
|
|
// ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) +
|
|
|
|
// ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i -
|
|
|
|
// 1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345)
|
|
|
|
// + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i]
|
|
|
|
// * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] +
|
|
|
|
// 17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888);
|
|
|
|
// return arr[16];
|
|
|
|
//}
|
|
|
|
// int main(int argc, char **argv) { printf("%g\n", foo(argc)); }
|
|
|
|
|
|
|
|
// so function foo() uses enough registers that it spills the callee-saved
|
|
|
|
// floating point registers.
|
|
|
|
uint8_t data[] = {
|
|
|
|
// prologue
|
|
|
|
0xef, 0x3b, 0xba, 0x6d, // 0: 0x6dba3bef stp d15, d14, [sp, #-0x60]!
|
|
|
|
0xed, 0x33, 0x01, 0x6d, // 4: 0x6d0133ed stp d13, d12, [sp, #0x10]
|
|
|
|
0xeb, 0x2b, 0x02, 0x6d, // 8: 0x6d022beb stp d11, d10, [sp, #0x20]
|
|
|
|
0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9 stp d9, d8, [sp, #0x30]
|
|
|
|
0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc stp x28, x27, [sp, #0x40]
|
|
|
|
0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
|
|
|
|
0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
|
|
|
|
0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff sub sp, sp, #0x110
|
|
|
|
|
|
|
|
// epilogue
|
|
|
|
0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf sub sp, x29, #0x50
|
|
|
|
0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd ldp x29, x30, [sp, #0x50]
|
|
|
|
0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc ldp x28, x27, [sp, #0x40]
|
|
|
|
0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9 ldp d9, d8, [sp, #0x30]
|
|
|
|
0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb ldp d11, d10, [sp, #0x20]
|
|
|
|
0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed ldp d13, d12, [sp, #0x10]
|
|
|
|
0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef ldp d15, d14, [sp], #0x60
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
// 0: CFA=sp +0 =>
|
|
|
|
// 4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
|
|
|
|
// d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
|
|
|
|
// d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
|
|
|
|
// d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
|
|
|
|
// d15=[CFA-96]
|
|
|
|
// 24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
|
|
|
|
// d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
|
|
|
|
// d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
|
|
|
|
// d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
|
|
|
|
// d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
|
|
|
|
// d15=[CFA-96]
|
|
|
|
// 44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
|
|
|
|
// d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
|
|
|
|
// d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
|
|
|
|
// 60: CFA=sp +0 =>
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
// 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
|
|
|
|
// d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
|
|
|
|
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());
|
|
|
|
|
|
|
|
// 60: CFA=sp +0 =>
|
|
|
|
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());
|
|
|
|
|
2019-05-29 02:36:35 +08:00
|
|
|
if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
|
|
|
if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)) {
|
2016-11-01 09:26:54 +08:00
|
|
|
EXPECT_TRUE(regloc.IsSame());
|
2019-05-29 02:36:35 +08:00
|
|
|
}
|
2016-11-01 09:26:54 +08:00
|
|
|
}
|
2020-04-15 07:51:58 +08:00
|
|
|
|
|
|
|
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[] = {
|
|
|
|
// prologue
|
|
|
|
0xf4, 0x4f, 0xbe, 0xa9, // 0: 0xa9be4ff4 stp x20, x19, [sp, #-0x20]!
|
|
|
|
0xfd, 0x7b, 0x01, 0xa9, // 4: 0xa9017bfd stp x29, x30, [sp, #0x10]
|
|
|
|
0xfd, 0x43, 0x00, 0x91, // 8: 0x910043fd add x29, sp, #0x10
|
|
|
|
0xff, 0x43, 0x00, 0xd1, // 12: 0xd10043ff sub sp, sp, #0x10
|
|
|
|
// conditional branch over a mid-function epilogue
|
|
|
|
0xeb, 0x00, 0x00, 0x54, // 16: 0x540000eb b.lt <+44>
|
|
|
|
// mid-function epilogue
|
|
|
|
0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
|
|
|
|
0xe0, 0x03, 0x13, 0xaa, // 24: 0xaa1303e0 mov x0, x19
|
|
|
|
0xbf, 0x43, 0x00, 0xd1, // 28: 0xd10043bf sub sp, x29, #0x10
|
|
|
|
0xfd, 0x7b, 0x41, 0xa9, // 32: 0xa9417bfd ldp x29, x30, [sp, #0x10]
|
|
|
|
0xf4, 0x4f, 0xc2, 0xa8, // 36: 0xa8c24ff4 ldp x20, x19, [sp], #0x20
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 40: 0xd65f03c0 ret
|
|
|
|
// unwind state restored, we're using a frame pointer, let's change the
|
|
|
|
// stack pointer and see no change in how the CFA is computed
|
|
|
|
0x1f, 0x20, 0x03, 0xd5, // 44: 0xd503201f nop
|
|
|
|
0xff, 0x43, 0x00, 0xd1, // 48: 0xd10043ff sub sp, sp, #0x10
|
|
|
|
0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop
|
|
|
|
// final epilogue
|
|
|
|
0xe0, 0x03, 0x13, 0xaa, // 56: 0xaa1303e0 mov x0, x19
|
|
|
|
0xbf, 0x43, 0x00, 0xd1, // 60: 0xd10043bf sub sp, x29, #0x10
|
|
|
|
0xfd, 0x7b, 0x41, 0xa9, // 64: 0xa9417bfd ldp x29, x30, [sp, #0x10]
|
|
|
|
0xf4, 0x4f, 0xc2, 0xa8, // 68: 0xa8c24ff4 ldp x20, x19, [sp], #0x20
|
|
|
|
0xc0, 0x03, 0x5f, 0xd6, // 72: 0xd65f03c0 ret
|
|
|
|
|
|
|
|
0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop
|
|
|
|
};
|
|
|
|
|
|
|
|
// UnwindPlan we expect:
|
|
|
|
// row[0]: 0: CFA=sp +0 =>
|
|
|
|
// row[1]: 4: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32]
|
|
|
|
// row[2]: 8: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[3]: 12: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[4]: 32: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[5]: 36: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
|
|
|
|
// row[6]: 40: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same>
|
|
|
|
// row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[8]: 64: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[9]: 68: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
|
|
|
|
// row[10]: 72: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same>
|
|
|
|
|
|
|
|
// The specific bug we're looking for is this incorrect CFA definition,
|
|
|
|
// where the InstEmulation is using the $sp value mixed in with $fp,
|
|
|
|
// it looks like this:
|
|
|
|
//
|
|
|
|
// row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[8]: 52: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
|
|
|
|
// row[9]: 68: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
|
|
|
|
|
|
|
|
sample_range = AddressRange(0x1000, sizeof(data));
|
|
|
|
|
|
|
|
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
|
|
|
sample_range, data, sizeof(data), unwind_plan));
|
|
|
|
|
|
|
|
// Confirm CFA at mid-func epilogue 'ret' is $sp+0
|
|
|
|
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());
|
|
|
|
|
|
|
|
// After the 'ret', confirm we're back to the correct CFA of $fp+16
|
|
|
|
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());
|
|
|
|
|
|
|
|
// Confirm that we have no additional UnwindPlan rows before the
|
|
|
|
// real epilogue -- we still get the Row at offset 44.
|
|
|
|
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());
|
|
|
|
|
|
|
|
// And in the epilogue, confirm that we start by switching back to
|
|
|
|
// defining the CFA in terms of $sp.
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|