Skip to content

Commit fb4e062

Browse files
committed
[lldb][RISCV] add jitted function calls to ABI
Function calls support in LLDB expressions for RISCV: 1 of 6 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 34b10e1 commit fb4e062

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

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

Lines changed: 82 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()
@@ -164,11 +167,83 @@ TotalArgsSizeInWords(bool is_rv64,
164167
return total_size;
165168
}
166169

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

174249
bool ABISysV_riscv::PrepareTrivialCall(
@@ -222,14 +297,14 @@ bool ABISysV_riscv::PrepareTrivialCall(
222297
assert(prototype.getFunctionNumParams() == args.size());
223298

224299
const size_t num_args = args.size();
225-
const size_t regs_for_args_count = 8U;
226300
const size_t num_args_in_regs =
227-
num_args > regs_for_args_count ? regs_for_args_count : num_args;
301+
num_args > s_regs_for_args_count ? s_regs_for_args_count : num_args;
228302

229303
// Number of arguments passed on stack.
230304
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;
305+
auto on_stack = args_size <= s_regs_for_args_count
306+
? 0
307+
: args_size - s_regs_for_args_count;
233308
auto offset = on_stack * word_size;
234309

235310
uint8_t reg_value[8];
@@ -260,7 +335,7 @@ bool ABISysV_riscv::PrepareTrivialCall(
260335
++reg_index;
261336
}
262337

263-
if (reg_index < regs_for_args_count || size == 0)
338+
if (reg_index < s_regs_for_args_count || size == 0)
264339
continue;
265340

266341
// Remaining arguments are passed on the stack.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class ABISysV_riscv : public lldb_private::RegInfoBasedABI {
124124
using lldb_private::RegInfoBasedABI::RegInfoBasedABI; // Call CreateInstance
125125
// instead.
126126
bool m_is_rv64; // true if target is riscv64; false if target is riscv32
127+
static constexpr size_t s_regs_for_args_count =
128+
8U; // number of argument registers (the base integer calling convention
129+
// provides 8 argument registers, a0-a7)
127130
};
128131

129132
#endif // liblldb_ABISysV_riscv_h_

0 commit comments

Comments
 (0)