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 | |
41 | using namespace lldb; |
42 | using namespace lldb_private; |
43 | |
44 | LLDB_PLUGIN_DEFINE_ADV(ABISysV_riscv, ABIRISCV) |
45 | |
46 | namespace { |
47 | namespace dwarf { |
48 | enum 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 | |
85 | static 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 | |
122 | const 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 | |
131 | ABISP |
132 | ABISysV_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 | |
145 | static 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 | |
150 | static size_t |
151 | TotalArgsSizeInWords(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 | |
166 | bool 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 | |
173 | bool 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 | |
284 | bool ABISysV_riscv::GetArgumentValues(Thread &thread, ValueList &values) const { |
285 | // TODO: Implement |
286 | return false; |
287 | } |
288 | |
289 | Status 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 ®_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 | |
358 | template <typename T> |
359 | static 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 | |
367 | static 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 | |
393 | static 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 | |
411 | static ValueObjectSP GetValObjFromIntRegs(Thread &thread, |
412 | const RegisterContextSP ®_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 | |
485 | static ValueObjectSP |
486 | GetValObjFromFPRegs(Thread &thread, const RegisterContextSP ®_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 | |
529 | ValueObjectSP |
530 | ABISysV_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 | |
582 | ValueObjectSP |
583 | ABISysV_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 | |
631 | ValueObjectSP 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 | |
642 | bool 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 | |
665 | bool 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 | |
694 | bool ABISysV_riscv::RegisterIsVolatile(const RegisterInfo *reg_info) { |
695 | return !RegisterIsCalleeSaved(reg_info); |
696 | } |
697 | |
698 | bool 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 | |
732 | void ABISysV_riscv::Initialize() { |
733 | PluginManager::RegisterPlugin( |
734 | name: GetPluginNameStatic(), description: "System V ABI for RISCV targets" , create_callback: CreateInstance); |
735 | } |
736 | |
737 | void ABISysV_riscv::Terminate() { |
738 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
739 | } |
740 | |
741 | static 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 | |
758 | void ABISysV_riscv::AugmentRegisterInfo( |
759 | std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) { |
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 | |