Skip to content

Commit 6a5c805

Browse files
committed
[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.
1 parent 0f97b48 commit 6a5c805

File tree

1 file changed

+84
-7
lines changed

1 file changed

+84
-7
lines changed

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.

0 commit comments

Comments
 (0)