1//===-- ABISysV_riscv.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===---------------------------------------------------------------------===//
8
9#include "ABISysV_riscv.h"
10
11#include <array>
12#include <limits>
13
14#include "llvm/IR/DerivedTypes.h"
15
16#include "lldb/Core/PluginManager.h"
17#include "lldb/Core/Value.h"
18#include "lldb/Core/ValueObjectConstResult.h"
19#include "lldb/Target/RegisterContext.h"
20#include "lldb/Target/StackFrame.h"
21#include "lldb/Target/Thread.h"
22#include "lldb/Utility/RegisterValue.h"
23
24#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()
25#define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString()
26
27// The ABI is not a source of such information as size, offset, encoding, etc.
28// of a register. Just provides correct dwarf and eh_frame numbers.
29
30#define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, generic_num) \
31 { \
32 DEFINE_REG_NAME(dwarf_num), DEFINE_REG_NAME_STR(str_name), 0, 0, \
33 eEncodingInvalid, eFormatDefault, \
34 {dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num}, \
35 nullptr, nullptr, nullptr, \
36 }
37
38#define DEFINE_REGISTER_STUB(dwarf_num, str_name) \
39 DEFINE_GENERIC_REGISTER_STUB(dwarf_num, str_name, LLDB_INVALID_REGNUM)
40
41using namespace lldb;
42using namespace lldb_private;
43
44LLDB_PLUGIN_DEFINE_ADV(ABISysV_riscv, ABIRISCV)
45
46namespace {
47namespace dwarf {
48enum regnums {
49 zero,
50 ra,
51 sp,
52 gp,
53 tp,
54 t0,
55 t1,
56 t2,
57 fp,
58 s0 = fp,
59 s1,
60 a0,
61 a1,
62 a2,
63 a3,
64 a4,
65 a5,
66 a6,
67 a7,
68 s2,
69 s3,
70 s4,
71 s5,
72 s6,
73 s7,
74 s8,
75 s9,
76 s10,
77 s11,
78 t3,
79 t4,
80 t5,
81 t6,
82 pc
83};
84
85static const std::array<RegisterInfo, 33> g_register_infos = {
86 ._M_elems: {DEFINE_REGISTER_STUB(zero, nullptr),
87 DEFINE_GENERIC_REGISTER_STUB(ra, nullptr, LLDB_REGNUM_GENERIC_RA),
88 DEFINE_GENERIC_REGISTER_STUB(sp, nullptr, LLDB_REGNUM_GENERIC_SP),
89 DEFINE_REGISTER_STUB(gp, nullptr),
90 DEFINE_REGISTER_STUB(tp, nullptr),
91 DEFINE_REGISTER_STUB(t0, nullptr),
92 DEFINE_REGISTER_STUB(t1, nullptr),
93 DEFINE_REGISTER_STUB(t2, nullptr),
94 DEFINE_GENERIC_REGISTER_STUB(fp, nullptr, LLDB_REGNUM_GENERIC_FP),
95 DEFINE_REGISTER_STUB(s1, nullptr),
96 DEFINE_GENERIC_REGISTER_STUB(a0, nullptr, LLDB_REGNUM_GENERIC_ARG1),
97 DEFINE_GENERIC_REGISTER_STUB(a1, nullptr, LLDB_REGNUM_GENERIC_ARG2),
98 DEFINE_GENERIC_REGISTER_STUB(a2, nullptr, LLDB_REGNUM_GENERIC_ARG3),
99 DEFINE_GENERIC_REGISTER_STUB(a3, nullptr, LLDB_REGNUM_GENERIC_ARG4),
100 DEFINE_GENERIC_REGISTER_STUB(a4, nullptr, LLDB_REGNUM_GENERIC_ARG5),
101 DEFINE_GENERIC_REGISTER_STUB(a5, nullptr, LLDB_REGNUM_GENERIC_ARG6),
102 DEFINE_GENERIC_REGISTER_STUB(a6, nullptr, LLDB_REGNUM_GENERIC_ARG7),
103 DEFINE_GENERIC_REGISTER_STUB(a7, nullptr, LLDB_REGNUM_GENERIC_ARG8),
104 DEFINE_REGISTER_STUB(s2, nullptr),
105 DEFINE_REGISTER_STUB(s3, nullptr),
106 DEFINE_REGISTER_STUB(s4, nullptr),
107 DEFINE_REGISTER_STUB(s5, nullptr),
108 DEFINE_REGISTER_STUB(s6, nullptr),
109 DEFINE_REGISTER_STUB(s7, nullptr),
110 DEFINE_REGISTER_STUB(s8, nullptr),
111 DEFINE_REGISTER_STUB(s9, nullptr),
112 DEFINE_REGISTER_STUB(s10, nullptr),
113 DEFINE_REGISTER_STUB(s11, nullptr),
114 DEFINE_REGISTER_STUB(t3, nullptr),
115 DEFINE_REGISTER_STUB(t4, nullptr),
116 DEFINE_REGISTER_STUB(t5, nullptr),
117 DEFINE_REGISTER_STUB(t6, nullptr),
118 DEFINE_GENERIC_REGISTER_STUB(pc, nullptr, LLDB_REGNUM_GENERIC_PC)}};
119} // namespace dwarf
120} // namespace
121
122const RegisterInfo *ABISysV_riscv::GetRegisterInfoArray(uint32_t &count) {
123 count = dwarf::g_register_infos.size();
124 return dwarf::g_register_infos.data();
125}
126
127//------------------------------------------------------------------
128// Static Functions
129//------------------------------------------------------------------
130
131ABISP
132ABISysV_riscv::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
133 llvm::Triple::ArchType machine = arch.GetTriple().getArch();
134
135 if (llvm::Triple::riscv32 != machine && llvm::Triple::riscv64 != machine)
136 return ABISP();
137
138 ABISysV_riscv *abi = new ABISysV_riscv(std::move(process_sp),
139 MakeMCRegisterInfo(arch));
140 if (abi)
141 abi->SetIsRV64((llvm::Triple::riscv64 == machine) ? true : false);
142 return ABISP(abi);
143}
144
145static inline size_t AugmentArgSize(bool is_rv64, size_t size_in_bytes) {
146 size_t word_size = is_rv64 ? 8 : 4;
147 return llvm::alignTo(Value: size_in_bytes, Align: word_size);
148}
149
150static size_t
151TotalArgsSizeInWords(bool is_rv64,
152 const llvm::ArrayRef<ABI::CallArgument> &args) {
153 size_t reg_size = is_rv64 ? 8 : 4;
154 size_t word_size = reg_size;
155 size_t total_size = 0;
156 for (const auto &arg : args)
157 total_size +=
158 (ABI::CallArgument::TargetValue == arg.type ? AugmentArgSize(is_rv64,
159 size_in_bytes: arg.size)
160 : reg_size) /
161 word_size;
162
163 return total_size;
164}
165
166bool ABISysV_riscv::PrepareTrivialCall(Thread &thread, addr_t sp,
167 addr_t func_addr, addr_t return_addr,
168 llvm::ArrayRef<addr_t> args) const {
169 // TODO: Implement
170 return false;
171}
172
173bool ABISysV_riscv::PrepareTrivialCall(
174 Thread &thread, addr_t sp, addr_t pc, addr_t ra, llvm::Type &prototype,
175 llvm::ArrayRef<ABI::CallArgument> args) const {
176 auto reg_ctx = thread.GetRegisterContext();
177 if (!reg_ctx)
178 return false;
179
180 uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
181 kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
182 if (pc_reg == LLDB_INVALID_REGNUM)
183 return false;
184
185 uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
186 kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
187 if (ra_reg == LLDB_INVALID_REGNUM)
188 return false;
189
190 uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
191 kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
192 if (sp_reg == LLDB_INVALID_REGNUM)
193 return false;
194
195 Status error;
196 ProcessSP process = thread.GetProcess();
197 if (!process)
198 return false;
199
200 size_t reg_size = m_is_rv64 ? 8 : 4;
201 size_t word_size = reg_size;
202 // Push host data onto target.
203 for (const auto &arg : args) {
204 // Skip over target values.
205 if (arg.type == ABI::CallArgument::TargetValue)
206 continue;
207
208 // Create space on the host stack for this data 4-byte aligned.
209 sp -= AugmentArgSize(is_rv64: m_is_rv64, size_in_bytes: arg.size);
210
211 if (process->WriteMemory(vm_addr: sp, buf: arg.data_up.get(), size: arg.size, error) <
212 arg.size ||
213 error.Fail())
214 return false;
215
216 // Update the argument with the target pointer.
217 *const_cast<addr_t *>(&arg.value) = sp;
218 }
219
220 // Make sure number of parameters matches prototype.
221 assert(prototype.getFunctionNumParams() == args.size());
222
223 const size_t num_args = args.size();
224 const size_t regs_for_args_count = 8U;
225 const size_t num_args_in_regs =
226 num_args > regs_for_args_count ? regs_for_args_count : num_args;
227
228 // Number of arguments passed on stack.
229 size_t args_size = TotalArgsSizeInWords(is_rv64: m_is_rv64, args);
230 auto on_stack =
231 args_size <= regs_for_args_count ? 0 : args_size - regs_for_args_count;
232 auto offset = on_stack * word_size;
233
234 uint8_t reg_value[8];
235 size_t reg_index = LLDB_REGNUM_GENERIC_ARG1;
236
237 for (size_t i = 0; i < args_size; ++i) {
238 auto value = reinterpret_cast<const uint8_t *>(&args[i].value);
239 auto size =
240 ABI::CallArgument::TargetValue == args[i].type ? args[i].size : reg_size;
241
242 // Pass arguments via registers.
243 if (i < num_args_in_regs) {
244 // copy value to register, padding if arg is smaller than register
245 auto end = size < reg_size ? size : reg_size;
246 memcpy(dest: reg_value, src: value, n: end);
247 if (reg_size > end)
248 memset(s: reg_value + end, c: 0, n: reg_size - end);
249
250 RegisterValue reg_val_obj(llvm::ArrayRef(reg_value, reg_size),
251 eByteOrderLittle);
252 if (!reg_ctx->WriteRegister(
253 reg_info: reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, reg_num: reg_index),
254 reg_value: reg_val_obj))
255 return false;
256
257 // NOTE: It's unsafe to iterate through LLDB_REGNUM_GENERICs
258 // But the "a" registers are sequential in the RISC-V register space
259 ++reg_index;
260 }
261
262 if (reg_index < regs_for_args_count || size == 0)
263 continue;
264
265 // Remaining arguments are passed on the stack.
266 if (process->WriteMemory(vm_addr: sp - offset, buf: value, size, error) < size ||
267 !error.Success())
268 return false;
269
270 offset -= AugmentArgSize(is_rv64: m_is_rv64, size_in_bytes: size);
271 }
272
273 // Set stack pointer immediately below arguments.
274 sp -= on_stack * word_size;
275
276 // Update registers with current function call state.
277 reg_ctx->WriteRegisterFromUnsigned(reg: pc_reg, uval: pc);
278 reg_ctx->WriteRegisterFromUnsigned(reg: ra_reg, uval: ra);
279 reg_ctx->WriteRegisterFromUnsigned(reg: sp_reg, uval: sp);
280
281 return true;
282}
283
284bool ABISysV_riscv::GetArgumentValues(Thread &thread, ValueList &values) const {
285 // TODO: Implement
286 return false;
287}
288
289Status ABISysV_riscv::SetReturnValueObject(StackFrameSP &frame_sp,
290 ValueObjectSP &new_value_sp) {
291 Status result;
292 if (!new_value_sp) {
293 result.SetErrorString("Empty value object for return value.");
294 return result;
295 }
296
297 CompilerType compiler_type = new_value_sp->GetCompilerType();
298 if (!compiler_type) {
299 result.SetErrorString("Null clang type for return value.");
300 return result;
301 }
302
303 auto &reg_ctx = *frame_sp->GetThread()->GetRegisterContext();
304
305 bool is_signed = false;
306 if (!compiler_type.IsIntegerOrEnumerationType(is_signed) &&
307 !compiler_type.IsPointerType()) {
308 result.SetErrorString("We don't support returning other types at present");
309 return result;
310 }
311
312 DataExtractor data;
313 size_t num_bytes = new_value_sp->GetData(data, error&: result);
314
315 if (result.Fail()) {
316 result.SetErrorStringWithFormat(
317 "Couldn't convert return value to raw data: %s", result.AsCString());
318 return result;
319 }
320
321 size_t reg_size = m_is_rv64 ? 8 : 4;
322 if (num_bytes <= 2 * reg_size) {
323 offset_t offset = 0;
324 uint64_t raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes);
325
326 auto reg_info =
327 reg_ctx.GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
328 if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, uval: raw_value)) {
329 result.SetErrorStringWithFormat("Couldn't write value to register %s",
330 reg_info->name);
331 return result;
332 }
333
334 if (num_bytes <= reg_size)
335 return result; // Successfully written.
336
337 // for riscv32, get the upper 32 bits from raw_value and write them
338 // for riscv64, get the next 64 bits from data and write them
339 if (4 == reg_size)
340 raw_value >>= 32;
341 else
342 raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes - reg_size);
343 reg_info =
344 reg_ctx.GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
345 if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, uval: raw_value)) {
346 result.SetErrorStringWithFormat("Couldn't write value to register %s",
347 reg_info->name);
348 }
349
350 return result;
351 }
352
353 result.SetErrorString(
354 "We don't support returning large integer values at present.");
355 return result;
356}
357
358template <typename T>
359static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) {
360 raw_value &= std::numeric_limits<T>::max();
361 if (is_signed)
362 scalar = static_cast<typename std::make_signed<T>::type>(raw_value);
363 else
364 scalar = static_cast<T>(raw_value);
365}
366
367static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value,
368 uint8_t size_in_bytes, bool is_signed) {
369 switch (size_in_bytes) {
370 default:
371 return false;
372
373 case sizeof(uint64_t):
374 SetInteger<uint64_t>(scalar, raw_value, is_signed);
375 break;
376
377 case sizeof(uint32_t):
378 SetInteger<uint32_t>(scalar, raw_value, is_signed);
379 break;
380
381 case sizeof(uint16_t):
382 SetInteger<uint16_t>(scalar, raw_value, is_signed);
383 break;
384
385 case sizeof(uint8_t):
386 SetInteger<uint8_t>(scalar, raw_value, is_signed);
387 break;
388 }
389
390 return true;
391}
392
393static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value,
394 uint8_t size_in_bytes) {
395 switch (size_in_bytes) {
396 default:
397 return false;
398
399 case sizeof(uint64_t):
400 scalar = *reinterpret_cast<double *>(&raw_value);
401 break;
402
403 case sizeof(uint32_t):
404 scalar = *reinterpret_cast<float *>(&raw_value);
405 break;
406 }
407
408 return true;
409}
410
411static ValueObjectSP GetValObjFromIntRegs(Thread &thread,
412 const RegisterContextSP &reg_ctx,
413 llvm::Triple::ArchType machine,
414 uint32_t type_flags,
415 uint32_t byte_size) {
416 Value value;
417 ValueObjectSP return_valobj_sp;
418 auto reg_info_a0 =
419 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
420 auto reg_info_a1 =
421 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
422 uint64_t raw_value;
423
424 switch (byte_size) {
425 case sizeof(uint32_t):
426 // Read a0 to get the arg
427 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0) & UINT32_MAX;
428 break;
429 case sizeof(uint64_t):
430 // Read a0 to get the arg on riscv64, a0 and a1 on riscv32
431 if (llvm::Triple::riscv32 == machine) {
432 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0) & UINT32_MAX;
433 raw_value |=
434 (reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a1, fail_value: 0) & UINT32_MAX) << 32U;
435 } else {
436 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0);
437 }
438 break;
439 case 16: {
440 // Read a0 and a1 to get the arg on riscv64, not supported on riscv32
441 if (llvm::Triple::riscv32 == machine)
442 return return_valobj_sp;
443
444 // Create the ValueObjectSP here and return
445 std::unique_ptr<DataBufferHeap> heap_data_up(
446 new DataBufferHeap(byte_size, 0));
447 const ByteOrder byte_order = thread.GetProcess()->GetByteOrder();
448 RegisterValue reg_value_a0, reg_value_a1;
449 if (reg_ctx->ReadRegister(reg_info: reg_info_a0, reg_value&: reg_value_a0) &&
450 reg_ctx->ReadRegister(reg_info: reg_info_a1, reg_value&: reg_value_a1)) {
451 Status error;
452 if (reg_value_a0.GetAsMemoryData(reg_info: *reg_info_a0,
453 dst: heap_data_up->GetBytes() + 0, dst_len: 8,
454 dst_byte_order: byte_order, error) &&
455 reg_value_a1.GetAsMemoryData(reg_info: *reg_info_a1,
456 dst: heap_data_up->GetBytes() + 8, dst_len: 8,
457 dst_byte_order: byte_order, error)) {
458 value.SetBytes(bytes: heap_data_up.release(), len: byte_size);
459 return ValueObjectConstResult::Create(
460 exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString(""));
461 }
462 }
463 break;
464 }
465 default:
466 return return_valobj_sp;
467 }
468
469 if (type_flags & eTypeIsInteger) {
470 const bool is_signed = (type_flags & eTypeIsSigned) != 0;
471 if (!SetSizedInteger(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size, is_signed))
472 return return_valobj_sp;
473 } else if (type_flags & eTypeIsFloat) {
474 if (!SetSizedFloat(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size))
475 return return_valobj_sp;
476 } else
477 return return_valobj_sp;
478
479 value.SetValueType(Value::ValueType::Scalar);
480 return_valobj_sp = ValueObjectConstResult::Create(
481 exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString(""));
482 return return_valobj_sp;
483}
484
485static ValueObjectSP
486GetValObjFromFPRegs(Thread &thread, const RegisterContextSP &reg_ctx,
487 llvm::Triple::ArchType machine, uint32_t arch_fp_flags,
488 uint32_t type_flags, uint32_t byte_size) {
489 auto reg_info_fa0 = reg_ctx->GetRegisterInfoByName(reg_name: "fa0");
490 bool use_fp_regs = false;
491 ValueObjectSP return_valobj_sp;
492
493 switch (arch_fp_flags) {
494 // fp return value in integer registers a0 and possibly a1
495 case ArchSpec::eRISCV_float_abi_soft:
496 return_valobj_sp =
497 GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
498 return return_valobj_sp;
499 // fp return value in fp register fa0 (only float)
500 case ArchSpec::eRISCV_float_abi_single:
501 if (byte_size <= 4)
502 use_fp_regs = true;
503 break;
504 // fp return value in fp registers fa0 (float, double)
505 case ArchSpec::eRISCV_float_abi_double:
506 [[fallthrough]];
507 // fp return value in fp registers fa0 (float, double, quad)
508 // not implemented; act like they're doubles
509 case ArchSpec::eRISCV_float_abi_quad:
510 if (byte_size <= 8)
511 use_fp_regs = true;
512 break;
513 }
514
515 if (use_fp_regs) {
516 uint64_t raw_value;
517 Value value;
518 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_fa0, fail_value: 0);
519 if (!SetSizedFloat(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size))
520 return return_valobj_sp;
521 value.SetValueType(Value::ValueType::Scalar);
522 return ValueObjectConstResult::Create(exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(),
523 value, name: ConstString(""));
524 }
525 // we should never reach this, but if we do, use the integer registers
526 return GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
527}
528
529ValueObjectSP
530ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread,
531 CompilerType &compiler_type) const {
532 ValueObjectSP return_valobj_sp;
533
534 if (!compiler_type)
535 return return_valobj_sp;
536
537 auto reg_ctx = thread.GetRegisterContext();
538 if (!reg_ctx)
539 return return_valobj_sp;
540
541 Value value;
542 value.SetCompilerType(compiler_type);
543
544 const uint32_t type_flags = compiler_type.GetTypeInfo();
545 const size_t byte_size = compiler_type.GetByteSize(exe_scope: &thread).value_or(u: 0);
546 const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture();
547 const llvm::Triple::ArchType machine = arch.GetMachine();
548
549 // Integer return type.
550 if (type_flags & eTypeIsInteger) {
551 return_valobj_sp =
552 GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
553 return return_valobj_sp;
554 }
555 // Pointer return type.
556 else if (type_flags & eTypeIsPointer) {
557 auto reg_info_a0 = reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric,
558 LLDB_REGNUM_GENERIC_ARG1);
559 value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0);
560 value.SetValueType(Value::ValueType::Scalar);
561 return ValueObjectConstResult::Create(exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(),
562 value, name: ConstString(""));
563 }
564 // Floating point return type.
565 else if (type_flags & eTypeIsFloat) {
566 uint32_t float_count = 0;
567 bool is_complex = false;
568
569 if (compiler_type.IsFloatingPointType(count&: float_count, is_complex) &&
570 float_count == 1 && !is_complex) {
571 const uint32_t arch_fp_flags =
572 arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask;
573 return_valobj_sp = GetValObjFromFPRegs(
574 thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size);
575 return return_valobj_sp;
576 }
577 }
578 // Unsupported return type.
579 return return_valobj_sp;
580}
581
582ValueObjectSP
583ABISysV_riscv::GetReturnValueObjectImpl(lldb_private::Thread &thread,
584 llvm::Type &type) const {
585 Value value;
586 ValueObjectSP return_valobj_sp;
587
588 auto reg_ctx = thread.GetRegisterContext();
589 if (!reg_ctx)
590 return return_valobj_sp;
591
592 uint32_t type_flags = 0;
593 if (type.isIntegerTy())
594 type_flags = eTypeIsInteger;
595 else if (type.isVoidTy())
596 type_flags = eTypeIsPointer;
597 else if (type.isFloatTy())
598 type_flags = eTypeIsFloat;
599
600 const uint32_t byte_size = type.getPrimitiveSizeInBits() / CHAR_BIT;
601 const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture();
602 const llvm::Triple::ArchType machine = arch.GetMachine();
603
604 // Integer return type.
605 if (type_flags & eTypeIsInteger) {
606 return_valobj_sp =
607 GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
608 return return_valobj_sp;
609 }
610 // Pointer return type.
611 else if (type_flags & eTypeIsPointer) {
612 auto reg_info_a0 = reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric,
613 LLDB_REGNUM_GENERIC_ARG1);
614 value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0);
615 value.SetValueType(Value::ValueType::Scalar);
616 return ValueObjectConstResult::Create(exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(),
617 value, name: ConstString(""));
618 }
619 // Floating point return type.
620 else if (type_flags & eTypeIsFloat) {
621 const uint32_t arch_fp_flags =
622 arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask;
623 return_valobj_sp = GetValObjFromFPRegs(
624 thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size);
625 return return_valobj_sp;
626 }
627 // Unsupported return type.
628 return return_valobj_sp;
629}
630
631ValueObjectSP ABISysV_riscv::GetReturnValueObjectImpl(
632 Thread &thread, CompilerType &return_compiler_type) const {
633 ValueObjectSP return_valobj_sp;
634
635 if (!return_compiler_type)
636 return return_valobj_sp;
637
638 ExecutionContext exe_ctx(thread.shared_from_this());
639 return GetReturnValueObjectSimple(thread, compiler_type&: return_compiler_type);
640}
641
642bool ABISysV_riscv::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
643 unwind_plan.Clear();
644 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
645
646 uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC;
647 uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
648 uint32_t ra_reg_num = LLDB_REGNUM_GENERIC_RA;
649
650 UnwindPlan::RowSP row(new UnwindPlan::Row);
651
652 // Define CFA as the stack pointer
653 row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: sp_reg_num, offset: 0);
654
655 // Previous frame's pc is in ra
656
657 row->SetRegisterLocationToRegister(reg_num: pc_reg_num, other_reg_num: ra_reg_num, can_replace: true);
658 unwind_plan.AppendRow(row_sp: row);
659 unwind_plan.SetSourceName("riscv function-entry unwind plan");
660 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
661
662 return true;
663}
664
665bool ABISysV_riscv::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
666 unwind_plan.Clear();
667 unwind_plan.SetRegisterKind(eRegisterKindGeneric);
668
669 uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC;
670 uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP;
671
672 UnwindPlan::RowSP row(new UnwindPlan::Row);
673
674 // Define the CFA as the current frame pointer value.
675 row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: fp_reg_num, offset: 0);
676 row->SetOffset(0);
677
678 int reg_size = 4;
679 if (m_is_rv64)
680 reg_size = 8;
681
682 // Assume the ra reg (return pc) and caller's frame pointer
683 // have been spilled to stack already.
684 row->SetRegisterLocationToAtCFAPlusOffset(reg_num: fp_reg_num, offset: reg_size * -2, can_replace: true);
685 row->SetRegisterLocationToAtCFAPlusOffset(reg_num: pc_reg_num, offset: reg_size * -1, can_replace: true);
686
687 unwind_plan.AppendRow(row_sp: row);
688 unwind_plan.SetSourceName("riscv default unwind plan");
689 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
690 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
691 return true;
692}
693
694bool ABISysV_riscv::RegisterIsVolatile(const RegisterInfo *reg_info) {
695 return !RegisterIsCalleeSaved(reg_info);
696}
697
698bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
699 if (!reg_info)
700 return false;
701
702 const char *name = reg_info->name;
703 ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture();
704 uint32_t arch_flags = arch.GetFlags();
705 // floating point registers are only callee saved when using
706 // F, D or Q hardware floating point ABIs
707 bool is_hw_fp = (arch_flags & ArchSpec::eRISCV_float_abi_mask) != 0;
708
709 bool is_callee_saved =
710 llvm::StringSwitch<bool>(name)
711 // integer ABI names
712 .Cases(S0: "ra", S1: "sp", S2: "fp", Value: true)
713 .Cases(S0: "s0", S1: "s1", S2: "s2", S3: "s3", S4: "s4", S5: "s5", S6: "s6", S7: "s7", S8: "s8", S9: "s9",
714 Value: true)
715 .Cases(S0: "s10", S1: "s11", Value: true)
716 // integer hardware names
717 .Cases(S0: "x1", S1: "x2", S2: "x8", S3: "x9", S4: "x18", S5: "x19", S6: "x20", S7: "x21", S8: "x22",
718 Value: true)
719 .Cases(S0: "x23", S1: "x24", S2: "x25", S3: "x26", S4: "x27", Value: true)
720 // floating point ABI names
721 .Cases(S0: "fs0", S1: "fs1", S2: "fs2", S3: "fs3", S4: "fs4", S5: "fs5", S6: "fs6", S7: "fs7",
722 Value: is_hw_fp)
723 .Cases(S0: "fs8", S1: "fs9", S2: "fs10", S3: "fs11", Value: is_hw_fp)
724 // floating point hardware names
725 .Cases(S0: "f8", S1: "f9", S2: "f18", S3: "f19", S4: "f20", S5: "f21", S6: "f22", S7: "f23", Value: is_hw_fp)
726 .Cases(S0: "f24", S1: "f25", S2: "f26", S3: "f27", Value: is_hw_fp)
727 .Default(Value: false);
728
729 return is_callee_saved;
730}
731
732void ABISysV_riscv::Initialize() {
733 PluginManager::RegisterPlugin(
734 name: GetPluginNameStatic(), description: "System V ABI for RISCV targets", create_callback: CreateInstance);
735}
736
737void ABISysV_riscv::Terminate() {
738 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
739}
740
741static uint32_t GetGenericNum(llvm::StringRef name) {
742 return llvm::StringSwitch<uint32_t>(name)
743 .Case(S: "pc", LLDB_REGNUM_GENERIC_PC)
744 .Cases(S0: "ra", S1: "x1", LLDB_REGNUM_GENERIC_RA)
745 .Cases(S0: "sp", S1: "x2", LLDB_REGNUM_GENERIC_SP)
746 .Cases(S0: "fp", S1: "s0", LLDB_REGNUM_GENERIC_FP)
747 .Case(S: "a0", LLDB_REGNUM_GENERIC_ARG1)
748 .Case(S: "a1", LLDB_REGNUM_GENERIC_ARG2)
749 .Case(S: "a2", LLDB_REGNUM_GENERIC_ARG3)
750 .Case(S: "a3", LLDB_REGNUM_GENERIC_ARG4)
751 .Case(S: "a4", LLDB_REGNUM_GENERIC_ARG5)
752 .Case(S: "a5", LLDB_REGNUM_GENERIC_ARG6)
753 .Case(S: "a6", LLDB_REGNUM_GENERIC_ARG7)
754 .Case(S: "a7", LLDB_REGNUM_GENERIC_ARG8)
755 .Default(LLDB_INVALID_REGNUM);
756}
757
758void ABISysV_riscv::AugmentRegisterInfo(
759 std::vector<lldb_private::DynamicRegisterInfo::Register> &regs) {
760 lldb_private::RegInfoBasedABI::AugmentRegisterInfo(regs);
761
762 for (auto it : llvm::enumerate(First&: regs)) {
763 // Set alt name for certain registers for convenience
764 if (it.value().name == "zero")
765 it.value().alt_name.SetCString("x0");
766 else if (it.value().name == "ra")
767 it.value().alt_name.SetCString("x1");
768 else if (it.value().name == "sp")
769 it.value().alt_name.SetCString("x2");
770 else if (it.value().name == "gp")
771 it.value().alt_name.SetCString("x3");
772 else if (it.value().name == "fp")
773 it.value().alt_name.SetCString("s0");
774 else if (it.value().name == "s0")
775 it.value().alt_name.SetCString("x8");
776
777 // Set generic regnum so lldb knows what the PC, etc is
778 it.value().regnum_generic = GetGenericNum(name: it.value().name.GetStringRef());
779 }
780}
781

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