================ @@ -0,0 +1,188 @@ +//===-- TestRiscvInstEmulation.cpp ----------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" + +#include "lldb/Core/AddressRange.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Utility/ArchSpec.h" + +#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h" +#include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h" +#include "Plugins/Process/Utility/lldb-riscv-register-enums.h" +#include "llvm/Support/TargetSelect.h" + +using namespace lldb; +using namespace lldb_private; + +class TestRiscvInstEmulation : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + +protected: +}; + +void TestRiscvInstEmulation::SetUpTestCase() { + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + DisassemblerLLVMC::Initialize(); + EmulateInstructionRISCV::Initialize(); +} + +void TestRiscvInstEmulation::TearDownTestCase() { + DisassemblerLLVMC::Terminate(); + EmulateInstructionRISCV::Terminate(); +} + +TEST_F(TestRiscvInstEmulation, TestSimpleRiscvFunction) { + ArchSpec arch("riscv64-unknown-linux-gnu"); + // Enable compressed instruction support (RVC extension) + arch.SetFlags(ArchSpec::eRISCV_rvc); + std::unique_ptr<UnwindAssemblyInstEmulation> engine( + static_cast<UnwindAssemblyInstEmulation *>( + UnwindAssemblyInstEmulation::CreateInstance(arch))); + ASSERT_NE(nullptr, engine); + + // RISC-V function with compressed and uncompressed instructions + // 0x0000: 1141 addi sp, sp, -0x10 + // 0x0002: e406 sd ra, 0x8(sp) + // 0x0004: e022 sd s0, 0x0(sp) + // 0x0006: 0800 addi s0, sp, 0x10 + // 0x0008: 00000537 lui a0, 0x0 + // 0x000C: 00050513 mv a0, a0 + // 0x0010: 00000097 auipc ra, 0x0 + // 0x0014: 000080e7 jalr ra <main+0x10> + // 0x0018: 4501 li a0, 0x0 + // 0x001A: ff040113 addi sp, s0, -0x10 + // 0x001E: 60a2 ld ra, 0x8(sp) + // 0x0020: 6402 ld s0, 0x0(sp) + // 0x0022: 0141 addi sp, sp, 0x10 + // 0x0024: 8082 ret + uint8_t data[] = {// 0x0000: 1141 addi sp, sp, -0x10 + 0x41, 0x11, + // 0x0002: e406 sd ra, 0x8(sp) + 0x06, 0xE4, + // 0x0004: e022 sd s0, 0x0(sp) + 0x22, 0xE0, + // 0x0006: 0800 addi s0, sp, 0x10 + 0x00, 0x08, + // 0x0008: 00000537 lui a0, 0x0 + 0x37, 0x05, 0x00, 0x00, + // 0x000C: 00050513 mv a0, a0 + 0x13, 0x05, 0x05, 0x00, + // 0x0010: 00000097 auipc ra, 0x0 + 0x97, 0x00, 0x00, 0x00, + // 0x0014: 000080e7 jalr ra <main+0x10> + 0xE7, 0x80, 0x00, 0x00, + // 0x0018: 4501 li a0, 0x0 + 0x01, 0x45, + // 0x001A: ff040113 addi sp, s0, -0x10 + 0x13, 0x01, 0x04, 0xFF, + // 0x001E: 60a2 ld ra, 0x8(sp) + 0xA2, 0x60, + // 0x0020: 6402 ld s0, 0x0(sp) + 0x02, 0x64, + // 0x0022: 0141 addi sp, sp, 0x10 + 0x41, 0x01, + // 0x0024: 8082 ret + 0x82, 0x80}; + + // Expected UnwindPlan (prologue only - emulation stops after frame setup): + // row[0]: 0: CFA=sp+0 => fp= <same> ra= <same> + // row[1]: 2: CFA=sp+16 => fp= <same> ra= <same> (after stack + // allocation) row[2]: 4: CFA=sp+16 => fp= <same> ra=[CFA-8] + // (after saving ra) row[3]: 6: CFA=sp+16 => fp=[CFA-16] ra=[CFA-8] + // (after saving s0/fp) row[4]: 8: CFA=s0+0 => fp=[CFA-16] ra=[CFA-8] + // (after setting frame pointer: s0=sp+16) + + const UnwindPlan::Row *row; + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + UnwindPlan::Row::AbstractRegisterLocation regloc; + sample_range = AddressRange(0x1000, sizeof(data)); + + EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( + sample_range, data, sizeof(data), unwind_plan)); + + // CFA=sp+0 => fp=<same> ra=<same> + row = unwind_plan.GetRowForFunctionOffset(0); + EXPECT_EQ(0, row->GetOffset()); + EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_riscv); + EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(0, row->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_riscv, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_ra_riscv, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + // CFA=sp+16 => fp=<same> ra=<same> + row = unwind_plan.GetRowForFunctionOffset(2); + EXPECT_EQ(2, row->GetOffset()); + EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_riscv); + EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_riscv, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_ra_riscv, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + // CFA=sp+16 => fp=<same> ra=[CFA-8] + row = unwind_plan.GetRowForFunctionOffset(4); + EXPECT_EQ(4, row->GetOffset()); + EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_riscv); + EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_riscv, regloc)); + EXPECT_TRUE(regloc.IsSame()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_ra_riscv, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); + + // CFA=sp+16 => fp=[CFA-16] ra=[CFA-8] + row = unwind_plan.GetRowForFunctionOffset(6); + EXPECT_EQ(6, row->GetOffset()); + EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_sp_riscv); + EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_riscv, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-16, regloc.GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_ra_riscv, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); + + // CFA=s0+0 => fp=[CFA-16] ra=[CFA-8] + // s0 = sp + 16, so switching CFA to s0 does not change the effective + // locations. + row = unwind_plan.GetRowForFunctionOffset(8); + EXPECT_EQ(8, row->GetOffset()); + EXPECT_TRUE(row->GetCFAValue().GetRegisterNumber() == gpr_fp_riscv); + EXPECT_TRUE(row->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(0, row->GetCFAValue().GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_fp_riscv, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-16, regloc.GetOffset()); + + EXPECT_TRUE(row->GetRegisterInfo(gpr_ra_riscv, regloc)); + EXPECT_TRUE(regloc.IsAtCFAPlusOffset()); + EXPECT_EQ(-8, regloc.GetOffset()); +} ---------------- JDevlieghere wrote:
Missing newline https://github.com/llvm/llvm-project/pull/158161 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits