Skip to content

Commit

Permalink
[lldb][RISCV] function calls support in lldb expressions (llvm#99336)
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
dlav-sc authored and VitaNuo committed Oct 2, 2024
1 parent fbc0f1e commit 4d3f7f4
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 24 deletions.
6 changes: 6 additions & 0 deletions lldb/source/Expression/IRExecutionUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr,
.setMCJITMemoryManager(std::make_unique<MemoryManager>(*this))
.setOptLevel(llvm::CodeGenOptLevel::Less);

// Resulted jitted code can be placed too far from the code in the binary
// and thus can contain more than +-2GB jumps, that are not available
// in RISC-V without large code model.
if (triple.isRISCV64())
builder.setCodeModel(llvm::CodeModel::Large);

llvm::StringRef mArch;
llvm::StringRef mCPU;
llvm::SmallVector<std::string, 0> mAttrs;
Expand Down
91 changes: 84 additions & 7 deletions lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

#include <array>
#include <limits>
#include <sstream>

#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/DerivedTypes.h"

#include "Utility/RISCV_DWARF_Registers.h"
Expand All @@ -20,6 +22,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/RegisterValue.h"

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

// Number of argument registers (the base integer calling convention
// provides 8 argument registers, a0-a7)
static constexpr size_t g_regs_for_args_count = 8U;

const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) {
count = dwarf::g_register_infos.size();
return dwarf::g_register_infos.data();
Expand Down Expand Up @@ -164,11 +171,81 @@ TotalArgsSizeInWords(bool is_rv64,
return total_size;
}

static bool UpdateRegister(RegisterContext *reg_ctx,
const lldb::RegisterKind reg_kind,
const uint32_t reg_num, const addr_t value) {
Log *log = GetLog(LLDBLog::Expressions);

const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(reg_kind, reg_num);

LLDB_LOG(log, "Writing {0}: 0x{1:x}", reg_info->name,
static_cast<uint64_t>(value));
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, value)) {
LLDB_LOG(log, "Writing {0}: failed", reg_info->name);
return false;
}
return true;
}

static void LogInitInfo(Log &log, const Thread &thread, addr_t sp,
addr_t func_addr, addr_t return_addr,
const llvm::ArrayRef<addr_t> args) {
std::stringstream ss;
ss << "ABISysV_riscv::PrepareTrivialCall"
<< " (tid = 0x" << std::hex << thread.GetID() << ", sp = 0x" << sp
<< ", func_addr = 0x" << func_addr << ", return_addr = 0x" << return_addr;

for (auto [idx, arg] : enumerate(args))
ss << ", arg" << std::dec << idx << " = 0x" << std::hex << arg;
ss << ")";
log.PutString(ss.str());
}

bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp,
addr_t func_addr, addr_t return_addr,
llvm::ArrayRef<addr_t> args) const {
// TODO: Implement
return false;
Log *log = GetLog(LLDBLog::Expressions);
if (log)
LogInitInfo(*log, thread, sp, func_addr, return_addr, args);

const auto reg_ctx_sp = thread.GetRegisterContext();
if (!reg_ctx_sp) {
LLDB_LOG(log, "Failed to get RegisterContext");
return false;
}

if (args.size() > g_regs_for_args_count) {
LLDB_LOG(log, "Function has {0} arguments, but only {1} are allowed!",
args.size(), g_regs_for_args_count);
return false;
}

// Write arguments to registers
for (auto [idx, arg] : enumerate(args)) {
const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + idx);
LLDB_LOG(log, "About to write arg{0} (0x{1:x}) into {2}", idx, arg,
reg_info->name);

if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, arg)) {
LLDB_LOG(log, "Failed to write arg{0} (0x{1:x}) into {2}", idx, arg,
reg_info->name);
return false;
}
}

if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC, func_addr))
return false;
if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP, sp))
return false;
if (!UpdateRegister(reg_ctx_sp.get(), eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_RA, return_addr))
return false;

LLDB_LOG(log, "ABISysV_riscv::{0}() success", __FUNCTION__);
return true;
}

bool ABISysV_riscv::PrepareTrivialCall(
Expand Down Expand Up @@ -222,14 +299,14 @@ bool ABISysV_riscv::PrepareTrivialCall(
assert(prototype.getFunctionNumParams() == args.size());

const size_t num_args = args.size();
const size_t regs_for_args_count = 8U;
const size_t num_args_in_regs =
num_args > regs_for_args_count ? regs_for_args_count : num_args;
num_args > g_regs_for_args_count ? g_regs_for_args_count : num_args;

// Number of arguments passed on stack.
size_t args_size = TotalArgsSizeInWords(m_is_rv64, args);
auto on_stack =
args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;
auto on_stack = args_size <= g_regs_for_args_count
? 0
: args_size - g_regs_for_args_count;
auto offset = on_stack * word_size;

uint8_t reg_value[8];
Expand Down Expand Up @@ -260,7 +337,7 @@ bool ABISysV_riscv::PrepareTrivialCall(
++reg_index;
}

if (reg_index < regs_for_args_count || size == 0)
if (reg_index < g_regs_for_args_count || size == 0)
continue;

// Remaining arguments are passed on the stack.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Triple.h"

#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
Expand Down Expand Up @@ -442,24 +443,50 @@ static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) {
/// \return
/// A string representing target ABI for the current architecture.
static std::string GetClangTargetABI(const ArchSpec &target_arch) {
std::string abi;

if (target_arch.IsMIPS()) {
switch (target_arch.GetFlags() & ArchSpec::eMIPSABI_mask) {
case ArchSpec::eMIPSABI_N64:
abi = "n64";
break;
return "n64";
case ArchSpec::eMIPSABI_N32:
abi = "n32";
break;
return "n32";
case ArchSpec::eMIPSABI_O32:
abi = "o32";
break;
return "o32";
default:
break;
return {};
}
}
return abi;

if (target_arch.GetTriple().isRISCV64()) {
switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
case ArchSpec::eRISCV_float_abi_soft:
return "lp64";
case ArchSpec::eRISCV_float_abi_single:
return "lp64f";
case ArchSpec::eRISCV_float_abi_double:
return "lp64d";
case ArchSpec::eRISCV_float_abi_quad:
return "lp64q";
default:
return {};
}
}

if (target_arch.GetTriple().isRISCV32()) {
switch (target_arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask) {
case ArchSpec::eRISCV_float_abi_soft:
return "ilp32";
case ArchSpec::eRISCV_float_abi_single:
return "ilp32f";
case ArchSpec::eRISCV_float_abi_double:
return "ilp32d";
case ArchSpec::eRISCV_float_abi_soft | ArchSpec::eRISCV_rve:
return "ilp32e";
default:
return {};
}
}

return {};
}

static void SetupTargetOpts(CompilerInstance &compiler,
Expand Down Expand Up @@ -506,6 +533,18 @@ static void SetupTargetOpts(CompilerInstance &compiler,
// Set the target ABI
if (std::string abi = GetClangTargetABI(target_arch); !abi.empty())
compiler.getTargetOpts().ABI = std::move(abi);

if ((target_machine == llvm::Triple::riscv64 &&
compiler.getTargetOpts().ABI == "lp64f") ||
(target_machine == llvm::Triple::riscv32 &&
compiler.getTargetOpts().ABI == "ilp32f"))
compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+f");

if ((target_machine == llvm::Triple::riscv64 &&
compiler.getTargetOpts().ABI == "lp64d") ||
(target_machine == llvm::Triple::riscv32 &&
compiler.getTargetOpts().ABI == "ilp32d"))
compiler.getTargetOpts().FeaturesAsWritten.emplace_back("+d");
}

static void SetupLangOpts(CompilerInstance &compiler,
Expand Down Expand Up @@ -757,7 +796,7 @@ ClangExpressionParser::ClangExpressionParser(
m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
m_compiler->getCodeGenOpts().InstrumentFunctions = false;
m_compiler->getCodeGenOpts().setFramePointer(
CodeGenOptions::FramePointerKind::All);
CodeGenOptions::FramePointerKind::All);
if (generate_debug_info)
m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
else
Expand All @@ -771,7 +810,7 @@ ClangExpressionParser::ClangExpressionParser(
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
m_compiler->getTarget().adjust(m_compiler->getDiagnostics(),
m_compiler->getLangOpts());
m_compiler->getLangOpts());

// 5. Set up the diagnostic buffer for reporting errors
auto diag_mgr = new ClangDiagnosticManagerAdapter(
Expand Down Expand Up @@ -1191,8 +1230,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef(
result_path)) {
source_mgr.setMainFileID(source_mgr.createFileID(
*fileEntry,
SourceLocation(), SrcMgr::C_User));
*fileEntry, SourceLocation(), SrcMgr::C_User));
created_main_file = true;
}
}
Expand Down
Loading

0 comments on commit 4d3f7f4

Please sign in to comment.