Skip to content

Commit ee3cadc

Browse files
author
Bar Soloveychik
committed
RISCV unwinding enable
1 parent ef7de8d commit ee3cadc

File tree

5 files changed

+359
-13
lines changed

5 files changed

+359
-13
lines changed

lldb/include/lldb/Core/Opcode.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ class Opcode {
223223
int Dump(Stream *s, uint32_t min_byte_width) const;
224224

225225
const void *GetOpcodeBytes() const {
226-
return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr);
226+
return ((m_type == Opcode::eTypeBytes || m_type == Opcode::eType16_32Tuples)
227+
? m_data.inst.bytes
228+
: nullptr);
227229
}
228230

229231
uint32_t GetByteSize() const {

lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp

Lines changed: 153 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,36 @@ Load(EmulateInstructionRISCV &emulator, I inst, uint64_t (*extend)(E)) {
230230
auto addr = LoadStoreAddr(emulator, inst);
231231
if (!addr)
232232
return false;
233-
return transformOptional(
234-
emulator.ReadMem<T>(*addr),
235-
[&](T t) { return inst.rd.Write(emulator, extend(E(t))); })
236-
.value_or(false);
233+
234+
// Set up context for the load operation, similar to ARM64
235+
EmulateInstructionRISCV::Context context;
236+
237+
// Get register info for base register
238+
uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs);
239+
std::optional<RegisterInfo> reg_info_rs1 =
240+
emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb);
241+
242+
if (!reg_info_rs1)
243+
return false;
244+
245+
// Set context type based on whether this is a stack-based load
246+
if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V
247+
context.type = EmulateInstruction::eContextPopRegisterOffStack;
248+
} else {
249+
context.type = EmulateInstruction::eContextRegisterLoad;
250+
}
251+
252+
// Set the context address information
253+
context.SetAddress(*addr);
254+
255+
// Read from memory with context and write to register
256+
bool success = false;
257+
uint64_t value =
258+
emulator.ReadMemoryUnsigned(context, *addr, sizeof(T), 0, &success);
259+
if (!success)
260+
return false;
261+
262+
return inst.rd.Write(emulator, extend(E(T(value))));
237263
}
238264

239265
template <typename I, typename T>
@@ -242,9 +268,38 @@ Store(EmulateInstructionRISCV &emulator, I inst) {
242268
auto addr = LoadStoreAddr(emulator, inst);
243269
if (!addr)
244270
return false;
245-
return transformOptional(
246-
inst.rs2.Read(emulator),
247-
[&](uint64_t rs2) { return emulator.WriteMem<T>(*addr, rs2); })
271+
272+
// Set up context for the store operation, similar to ARM64
273+
EmulateInstructionRISCV::Context context;
274+
275+
// Get register info for source and base registers
276+
uint32_t rs1_lldb = GPREncodingToLLDB(inst.rs1.rs);
277+
uint32_t rs2_lldb = GPREncodingToLLDB(inst.rs2.rs);
278+
std::optional<RegisterInfo> reg_info_rs1 =
279+
emulator.GetRegisterInfo(eRegisterKindLLDB, rs1_lldb);
280+
std::optional<RegisterInfo> reg_info_rs2 =
281+
emulator.GetRegisterInfo(eRegisterKindLLDB, rs2_lldb);
282+
283+
if (!reg_info_rs1 || !reg_info_rs2)
284+
return false;
285+
286+
// Set context type based on whether this is a stack-based store
287+
if (inst.rs1.rs == 2) { // x2 is the stack pointer in RISC-V
288+
context.type = EmulateInstruction::eContextPushRegisterOnStack;
289+
} else {
290+
context.type = EmulateInstruction::eContextRegisterStore;
291+
}
292+
293+
// Set the context to show which register is being stored to which base
294+
// register + offset
295+
context.SetRegisterToRegisterPlusOffset(*reg_info_rs2, *reg_info_rs1,
296+
SignExt(inst.imm));
297+
298+
return transformOptional(inst.rs2.Read(emulator),
299+
[&](uint64_t rs2) {
300+
return emulator.WriteMemoryUnsigned(
301+
context, *addr, rs2, sizeof(T));
302+
})
248303
.value_or(false);
249304
}
250305

@@ -737,11 +792,42 @@ class Executor {
737792
bool operator()(SH inst) { return Store<SH, uint16_t>(m_emu, inst); }
738793
bool operator()(SW inst) { return Store<SW, uint32_t>(m_emu, inst); }
739794
bool operator()(ADDI inst) {
740-
return transformOptional(inst.rs1.ReadI64(m_emu),
741-
[&](int64_t rs1) {
742-
return inst.rd.Write(
743-
m_emu, rs1 + int64_t(SignExt(inst.imm)));
744-
})
795+
return transformOptional(
796+
inst.rs1.ReadI64(m_emu),
797+
[&](int64_t rs1) {
798+
int64_t result = rs1 + int64_t(SignExt(inst.imm));
799+
// Check if this is a stack pointer adjustment
800+
if (inst.rd.rd == 2 && inst.rs1.rs == 2) { // rd=sp, rs1=sp
801+
EmulateInstruction::Context context;
802+
context.type =
803+
EmulateInstruction::eContextAdjustStackPointer;
804+
context.SetImmediateSigned(SignExt(inst.imm));
805+
uint32_t sp_lldb_reg = GPREncodingToLLDB(2);
806+
RegisterValue registerValue;
807+
registerValue.SetUInt64(result);
808+
return m_emu.WriteRegister(context, eRegisterKindLLDB,
809+
sp_lldb_reg, registerValue);
810+
}
811+
// Check if this is setting up the frame pointer
812+
// addi fp, sp, imm -> fp = sp + imm (frame pointer setup)
813+
if (inst.rd.rd == 8 && inst.rs1.rs == 2) { // rd=fp, rs1=sp
814+
EmulateInstruction::Context context;
815+
context.type = EmulateInstruction::eContextSetFramePointer;
816+
auto sp_reg_info = m_emu.GetRegisterInfo(
817+
eRegisterKindLLDB, GPREncodingToLLDB(2));
818+
if (sp_reg_info) {
819+
context.SetRegisterPlusOffset(*sp_reg_info,
820+
SignExt(inst.imm));
821+
}
822+
uint32_t fp_lldb_reg = GPREncodingToLLDB(8);
823+
RegisterValue registerValue;
824+
registerValue.SetUInt64(result);
825+
return m_emu.WriteRegister(context, eRegisterKindLLDB,
826+
fp_lldb_reg, registerValue);
827+
}
828+
// Regular ADDI instruction
829+
return inst.rd.Write(m_emu, result);
830+
})
745831
.value_or(false);
746832
}
747833
bool operator()(SLTI inst) {
@@ -1745,6 +1831,61 @@ EmulateInstructionRISCV::GetRegisterInfo(RegisterKind reg_kind,
17451831
return array[reg_index];
17461832
}
17471833

1834+
bool EmulateInstructionRISCV::SetInstruction(const Opcode &opcode,
1835+
const Address &inst_addr,
1836+
Target *target) {
1837+
// Call the base class implementation
1838+
if (!EmulateInstruction::SetInstruction(opcode, inst_addr, target))
1839+
return false;
1840+
1841+
// Extract instruction data from the opcode
1842+
uint32_t inst_data = 0;
1843+
const void *opcode_data = m_opcode.GetOpcodeBytes();
1844+
if (!opcode_data)
1845+
return false;
1846+
1847+
if (m_opcode.GetByteSize() == 2) {
1848+
// 16-bit compressed instruction
1849+
const uint16_t *data = static_cast<const uint16_t *>(opcode_data);
1850+
inst_data = *data;
1851+
} else if (m_opcode.GetByteSize() == 4) {
1852+
// 32-bit instruction
1853+
const uint32_t *data = static_cast<const uint32_t *>(opcode_data);
1854+
inst_data = *data;
1855+
} else {
1856+
return false;
1857+
}
1858+
1859+
// Decode the instruction
1860+
auto decoded_inst = Decode(inst_data);
1861+
if (!decoded_inst)
1862+
return false;
1863+
1864+
// Store the decoded result
1865+
m_decoded = *decoded_inst;
1866+
return true;
1867+
}
1868+
1869+
bool EmulateInstructionRISCV::CreateFunctionEntryUnwind(
1870+
UnwindPlan &unwind_plan) {
1871+
unwind_plan.Clear();
1872+
unwind_plan.SetRegisterKind(eRegisterKindLLDB);
1873+
1874+
UnwindPlan::Row row;
1875+
1876+
row.GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_riscv, 0);
1877+
row.SetRegisterLocationToSame(gpr_ra_riscv, /*must_replace=*/false);
1878+
row.SetRegisterLocationToSame(gpr_fp_riscv, /*must_replace=*/false);
1879+
1880+
unwind_plan.AppendRow(std::move(row));
1881+
unwind_plan.SetSourceName("EmulateInstructionRISCV");
1882+
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1883+
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
1884+
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1885+
unwind_plan.SetReturnAddressRegister(gpr_ra_riscv);
1886+
return true;
1887+
}
1888+
17481889
bool EmulateInstructionRISCV::SetTargetTriple(const ArchSpec &arch) {
17491890
return SupportsThisArch(arch);
17501891
}

lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class EmulateInstructionRISCV : public EmulateInstruction {
6161
case eInstructionTypePCModifying:
6262
return true;
6363
case eInstructionTypePrologueEpilogue:
64+
return true;
6465
case eInstructionTypeAll:
6566
return false;
6667
}
@@ -85,6 +86,7 @@ class EmulateInstructionRISCV : public EmulateInstruction {
8586
return SupportsThisInstructionType(inst_type);
8687
}
8788

89+
bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) override;
8890
bool SetTargetTriple(const ArchSpec &arch) override;
8991
bool ReadInstruction() override;
9092
std::optional<uint32_t> GetLastInstrSize() override { return m_last_size; }
@@ -94,6 +96,8 @@ class EmulateInstructionRISCV : public EmulateInstruction {
9496
std::optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind,
9597
uint32_t reg_num) override;
9698

99+
bool SetInstruction(const Opcode &opcode, const Address &inst_addr,
100+
Target *target) override;
97101
std::optional<DecodeResult> ReadInstructionAt(lldb::addr_t addr);
98102
std::optional<DecodeResult> Decode(uint32_t inst);
99103
bool Execute(DecodeResult inst, bool ignore_cond);

lldb/unittests/Instruction/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ add_lldb_unittest(EmulatorTests
22
ARM64/TestAArch64Emulator.cpp
33
LoongArch/TestLoongArchEmulator.cpp
44
RISCV/TestRISCVEmulator.cpp
5+
RISCV/TestRiscvInstEmulation.cpp
56

67
LINK_COMPONENTS
78
Support
9+
${LLVM_TARGETS_TO_BUILD}
810
LINK_LIBS
911
lldbCore
1012
lldbSymbol
1113
lldbTarget
1214
lldbPluginInstructionARM64
1315
lldbPluginInstructionLoongArch
1416
lldbPluginInstructionRISCV
17+
lldbPluginDisassemblerLLVMC
18+
lldbPluginUnwindAssemblyInstEmulation
19+
lldbPluginProcessUtility
1520
)

0 commit comments

Comments
 (0)