Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][RISCV] function calls support in lldb expressions #99336

Merged
merged 4 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have a comment. If every other arch set the code model it'd be fine, but this sticks out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

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
Loading