Skip to content

Commit 8712140

Browse files
authored
[lldb][RISCV] function calls support in lldb expressions (#99336)
[lldb][RISCV] add jitted function calls to ABI Function calls support in LLDB expressions for RISCV: 1 of 4 Augments corresponding functionality to RISCV ABI, which allows to jit lldb expressions and thus make function calls inside them. Only function calls with integer and void function arguments and return value are supported. [lldb][RISCV] add JIT relocations resolver Function calls support in LLDB expressions for RISCV: 2 of 4 Adds required RISCV relocations resolving functionality in lldb ExecutionEngine. [lldb][RISCV] RISC-V large code model in lldb expressions Function calls support in LLDB expressions for RISCV: 3 of 4 This patch sets large code model in MCJIT settings for RISC-V 64-bit targets that allows to make assembly jumps at any 64bit address. This is needed, because resulted jitted code may contain more that +-2GB jumps, that are not available in RISC-V with medium code model. [lldb][RISCV] doubles support in lldb expressions Function calls support in LLDB expressions for RISCV: 4 of 4 This patch adds desired feature flags in MCJIT compiler to enable hard-float instructions if target supports them and allows to use floats and doubles in lldb expressions.
1 parent e64ef74 commit 8712140

File tree

5 files changed

+301
-24
lines changed

5 files changed

+301
-24
lines changed

lldb/source/Expression/IRExecutionUnit.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr,
277277
.setMCJITMemoryManager(std::make_unique<MemoryManager>(*this))
278278
.setOptLevel(llvm::CodeGenOptLevel::Less);
279279

280+
// Resulted jitted code can be placed too far from the code in the binary
281+
// and thus can contain more than +-2GB jumps, that are not available
282+
// in RISC-V without large code model.
283+
if (triple.isRISCV64())
284+
builder.setCodeModel(llvm::CodeModel::Large);
285+
280286
llvm::StringRef mArch;
281287
llvm::StringRef mCPU;
282288
llvm::SmallVector<std::string, 0> mAttrs;

lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
#include <array>
1212
#include <limits>
13+
#include <sstream>
1314

15+
#include "llvm/ADT/STLExtras.h"
1416
#include "llvm/IR/DerivedTypes.h"
1517

1618
#include "Utility/RISCV_DWARF_Registers.h"
@@ -20,6 +22,7 @@
2022
#include "lldb/Target/RegisterContext.h"
2123
#include "lldb/Target/StackFrame.h"
2224
#include "lldb/Target/Thread.h"
25+
#include "lldb/Utility/LLDBLog.h"
2326
#include "lldb/Utility/RegisterValue.h"
2427

2528
#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()
@@ -120,6 +123,10 @@ static const std::array<RegisterInfo, 33> g_register_infos = {
120123
} // namespace dwarf
121124
} // namespace
122125

126+
// Number of argument registers (the base integer calling convention
127+
// provides 8 argument registers, a0-a7)
128+
static constexpr size_t g_regs_for_args_count = 8U;
129+
123130
const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) {
124131
count = dwarf::g_register_infos.size();
125132
return dwarf::g_register_infos.data();
@@ -164,11 +171,81 @@ TotalArgsSizeInWords(bool is_rv64,
164171
return total_size;
165172
}
166173

174+
static bool UpdateRegister(RegisterContext *reg_ctx,
175+
const lldb::RegisterKind reg_kind,
176+
const uint32_t reg_num, const addr_t value) {
177+
Log *log = GetLog(LLDBLog::Expressions);
178+
179+
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(reg_kind, reg_num);
180+
181+
LLDB_LOG(log, "Writing {0}: 0x{1:x}", reg_info->name,
182+
static_cast<uint64_t>(value));
183+
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) {
184+
LLDB_LOG(log, "Writing {0}: failed", reg_info->name);
185+
return false;
186+
}
187+
return true;
188+
}
189+
190+
static void LogInitInfo(Log &log, const Thread &thread, addr_t sp,
191+
addr_t func_addr, addr_t return_addr,
192+
const llvm::ArrayRef<addr_t> args) {
193+
std::stringstream ss;
194+
ss << "ABISysV_riscv::PrepareTrivialCall"
195+
<< " (tid = 0x" << std::hex << thread.GetID() << ", sp = 0x" << sp
196+
<< ", func_addr = 0x" << func_addr << ", return_addr = 0x" << return_addr;
197+
198+
for (auto [idx, arg] : enumerate(args))
199+
ss << ", arg" << std::dec << idx << " = 0x" << std::hex << arg;
200+
ss << ")";
201+
log.PutString(ss.str());
202+
}
203+
167204
bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp,
168205
addr_t func_addr, addr_t return_addr,
169206
llvm::ArrayRef<addr_t> args) const {
170-
// TODO: Implement
171-
return false;
207+
Log *log = GetLog(LLDBLog::Expressions);
208+
if (log)
209+
LogInitInfo(*log, thread, sp, func_addr, return_addr, args);
210+
211+
const auto reg_ctx_sp = thread.GetRegisterContext();
212+
if (!reg_ctx_sp) {
213+
LLDB_LOG(log, "Failed to get RegisterContext");
214+
return false;
215+
}
216+
217+
if (args.size() > g_regs_for_args_count) {
218+
LLDB_LOG(log, "Function has {0} arguments, but only {1} are allowed!",
219+
args.size(), g_regs_for_args_count);
220+
return false;
221+
}
222+
223+
// Write arguments to registers
224+
for (auto [idx, arg] : enumerate(args)) {
225+
const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(
226+
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + idx);
227+
LLDB_LOG(log, "About to write arg{0} (0x{1:x}) into {2}", idx, arg,
228+
reg_info->name);
229+
230+
if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, arg)) {
231+
LLDB_LOG(log, "Failed to write arg{0} (0x{1:x}) into {2}", idx, arg,
232+
reg_info->name);
233+
return false;
234+
}
235+
}
236+
237+
if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
238+
LLDB_REGNUM_GENERIC_PC, func_addr))
239+
return false;
240+
if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
241+
LLDB_REGNUM_GENERIC_SP, sp))
242+
return false;
243+
if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
244+
LLDB_REGNUM_GENERIC_RA, return_addr))
245+
return false;
246+
247+
LLDB_LOG(log, "ABISysV_riscv::{0}() success", __FUNCTION__);
248+
return true;
172249
}
173250

174251
bool ABISysV_riscv::PrepareTrivialCall(
@@ -222,14 +299,14 @@ bool ABISysV_riscv::PrepareTrivialCall(
222299
assert(prototype.getFunctionNumParams() == args.size());
223300

224301
const size_t num_args = args.size();
225-
const size_t regs_for_args_count = 8U;
226302
const size_t num_args_in_regs =
227-
num_args > regs_for_args_count ? regs_for_args_count : num_args;
303+
num_args > g_regs_for_args_count ? g_regs_for_args_count : num_args;
228304

229305
// Number of arguments passed on stack.
230306
size_t args_size = TotalArgsSizeInWords(m_is_rv64, args);
231-
auto on_stack =
232-
args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;
307+
auto on_stack = args_size <= g_regs_for_args_count
308+
? 0
309+
: args_size - g_regs_for_args_count;
233310
auto offset = on_stack * word_size;
234311

235312
uint8_t reg_value[8];
@@ -260,7 +337,7 @@ bool ABISysV_riscv::PrepareTrivialCall(
260337
++reg_index;
261338
}
262339

263-
if (reg_index < regs_for_args_count || size == 0)
340+
if (reg_index < g_regs_for_args_count || size == 0)
264341
continue;
265342

266343
// Remaining arguments are passed on the stack.

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "llvm/Support/Error.h"
4545
#include "llvm/Support/FileSystem.h"
4646
#include "llvm/Support/TargetSelect.h"
47+
#include "llvm/TargetParser/Triple.h"
4748

4849
#include "llvm/IR/LLVMContext.h"
4950
#include "llvm/IR/Module.h"
@@ -442,24 +443,50 @@ static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) {
442443
/// \return
443444
/// A string representing target ABI for the current architecture.
444445
static std::string GetClangTargetABI(const ArchSpec &target_arch) {
445-
std::string abi;
446-
447446
if (target_arch.IsMIPS()) {
448447
switch (target_arch.GetFlags() & ArchSpec::eMIPSABI_mask) {
449448
case ArchSpec::eMIPSABI_N64:
450-
abi = "n64";
451-
break;
449+
return "n64";
452450
case ArchSpec::eMIPSABI_N32:
453-
abi = "n32";
454-
break;
451+
return "n32";
455452
case ArchSpec::eMIPSABI_O32:
456-
abi = "o32";
457-
break;
453+
return "o32";
458454
default:
459-
break;
455+
return {};
460456
}
461457
}
462-
return abi;
458+
459+
if (target_arch.GetTriple().isRISCV64()) {
460+
switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
461+
case ArchSpec::eRISCV_float_abi_soft:
462+
return "lp64";
463+
case ArchSpec::eRISCV_float_abi_single:
464+
return "lp64f";
465+
case ArchSpec::eRISCV_float_abi_double:
466+
return "lp64d";
467+
case ArchSpec::eRISCV_float_abi_quad:
468+
return "lp64q";
469+
default:
470+
return {};
471+
}
472+
}
473+
474+
if (target_arch.GetTriple().isRISCV32()) {
475+
switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
476+
case ArchSpec::eRISCV_float_abi_soft:
477+
return "ilp32";
478+
case ArchSpec::eRISCV_float_abi_single:
479+
return "ilp32f";
480+
case ArchSpec::eRISCV_float_abi_double:
481+
return "ilp32d";
482+
case ArchSpec::eRISCV_float_abi_soft | ArchSpec::eRISCV_rve:
483+
return "ilp32e";
484+
default:
485+
return {};
486+
}
487+
}
488+
489+
return {};
463490
}
464491

465492
static void SetupTargetOpts(CompilerInstance &compiler,
@@ -506,6 +533,18 @@ static void SetupTargetOpts(CompilerInstance &compiler,
506533
// Set the target ABI
507534
if (std::string abi = GetClangTargetABI(target_arch); !abi.empty())
508535
compiler.getTargetOpts().ABI = std::move(abi);
536+
537+
if ((target_machine == llvm::Triple::riscv64 &&
538+
compiler.getTargetOpts().ABI == "lp64f") ||
539+
(target_machine == llvm::Triple::riscv32 &&
540+
compiler.getTargetOpts().ABI == "ilp32f"))
541+
compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+f");
542+
543+
if ((target_machine == llvm::Triple::riscv64 &&
544+
compiler.getTargetOpts().ABI == "lp64d") ||
545+
(target_machine == llvm::Triple::riscv32 &&
546+
compiler.getTargetOpts().ABI == "ilp32d"))
547+
compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+d");
509548
}
510549

511550
static void SetupLangOpts(CompilerInstance &compiler,
@@ -757,7 +796,7 @@ ClangExpressionParser::ClangExpressionParser(
757796
m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
758797
m_compiler->getCodeGenOpts().InstrumentFunctions = false;
759798
m_compiler->getCodeGenOpts().setFramePointer(
760-
CodeGenOptions::FramePointerKind::All);
799+
CodeGenOptions::FramePointerKind::All);
761800
if (generate_debug_info)
762801
m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
763802
else
@@ -771,7 +810,7 @@ ClangExpressionParser::ClangExpressionParser(
771810
// FIXME: We shouldn't need to do this, the target should be immutable once
772811
// created. This complexity should be lifted elsewhere.
773812
m_compiler->getTarget().adjust(m_compiler->getDiagnostics(),
774-
m_compiler->getLangOpts());
813+
m_compiler->getLangOpts());
775814

776815
// 5. Set up the diagnostic buffer for reporting errors
777816
auto diag_mgr = new ClangDiagnosticManagerAdapter(
@@ -1191,8 +1230,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
11911230
if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef(
11921231
result_path)) {
11931232
source_mgr.setMainFileID(source_mgr.createFileID(
1194-
*fileEntry,
1195-
SourceLocation(), SrcMgr::C_User));
1233+
*fileEntry, SourceLocation(), SrcMgr::C_User));
11961234
created_main_file = true;
11971235
}
11981236
}

0 commit comments

Comments
 (0)