Author: jmolenda Date: Mon Oct 10 21:24:00 2016 New Revision: 283847 URL: http://llvm.org/viewvc/llvm-project?rev=283847&view=rev Log: Add a first unit test for the arm64 instruction profiled unwind plan generator.
Fix a small bug in EmulateInstructionARM64::GetFramePointerRegister which was returning the stack pointer reg instead of fp, prevented the unwinder from recognizing the switch to using the fp in a function. (<rdar://problem/28663117>) Add a new eContextRestoreStackPointer context hint so that the arm64 emulator can flag when the frame pointer value is copied back in to the stack pointer and that should be used to compute the canonical frame address again in an epilogue sequence. (<rdar://problem/28704862>) Small changes to UnwindAssemblyInstEmulation to have a method we can call without a live process/thread/etc for unit tests. <rdar://problem/28663117> <rdar://problem/28704862> <rdar://problem/28509178> Added: lldb/trunk/unittests/UnwindAssembly/InstEmulation/ lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp Modified: lldb/trunk/include/lldb/Core/EmulateInstruction.h lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt Modified: lldb/trunk/include/lldb/Core/EmulateInstruction.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/EmulateInstruction.h?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/EmulateInstruction.h (original) +++ lldb/trunk/include/lldb/Core/EmulateInstruction.h Mon Oct 10 21:24:00 2016 @@ -111,6 +111,10 @@ public: // Adjust the frame pointer for the current frame eContextSetFramePointer, + // Typically in an epilogue sequence. Copy the frame pointer back + // into the stack pointer, use SP for CFA calculations again. + eContextRestoreStackPointer, + // Add or subtract a value from a base address register (other than SP) eContextAdjustBaseRegister, Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Oct 10 21:24:00 2016 @@ -916,6 +916,7 @@ AF20F76A1AF18F9000751A6E /* ABISysV_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF20F7681AF18F9000751A6E /* ABISysV_arm64.cpp */; }; AF20F7701AF1902900751A6E /* RegisterContextLinux_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF20F76E1AF1902900751A6E /* RegisterContextLinux_arm64.cpp */; }; AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */; }; + AF248A4D1DA71C77000B814D /* TestArm64InstEmulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF248A4C1DA71C77000B814D /* TestArm64InstEmulation.cpp */; }; AF254E31170CCC33007AE5C9 /* PlatformDarwinKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */; }; AF25AB26188F685C0030DEC3 /* AppleGetQueuesHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF25AB24188F685C0030DEC3 /* AppleGetQueuesHandler.cpp */; }; AF26703A1852D01E00B6CC36 /* Queue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF2670381852D01E00B6CC36 /* Queue.cpp */; }; @@ -2922,6 +2923,7 @@ AF20F76F1AF1902900751A6E /* RegisterContextLinux_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextLinux_arm64.h; path = Utility/RegisterContextLinux_arm64.h; sourceTree = "<group>"; }; AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FreeBSDSignals.cpp; path = Utility/FreeBSDSignals.cpp; sourceTree = "<group>"; }; AF23B4DA19009C66003E2A58 /* FreeBSDSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FreeBSDSignals.h; path = Utility/FreeBSDSignals.h; sourceTree = "<group>"; }; + AF248A4C1DA71C77000B814D /* TestArm64InstEmulation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestArm64InstEmulation.cpp; path = UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp; sourceTree = "<group>"; }; AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformDarwinKernel.cpp; sourceTree = "<group>"; }; AF254E30170CCC33007AE5C9 /* PlatformDarwinKernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformDarwinKernel.h; sourceTree = "<group>"; }; AF25AB24188F685C0030DEC3 /* AppleGetQueuesHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleGetQueuesHandler.cpp; sourceTree = "<group>"; }; @@ -6252,6 +6254,14 @@ name = "SysV-arm64"; sourceTree = "<group>"; }; + AF248A4B1DA71C67000B814D /* InstEmulation */ = { + isa = PBXGroup; + children = ( + AF248A4C1DA71C77000B814D /* TestArm64InstEmulation.cpp */, + ); + name = InstEmulation; + sourceTree = "<group>"; + }; AF2BCA6518C7EFDE005B4526 /* JITLoader */ = { isa = PBXGroup; children = ( @@ -6301,7 +6311,7 @@ AFEC5FD31D94F9130076A480 /* UnwindAssembly */ = { isa = PBXGroup; children = ( - AFEC5FD51D94F9380076A480 /* Testx86AssemblyInspectionEngine.cpp */, + AF248A4B1DA71C67000B814D /* InstEmulation */, AFEC5FD41D94F9270076A480 /* x86 */, ); name = UnwindAssembly; @@ -6310,6 +6320,7 @@ AFEC5FD41D94F9270076A480 /* x86 */ = { isa = PBXGroup; children = ( + AFEC5FD51D94F9380076A480 /* Testx86AssemblyInspectionEngine.cpp */, ); name = x86; sourceTree = "<group>"; @@ -6911,6 +6922,7 @@ 23CB15351D66DA9300EDDDE1 /* UriParserTest.cpp in Sources */, 23CB15361D66DA9300EDDDE1 /* FileSpecTest.cpp in Sources */, 23E2E5251D90373D006F38BB /* ArchSpecTest.cpp in Sources */, + AF248A4D1DA71C77000B814D /* TestArm64InstEmulation.cpp in Sources */, 23CB15371D66DA9300EDDDE1 /* PythonTestSuite.cpp in Sources */, 23E2E5291D9037D9006F38BB /* SymbolFilePDBTests.cpp in Sources */, 23E2E5321D903832006F38BB /* BreakpointIDTest.cpp in Sources */, Modified: lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp (original) +++ lldb/trunk/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp Mon Oct 10 21:24:00 2016 @@ -497,7 +497,7 @@ uint32_t EmulateInstructionARM64::GetFra if (m_arch.GetTriple().isAndroid()) return LLDB_INVALID_REGNUM; // Don't use frame pointer on android - return arm64_dwarf::sp; + return arm64_dwarf::fp; } bool EmulateInstructionARM64::UsingAArch32() { @@ -693,8 +693,13 @@ bool EmulateInstructionARM64::EmulateADD if (arm64_dwarf::GetRegisterInfo(n, reg_info_Rn)) context.SetRegisterPlusOffset(reg_info_Rn, imm); - if ((n == arm64_dwarf::sp || n == GetFramePointerRegisterNumber()) && - d == arm64_dwarf::sp && !setflags) { + if (n == GetFramePointerRegisterNumber() && d == arm64_dwarf::sp && + !setflags) { + // 'mov sp, fp' - common epilogue instruction, CFA is now in terms + // of the stack pointer, instead of frame pointer. + context.type = EmulateInstruction::eContextRestoreStackPointer; + } else if ((n == arm64_dwarf::sp || n == GetFramePointerRegisterNumber()) && + d == arm64_dwarf::sp && !setflags) { context.type = EmulateInstruction::eContextAdjustStackPointer; } else if (d == GetFramePointerRegisterNumber() && n == arm64_dwarf::sp && !setflags) { Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original) +++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Mon Oct 10 21:24:00 2016 @@ -34,6 +34,27 @@ using namespace lldb_private; bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) { + std::vector<uint8_t> function_text(range.GetByteSize()); + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) { + Error error; + const bool prefer_file_cache = true; + if (process_sp->GetTarget().ReadMemory( + range.GetBaseAddress(), prefer_file_cache, function_text.data(), + range.GetByteSize(), error) != range.GetByteSize()) { + return false; + } + } + return GetNonCallSiteUnwindPlanFromAssembly( + range, function_text.data(), function_text.size(), unwind_plan); +} + +bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( + AddressRange &range, uint8_t *opcode_data, size_t opcode_size, + UnwindPlan &unwind_plan) { + if (opcode_data == nullptr || opcode_size == 0) + return false; + if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() && m_inst_emulator_ap.get()) { @@ -46,18 +67,16 @@ bool UnwindAssemblyInstEmulation::GetNon if (unwind_plan.GetRowCount() == 0) return false; - ExecutionContext exe_ctx; - thread.CalculateExecutionContext(exe_ctx); const bool prefer_file_cache = true; - DisassemblerSP disasm_sp(Disassembler::DisassembleRange( - m_arch, NULL, NULL, exe_ctx, range, prefer_file_cache)); + DisassemblerSP disasm_sp(Disassembler::DisassembleBytes( + m_arch, NULL, NULL, range.GetBaseAddress(), opcode_data, opcode_size, + 99999, prefer_file_cache)); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); if (disasm_sp) { m_range_ptr = ⦥ - m_thread_ptr = &thread; m_unwind_plan_ptr = &unwind_plan; const uint32_t addr_byte_size = m_arch.GetAddressByteSize(); @@ -154,8 +173,8 @@ bool UnwindAssemblyInstEmulation::GetNon m_register_values = it->second.second; } - m_inst_emulator_ap->SetInstruction( - inst->GetOpcode(), inst->GetAddress(), exe_ctx.GetTargetPtr()); + m_inst_emulator_ap->SetInstruction(inst->GetOpcode(), + inst->GetAddress(), nullptr); if (last_condition != m_inst_emulator_ap->GetInstructionCondition()) { @@ -253,11 +272,10 @@ bool UnwindAssemblyInstEmulation::GetNon if (log && log->GetVerbose()) { StreamString strm; - lldb::addr_t base_addr = - range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get()); + lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress(); strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize()); - unwind_plan.Dump(strm, &thread, base_addr); + unwind_plan.Dump(strm, nullptr, base_addr); log->PutCString(strm.GetData()); } return unwind_plan.GetRowCount() > 0; @@ -613,6 +631,19 @@ bool UnwindAssemblyInstEmulation::WriteR m_cfa_reg_info = *reg_info; const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; + assert(cfa_reg_num != LLDB_INVALID_REGNUM); + m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( + cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); + m_curr_row_modified = true; + } + break; + + case EmulateInstruction::eContextRestoreStackPointer: + if (m_fp_is_cfa) { + m_fp_is_cfa = false; + m_cfa_reg_info = *reg_info; + const uint32_t cfa_reg_num = + reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; assert(cfa_reg_num != LLDB_INVALID_REGNUM); m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original) +++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Mon Oct 10 21:24:00 2016 @@ -29,6 +29,11 @@ public: lldb_private::UnwindPlan &unwind_plan) override; bool + GetNonCallSiteUnwindPlanFromAssembly(lldb_private::AddressRange &func, + uint8_t *opcode_data, size_t opcode_size, + lldb_private::UnwindPlan &unwind_plan); + + bool AugmentUnwindPlanFromCallSite(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override; @@ -67,8 +72,8 @@ private: UnwindAssemblyInstEmulation(const lldb_private::ArchSpec &arch, lldb_private::EmulateInstruction *inst_emulator) : UnwindAssembly(arch), m_inst_emulator_ap(inst_emulator), - m_range_ptr(NULL), m_thread_ptr(NULL), m_unwind_plan_ptr(NULL), - m_curr_row(), m_cfa_reg_info(), m_fp_is_cfa(false), m_register_values(), + m_range_ptr(NULL), m_unwind_plan_ptr(NULL), m_curr_row(), + m_cfa_reg_info(), m_fp_is_cfa(false), m_register_values(), m_pushed_regs(), m_curr_row_modified(false), m_forward_branch_offset(0) { if (m_inst_emulator_ap.get()) { @@ -130,7 +135,6 @@ private: std::unique_ptr<lldb_private::EmulateInstruction> m_inst_emulator_ap; lldb_private::AddressRange *m_range_ptr; - lldb_private::Thread *m_thread_ptr; lldb_private::UnwindPlan *m_unwind_plan_ptr; lldb_private::UnwindPlan::RowSP m_curr_row; typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap; Modified: lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt?rev=283847&r1=283846&r2=283847&view=diff ============================================================================== --- lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt (original) +++ lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt Mon Oct 10 21:24:00 2016 @@ -1 +1,2 @@ add_subdirectory(x86) +add_subdirectory(InstEmulation) Added: lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt?rev=283847&view=auto ============================================================================== --- lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt (added) +++ lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt Mon Oct 10 21:24:00 2016 @@ -0,0 +1 @@ +add_lldb_unittest(InstEmulationTests TestArm64InstEmulation.cpp) Added: lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp?rev=283847&view=auto ============================================================================== --- lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp (added) +++ lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp Mon Oct 10 21:24:00 2016 @@ -0,0 +1,166 @@ +//===-- TestArm64InstEmulation.cpp ------------------------------------*- C++ +//-*-===// + +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include <vector> + +#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" +#include "Utility/ARM64_DWARF_Registers.h" + +#include "lldb/Core/Address.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/UnwindAssembly.h" + +#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" +#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.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() { } + + // virtual void SetUp() override { } + + // virtual void TearDown() override { } + +protected: +}; + +static void init() { + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + DisassemblerLLVMC::Initialize(); + EmulateInstructionARM64::Initialize(); +} + +static void terminate() { + DisassemblerLLVMC::Terminate(); + EmulateInstructionARM64::Terminate(); +} + +TEST_F(TestArm64InstEmulation, TestSimpleFunction) { + + init(); + + ArchSpec arch("arm64-apple-ios10", nullptr); + UnwindAssemblyInstEmulation *engine = + static_cast<UnwindAssemblyInstEmulation *>( + UnwindAssemblyInstEmulation::CreateInstance(arch)); + EXPECT_TRUE(engine != nullptr); + if (engine == nullptr) + return; + + UnwindPlan::RowSP row_sp; + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + UnwindPlan::Row::RegisterLocation regloc; + + // 'int main() { }' compiled for arm64-apple-macosx with clang + 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> + + // But this is missing the setup of the frame pointer register (x29) and + // restore of the same. This is a bug in the instruction profiler -- + // it won't work if we have a stack frame with a variable length array, or + // an alloca style call where the stack frame size is not fixed. We need + // to recognize the setup of the frame pointer register. + + 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); + EXPECT_EQ(0, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == arm64_dwarf::sp); + 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); + EXPECT_EQ(4, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == arm64_dwarf::sp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::fp, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-16, regloc.GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::lr, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); + + // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8] + row_sp = unwind_plan.GetRowForFunctionOffset(8); + EXPECT_EQ(8, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == arm64_dwarf::fp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::fp, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-16, regloc.GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::lr, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); + + // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8] + row_sp = unwind_plan.GetRowForFunctionOffset(16); + EXPECT_EQ(16, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == arm64_dwarf::sp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::fp, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-16, regloc.GetOffset()); + + EXPECT_TRUE(row_sp->GetRegisterInfo(arm64_dwarf::lr, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); + + // CFA=sp +0 => fp= <same> lr= <same> + row_sp = unwind_plan.GetRowForFunctionOffset(20); + EXPECT_EQ(20, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == arm64_dwarf::sp); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); + + terminate(); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits