https://github.com/barsolo2000 updated https://github.com/llvm/llvm-project/pull/158161
>From 827f68dcc9b6e207ff324f1be353561ee10892d1 Mon Sep 17 00:00:00 2001 From: Bar Soloveychik <bars...@fb.com> Date: Thu, 11 Sep 2025 14:06:05 -0700 Subject: [PATCH 1/5] RISCV unwinding enable --- lldb/include/lldb/Core/Opcode.h | 4 +- .../RISCV/EmulateInstructionRISCV.cpp | 165 +++++++++++++-- .../RISCV/EmulateInstructionRISCV.h | 4 + lldb/unittests/Instruction/CMakeLists.txt | 5 + .../RISCV/TestRiscvInstEmulation.cpp | 194 ++++++++++++++++++ 5 files changed, 359 insertions(+), 13 deletions(-) create mode 100644 lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp diff --git a/lldb/include/lldb/Core/Opcode.h b/lldb/include/lldb/Core/Opcode.h index 7bbd73d039f99..7e756d3f15d22 100644 --- a/lldb/include/lldb/Core/Opcode.h +++ b/lldb/include/lldb/Core/Opcode.h @@ -223,7 +223,9 @@ class Opcode { int Dump(Stream *s, uint32_t min_byte_width) const; const void *GetOpcodeBytes() const { - return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr); + return ((m_type == Opcode::eTypeBytes || m_type == Opcode::eType16_32Tuples) + ? m_data.inst.bytes + : nullptr); } uint32_t GetByteSize() const { diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp index 5e429a92613ce..7a56dcaa2f2db 100644 --- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -230,10 +230,36 @@ Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) { auto addr = LoadStoreAddr(emulator, inst); if (!addr) return false; - return transformOptional( - emulator.ReadMem<T>(*addr), - [&](T t) { return inst.rd.Write(emulator, extend(E(t))); }) - .value_or(false); + + // Set up context for the load operation, similar to ARM64 + EmulateInstructionRISCV::Context context; + + // Get register info for base register + uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs); + std::optional<RegisterInfo> reg_info_rs1 = + emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb); + + if (!reg_info_rs1) + return false; + + // Set context type based on whether this is a stack-based load + if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V + context.type = EmulateInstruction::eContextPopRegisterOffStack; + } else { + context.type = EmulateInstruction::eContextRegisterLoad; + } + + // Set the context address information + context.SetAddress(*addr); + + // Read from memory with context and write to register + bool success = false; + uint64_t value = + emulator.ReadMemoryUnsigned(context, *addr, sizeof(T), 0, &success); + if (!success) + return false; + + return inst.rd.Write(emulator, extend(E(T(value)))); } template <typename I, typename T> @@ -242,9 +268,38 @@ Store(EmulateInstructionRISCV &emulator, I inst) { auto addr = LoadStoreAddr(emulator, inst); if (!addr) return false; - return transformOptional( - inst.rs2.Read(emulator), - [&](uint64_t rs2) { return emulator.WriteMem<T>(*addr, rs2); }) + + // Set up context for the store operation, similar to ARM64 + EmulateInstructionRISCV::Context context; + + // Get register info for source and base registers + uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs); + uint32_t rs2_lldb = GPREncodingToLLDB(inst.rs2.rs); + std::optional<RegisterInfo> reg_info_rs1 = + emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb); + std::optional<RegisterInfo> reg_info_rs2 = + emulator.GetRegisterInfo(eRegisterKindLLDB, rs2_lldb); + + if (!reg_info_rs1 || !reg_info_rs2) + return false; + + // Set context type based on whether this is a stack-based store + if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V + context.type = EmulateInstruction::eContextPushRegisterOnStack; + } else { + context.type = EmulateInstruction::eContextRegisterStore; + } + + // Set the context to show which register is being stored to which base + // register + offset + context.SetRegisterToRegisterPlusOffset(*reg_info_rs2, *reg_info_rs1, + SignExt(inst.imm)); + + return transformOptional(inst.rs2.Read(emulator), + [&](uint64_t rs2) { + return emulator.WriteMemoryUnsigned( + context, *addr, rs2, sizeof(T)); + }) .value_or(false); } @@ -737,11 +792,42 @@ class Executor { bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); } bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); } bool operator()(ADDI inst) { - return transformOptional(inst.rs1.ReadI64(m_emu), - [&](int64_t rs1) { - return inst.rd.Write( - m_emu, rs1 + int64_t(SignExt(inst.imm))); - }) + return transformOptional( + inst.rs1.ReadI64(m_emu), + [&](int64_t rs1) { + int64_t result = rs1 + int64_t(SignExt(inst.imm)); + // Check if this is a stack pointer adjustment + if (inst.rd.rd == 2 && inst.rs1.rs == 2) { // rd=sp, rs1=sp + EmulateInstruction::Context context; + context.type = + EmulateInstruction::eContextAdjustStackPointer; + context.SetImmediateSigned(SignExt(inst.imm)); + uint32_t sp_lldb_reg = GPREncodingToLLDB(2); + RegisterValue registerValue; + registerValue.SetUInt64(result); + return m_emu.WriteRegister(context, eRegisterKindLLDB, + sp_lldb_reg, registerValue); + } + // Check if this is setting up the frame pointer + // addi fp, sp, imm -> fp = sp + imm (frame pointer setup) + if (inst.rd.rd == 8 && inst.rs1.rs == 2) { // rd=fp, rs1=sp + EmulateInstruction::Context context; + context.type = EmulateInstruction::eContextSetFramePointer; + auto sp_reg_info = m_emu.GetRegisterInfo( + eRegisterKindLLDB, GPREncodingToLLDB(2)); + if (sp_reg_info) { + context.SetRegisterPlusOffset(*sp_reg_info, + SignExt(inst.imm)); + } + uint32_t fp_lldb_reg = GPREncodingToLLDB(8); + RegisterValue registerValue; + registerValue.SetUInt64(result); + return m_emu.WriteRegister(context, eRegisterKindLLDB, + fp_lldb_reg, registerValue); + } + // Regular ADDI instruction + return inst.rd.Write(m_emu, result); + }) .value_or(false); } bool operator()(SLTI inst) { @@ -1745,6 +1831,61 @@ EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind, return array[reg_index]; } +bool EmulateInstructionRISCV::SetInstruction(const Opcode &opcode, + const Address &inst_addr, + Target *target) { + // Call the base class implementation + if (!EmulateInstruction::SetInstruction(opcode, inst_addr, target)) + return false; + + // Extract instruction data from the opcode + uint32_t inst_data = 0; + const void *opcode_data = m_opcode.GetOpcodeBytes(); + if (!opcode_data) + return false; + + if (m_opcode.GetByteSize() == 2) { + // 16-bit compressed instruction + const uint16_t *data = static_cast<const uint16_t *>(opcode_data); + inst_data = *data; + } else if (m_opcode.GetByteSize() == 4) { + // 32-bit instruction + const uint32_t *data = static_cast<const uint32_t *>(opcode_data); + inst_data = *data; + } else { + return false; + } + + // Decode the instruction + auto decoded_inst = Decode(inst_data); + if (!decoded_inst) + return false; + + // Store the decoded result + m_decoded = *decoded_inst; + return true; +} + +bool EmulateInstructionRISCV::CreateFunctionEntryUnwind( + UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + unwind_plan.SetRegisterKind(eRegisterKindLLDB); + + UnwindPlan::Row row; + + row.GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_riscv, 0); + row.SetRegisterLocationToSame(gpr_ra_riscv, /*must_replace=*/false); + row.SetRegisterLocationToSame(gpr_fp_riscv, /*must_replace=*/false); + + unwind_plan.AppendRow(std::move(row)); + unwind_plan.SetSourceName("EmulateInstructionRISCV"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); + unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); + unwind_plan.SetReturnAddressRegister(gpr_ra_riscv); + return true; +} + bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) { return SupportsThisArch(arch); } diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h index 3578a4ab03053..c196a9bb9ce82 100644 --- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h +++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h @@ -61,6 +61,7 @@ class EmulateInstructionRISCV : public EmulateInstruction { case eInstructionTypePCModifying: return true; case eInstructionTypePrologueEpilogue: + return true; case eInstructionTypeAll: return false; } @@ -85,6 +86,7 @@ class EmulateInstructionRISCV : public EmulateInstruction { return SupportsThisInstructionType(inst_type); } + bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) override; bool SetTargetTriple(const ArchSpec &arch) override; bool ReadInstruction() override; std::optional<uint32_t> GetLastInstrSize() override { return m_last_size; } @@ -94,6 +96,8 @@ class EmulateInstructionRISCV : public EmulateInstruction { std::optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num) override; + bool SetInstruction(const Opcode &opcode, const Address &inst_addr, + Target *target) override; std::optional<DecodeResult> ReadInstructionAt(lldb::addr_t addr); std::optional<DecodeResult> Decode(uint32_t inst); bool Execute(DecodeResult inst, bool ignore_cond); diff --git a/lldb/unittests/Instruction/CMakeLists.txt b/lldb/unittests/Instruction/CMakeLists.txt index 10385377923ba..6a35b1c5b02d6 100644 --- a/lldb/unittests/Instruction/CMakeLists.txt +++ b/lldb/unittests/Instruction/CMakeLists.txt @@ -2,9 +2,11 @@ add_lldb_unittest(EmulatorTests ARM64/TestAArch64Emulator.cpp LoongArch/TestLoongArchEmulator.cpp RISCV/TestRISCVEmulator.cpp + RISCV/TestRiscvInstEmulation.cpp LINK_COMPONENTS Support + ${LLVM_TARGETS_TO_BUILD} LINK_LIBS lldbCore lldbSymbol @@ -12,4 +14,7 @@ add_lldb_unittest(EmulatorTests lldbPluginInstructionARM64 lldbPluginInstructionLoongArch lldbPluginInstructionRISCV + lldbPluginDisassemblerLLVMC + lldbPluginUnwindAssemblyInstEmulation + lldbPluginProcessUtility ) diff --git a/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp new file mode 100644 index 0000000000000..00b76b4b057b5 --- /dev/null +++ b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp @@ -0,0 +1,194 @@ +//===-- 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(); + + // virtual void SetUp() override { } + // virtual void TearDown() override { } + +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); + + const UnwindPlan::Row *row; + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + UnwindPlan::Row::AbstractRegisterLocation regloc; + + // 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) + + // Debug: Print all rows in the unwind plan + + 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()); +} \ No newline at end of file >From ffe226ec99a1480c0235f5fdba3597fc21a153f6 Mon Sep 17 00:00:00 2001 From: Bar Soloveychik <bars...@fb.com> Date: Fri, 12 Sep 2025 10:00:10 -0700 Subject: [PATCH 2/5] fixed comments --- .../RISCV/EmulateInstructionRISCV.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp index 7a56dcaa2f2db..87bff4cfeda45 100644 --- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -33,6 +33,10 @@ LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionRISCV, InstructionRISCV) namespace lldb_private { +// RISC-V General Purpose Register numbers +static constexpr uint32_t RISCV_GPR_SP = 2; // x2 is the stack pointer +static constexpr uint32_t RISCV_GPR_FP = 8; // x8 is the frame pointer + /// Returns all values wrapped in Optional, or std::nullopt if any of the values /// is std::nullopt. template <typename... Ts> @@ -243,11 +247,10 @@ Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) { return false; // Set context type based on whether this is a stack-based load - if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V + if (inst.rs1.rs == RISCV_GPR_SP) // x2 is the stack pointer in RISC-V context.type = EmulateInstruction::eContextPopRegisterOffStack; - } else { + else context.type = EmulateInstruction::eContextRegisterLoad; - } // Set the context address information context.SetAddress(*addr); @@ -284,11 +287,10 @@ Store(EmulateInstructionRISCV &emulator, I inst) { return false; // Set context type based on whether this is a stack-based store - if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V + if (inst.rs1.rs == RISCV_GPR_SP) // x2 is the stack pointer in RISC-V context.type = EmulateInstruction::eContextPushRegisterOnStack; - } else { + else context.type = EmulateInstruction::eContextRegisterStore; - } // Set the context to show which register is being stored to which base // register + offset @@ -797,12 +799,13 @@ class Executor { [&](int64_t rs1) { int64_t result = rs1 + int64_t(SignExt(inst.imm)); // Check if this is a stack pointer adjustment - if (inst.rd.rd == 2 && inst.rs1.rs == 2) { // rd=sp, rs1=sp + if (inst.rd.rd == RISCV_GPR_SP && + inst.rs1.rs == RISCV_GPR_SP) { // rd=sp, rs1=sp EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned(SignExt(inst.imm)); - uint32_t sp_lldb_reg = GPREncodingToLLDB(2); + uint32_t sp_lldb_reg = GPREncodingToLLDB(RISCV_GPR_SP); RegisterValue registerValue; registerValue.SetUInt64(result); return m_emu.WriteRegister(context, eRegisterKindLLDB, @@ -810,16 +813,17 @@ class Executor { } // Check if this is setting up the frame pointer // addi fp, sp, imm -> fp = sp + imm (frame pointer setup) - if (inst.rd.rd == 8 && inst.rs1.rs == 2) { // rd=fp, rs1=sp + if (inst.rd.rd == RISCV_GPR_FP && + inst.rs1.rs == RISCV_GPR_SP) { // rd=fp, rs1=sp EmulateInstruction::Context context; context.type = EmulateInstruction::eContextSetFramePointer; auto sp_reg_info = m_emu.GetRegisterInfo( - eRegisterKindLLDB, GPREncodingToLLDB(2)); + eRegisterKindLLDB, GPREncodingToLLDB(RISCV_GPR_SP)); if (sp_reg_info) { context.SetRegisterPlusOffset(*sp_reg_info, SignExt(inst.imm)); } - uint32_t fp_lldb_reg = GPREncodingToLLDB(8); + uint32_t fp_lldb_reg = GPREncodingToLLDB(RISCV_GPR_FP); RegisterValue registerValue; registerValue.SetUInt64(result); return m_emu.WriteRegister(context, eRegisterKindLLDB, >From e664164041856d7ae605feccc8a5f990c309d68b Mon Sep 17 00:00:00 2001 From: Bar Soloveychik <bars...@fb.com> Date: Fri, 12 Sep 2025 10:15:06 -0700 Subject: [PATCH 3/5] added helper function --- .../RISCV/EmulateInstructionRISCV.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp index 87bff4cfeda45..36e6bd41ad7fa 100644 --- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -112,6 +112,14 @@ static uint32_t FPREncodingToLLDB(uint32_t reg_encode) { return LLDB_INVALID_REGNUM; } +// Helper function to get register info from GPR encoding +static std::optional<RegisterInfo> +GPREncodingToRegisterInfo(EmulateInstructionRISCV &emulator, + uint32_t reg_encode) { + uint32_t lldb_reg = GPREncodingToLLDB(reg_encode); + return emulator.GetRegisterInfo(eRegisterKindLLDB, lldb_reg); +} + bool Rd::Write(EmulateInstructionRISCV &emulator, uint64_t value) { uint32_t lldb_reg = GPREncodingToLLDB(rd); EmulateInstruction::Context ctx; @@ -239,9 +247,8 @@ Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) { EmulateInstructionRISCV::Context context; // Get register info for base register - uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs); std::optional<RegisterInfo> reg_info_rs1 = - emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb); + GPREncodingToRegisterInfo(emulator, inst.rs1.rs); if (!reg_info_rs1) return false; @@ -276,12 +283,10 @@ Store(EmulateInstructionRISCV &emulator, I inst) { EmulateInstructionRISCV::Context context; // Get register info for source and base registers - uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs); - uint32_t rs2_lldb = GPREncodingToLLDB(inst.rs2.rs); std::optional<RegisterInfo> reg_info_rs1 = - emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb); + GPREncodingToRegisterInfo(emulator, inst.rs1.rs); std::optional<RegisterInfo> reg_info_rs2 = - emulator.GetRegisterInfo(eRegisterKindLLDB, rs2_lldb); + GPREncodingToRegisterInfo(emulator, inst.rs2.rs); if (!reg_info_rs1 || !reg_info_rs2) return false; >From da1e4e3dcefcc42c674d89368545432b23ea6a22 Mon Sep 17 00:00:00 2001 From: Bar Soloveychik <bars...@fb.com> Date: Fri, 12 Sep 2025 10:28:37 -0700 Subject: [PATCH 4/5] fixed test comments --- .../Instruction/RISCV/TestRiscvInstEmulation.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp index 00b76b4b057b5..2183e6881ac5d 100644 --- a/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp +++ b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp @@ -27,9 +27,6 @@ class TestRiscvInstEmulation : public testing::Test { static void SetUpTestCase(); static void TearDownTestCase(); - // virtual void SetUp() override { } - // virtual void TearDown() override { } - protected: }; @@ -56,11 +53,6 @@ TEST_F(TestRiscvInstEmulation, TestSimpleRiscvFunction) { UnwindAssemblyInstEmulation::CreateInstance(arch))); ASSERT_NE(nullptr, engine); - const UnwindPlan::Row *row; - AddressRange sample_range; - UnwindPlan unwind_plan(eRegisterKindLLDB); - UnwindPlan::Row::AbstractRegisterLocation regloc; - // RISC-V function with compressed and uncompressed instructions // 0x0000: 1141 addi sp, sp, -0x10 // 0x0002: e406 sd ra, 0x8(sp) @@ -113,8 +105,11 @@ TEST_F(TestRiscvInstEmulation, TestSimpleRiscvFunction) { // (after saving s0/fp) row[4]: 8: CFA=s0+0 => fp=[CFA-16] ra=[CFA-8] // (after setting frame pointer: s0=sp+16) - // Debug: Print all rows in the unwind plan + 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( >From 50b2c455941b2872ca188758cd228f2e63504514 Mon Sep 17 00:00:00 2001 From: Bar Soloveychik <bars...@fb.com> Date: Fri, 12 Sep 2025 10:34:08 -0700 Subject: [PATCH 5/5] format --- lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp index 2183e6881ac5d..7d9344df77465 100644 --- a/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp +++ b/lldb/unittests/Instruction/RISCV/TestRiscvInstEmulation.cpp @@ -105,7 +105,6 @@ TEST_F(TestRiscvInstEmulation, TestSimpleRiscvFunction) { // (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); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits