|
10 | 10 |
|
11 | 11 | #include <array>
|
12 | 12 | #include <limits>
|
| 13 | +#include <sstream> |
13 | 14 |
|
| 15 | +#include "llvm/ADT/STLExtras.h" |
14 | 16 | #include "llvm/IR/DerivedTypes.h"
|
15 | 17 |
|
16 | 18 | #include "Utility/RISCV_DWARF_Registers.h"
|
|
20 | 22 | #include "lldb/Target/RegisterContext.h"
|
21 | 23 | #include "lldb/Target/StackFrame.h"
|
22 | 24 | #include "lldb/Target/Thread.h"
|
| 25 | +#include "lldb/Utility/LLDBLog.h" |
23 | 26 | #include "lldb/Utility/RegisterValue.h"
|
24 | 27 |
|
25 | 28 | #define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()
|
@@ -120,6 +123,10 @@ static const std::array<RegisterInfo, 33> g_register_infos = {
|
120 | 123 | } // namespace dwarf
|
121 | 124 | } // namespace
|
122 | 125 |
|
| 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 | + |
123 | 130 | const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) {
|
124 | 131 | count = dwarf::g_register_infos.size();
|
125 | 132 | return dwarf::g_register_infos.data();
|
@@ -164,11 +171,81 @@ TotalArgsSizeInWords(bool is_rv64,
|
164 | 171 | return total_size;
|
165 | 172 | }
|
166 | 173 |
|
| 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 | + |
167 | 204 | bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp,
|
168 | 205 | addr_t func_addr, addr_t return_addr,
|
169 | 206 | 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; |
172 | 249 | }
|
173 | 250 |
|
174 | 251 | bool ABISysV_riscv::PrepareTrivialCall(
|
@@ -222,14 +299,14 @@ bool ABISysV_riscv::PrepareTrivialCall(
|
222 | 299 | assert(prototype.getFunctionNumParams() == args.size());
|
223 | 300 |
|
224 | 301 | const size_t num_args = args.size();
|
225 |
| - const size_t regs_for_args_count = 8U; |
226 | 302 | 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; |
228 | 304 |
|
229 | 305 | // Number of arguments passed on stack.
|
230 | 306 | 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; |
233 | 310 | auto offset = on_stack * word_size;
|
234 | 311 |
|
235 | 312 | uint8_t reg_value[8];
|
@@ -260,7 +337,7 @@ bool ABISysV_riscv::PrepareTrivialCall(
|
260 | 337 | ++reg_index;
|
261 | 338 | }
|
262 | 339 |
|
263 |
| - if (reg_index < regs_for_args_count || size == 0) |
| 340 | + if (reg_index < g_regs_for_args_count || size == 0) |
264 | 341 | continue;
|
265 | 342 |
|
266 | 343 | // Remaining arguments are passed on the stack.
|
|
0 commit comments