1//===-- ABISysV_loongarch.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_loongarch.h"
10
11#include <array>
12#include <limits>
13#include <sstream>
14
15#include "llvm/ADT/StringRef.h"
16#include "llvm/IR/DerivedTypes.h"
17#include "llvm/Support/MathExtras.h"
18
19#include "Utility/LoongArch_DWARF_Registers.h"
20#include "lldb/Core/PluginManager.h"
21#include "lldb/Core/Value.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/StackFrame.h"
24#include "lldb/Target/Thread.h"
25#include "lldb/Utility/LLDBLog.h"
26#include "lldb/Utility/RegisterValue.h"
27#include "lldb/ValueObject/ValueObjectConstResult.h"
28
29#define DEFINE_REG_NAME(reg_num) ConstString(#reg_num).GetCString()
30#define DEFINE_REG_NAME_STR(reg_name) ConstString(reg_name).GetCString()
31
32// The ABI is not a source of such information as size, offset, encoding, etc.
33// of a register. Just provides correct dwarf and eh_frame numbers.
34
35#define DEFINE_GENERIC_REGISTER_STUB(dwarf_num, generic_num) \
36 { \
37 DEFINE_REG_NAME(dwarf_num), \
38 DEFINE_REG_NAME_STR(nullptr), \
39 0, \
40 0, \
41 eEncodingInvalid, \
42 eFormatDefault, \
43 {dwarf_num, dwarf_num, generic_num, LLDB_INVALID_REGNUM, dwarf_num}, \
44 nullptr, \
45 nullptr, \
46 nullptr, \
47 }
48
49#define DEFINE_REGISTER_STUB(dwarf_num) \
50 DEFINE_GENERIC_REGISTER_STUB(dwarf_num, LLDB_INVALID_REGNUM)
51
52using namespace lldb;
53using namespace lldb_private;
54
55LLDB_PLUGIN_DEFINE_ADV(ABISysV_loongarch, ABILoongArch)
56
57namespace {
58namespace dwarf {
59enum regnums {
60 r0,
61 r1,
62 ra = r1,
63 r2,
64 r3,
65 sp = r3,
66 r4,
67 r5,
68 r6,
69 r7,
70 r8,
71 r9,
72 r10,
73 r11,
74 r12,
75 r13,
76 r14,
77 r15,
78 r16,
79 r17,
80 r18,
81 r19,
82 r20,
83 r21,
84 r22,
85 fp = r22,
86 r23,
87 r24,
88 r25,
89 r26,
90 r27,
91 r28,
92 r29,
93 r30,
94 r31,
95 pc
96};
97
98static const std::array<RegisterInfo, 33> g_register_infos = {
99 ._M_elems: {DEFINE_REGISTER_STUB(r0),
100 DEFINE_GENERIC_REGISTER_STUB(r1, LLDB_REGNUM_GENERIC_RA),
101 DEFINE_REGISTER_STUB(r2),
102 DEFINE_GENERIC_REGISTER_STUB(r3, LLDB_REGNUM_GENERIC_SP),
103 DEFINE_GENERIC_REGISTER_STUB(r4, LLDB_REGNUM_GENERIC_ARG1),
104 DEFINE_GENERIC_REGISTER_STUB(r5, LLDB_REGNUM_GENERIC_ARG2),
105 DEFINE_GENERIC_REGISTER_STUB(r6, LLDB_REGNUM_GENERIC_ARG3),
106 DEFINE_GENERIC_REGISTER_STUB(r7, LLDB_REGNUM_GENERIC_ARG4),
107 DEFINE_GENERIC_REGISTER_STUB(r8, LLDB_REGNUM_GENERIC_ARG5),
108 DEFINE_GENERIC_REGISTER_STUB(r9, LLDB_REGNUM_GENERIC_ARG6),
109 DEFINE_GENERIC_REGISTER_STUB(r10, LLDB_REGNUM_GENERIC_ARG7),
110 DEFINE_GENERIC_REGISTER_STUB(r11, LLDB_REGNUM_GENERIC_ARG8),
111 DEFINE_REGISTER_STUB(r12),
112 DEFINE_REGISTER_STUB(r13),
113 DEFINE_REGISTER_STUB(r14),
114 DEFINE_REGISTER_STUB(r15),
115 DEFINE_REGISTER_STUB(r16),
116 DEFINE_REGISTER_STUB(r17),
117 DEFINE_REGISTER_STUB(r18),
118 DEFINE_REGISTER_STUB(r19),
119 DEFINE_REGISTER_STUB(r20),
120 DEFINE_REGISTER_STUB(r21),
121 DEFINE_GENERIC_REGISTER_STUB(r22, LLDB_REGNUM_GENERIC_FP),
122 DEFINE_REGISTER_STUB(r23),
123 DEFINE_REGISTER_STUB(r24),
124 DEFINE_REGISTER_STUB(r25),
125 DEFINE_REGISTER_STUB(r26),
126 DEFINE_REGISTER_STUB(r27),
127 DEFINE_REGISTER_STUB(r28),
128 DEFINE_REGISTER_STUB(r29),
129 DEFINE_REGISTER_STUB(r30),
130 DEFINE_REGISTER_STUB(r31),
131 DEFINE_GENERIC_REGISTER_STUB(pc, LLDB_REGNUM_GENERIC_PC)}};
132} // namespace dwarf
133} // namespace
134
135// Number of argument registers (the base integer calling convention
136// provides 8 argument registers, a0-a7)
137static constexpr size_t g_regs_for_args_count = 8U;
138
139const RegisterInfo *ABISysV_loongarch::GetRegisterInfoArray(uint32_t &count) {
140 count = dwarf::g_register_infos.size();
141 return dwarf::g_register_infos.data();
142}
143
144//------------------------------------------------------------------
145// Static Functions
146//------------------------------------------------------------------
147
148ABISP
149ABISysV_loongarch::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
150 llvm::Triple::ArchType machine = arch.GetTriple().getArch();
151
152 if (llvm::Triple::loongarch32 != machine &&
153 llvm::Triple::loongarch64 != machine)
154 return ABISP();
155
156 ABISysV_loongarch *abi =
157 new ABISysV_loongarch(std::move(process_sp), MakeMCRegisterInfo(arch));
158 if (abi)
159 abi->SetIsLA64(llvm::Triple::loongarch64 == machine);
160 return ABISP(abi);
161}
162
163static bool UpdateRegister(RegisterContext *reg_ctx,
164 const lldb::RegisterKind reg_kind,
165 const uint32_t reg_num, const addr_t value) {
166 Log *log = GetLog(mask: LLDBLog::Expressions);
167
168 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(reg_kind, reg_num);
169
170 LLDB_LOG(log, "Writing {0}: 0x{1:x}", reg_info->name,
171 static_cast<uint64_t>(value));
172 if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, uval: value)) {
173 LLDB_LOG(log, "Writing {0}: failed", reg_info->name);
174 return false;
175 }
176 return true;
177}
178
179static void LogInitInfo(Log &log, const Thread &thread, addr_t sp,
180 addr_t func_addr, addr_t return_addr,
181 const llvm::ArrayRef<addr_t> args) {
182 std::stringstream ss;
183 ss << "ABISysV_loongarch::PrepareTrivialCall"
184 << " (tid = 0x" << std::hex << thread.GetID() << ", sp = 0x" << sp
185 << ", func_addr = 0x" << func_addr << ", return_addr = 0x" << return_addr;
186
187 for (auto [idx, arg] : enumerate(First: args))
188 ss << ", arg" << std::dec << idx << " = 0x" << std::hex << arg;
189 ss << ")";
190 log.PutString(str: ss.str());
191}
192
193bool ABISysV_loongarch::PrepareTrivialCall(Thread &thread, addr_t sp,
194 addr_t func_addr, addr_t return_addr,
195 llvm::ArrayRef<addr_t> args) const {
196 Log *log = GetLog(mask: LLDBLog::Expressions);
197 if (log)
198 LogInitInfo(log&: *log, thread, sp, func_addr, return_addr, args);
199
200 const auto reg_ctx_sp = thread.GetRegisterContext();
201 if (!reg_ctx_sp) {
202 LLDB_LOG(log, "Failed to get RegisterContext");
203 return false;
204 }
205
206 if (args.size() > g_regs_for_args_count) {
207 LLDB_LOG(log, "Function has {0} arguments, but only {1} are allowed!",
208 args.size(), g_regs_for_args_count);
209 return false;
210 }
211
212 // Write arguments to registers
213 for (auto [idx, arg] : enumerate(First&: args)) {
214 const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(
215 reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + idx);
216 LLDB_LOG(log, "About to write arg{0} ({1:x}) into {2}", idx, arg,
217 reg_info->name);
218
219 if (!reg_ctx_sp->WriteRegisterFromUnsigned(reg_info, uval: arg)) {
220 LLDB_LOG(log, "Failed to write arg{0} ({1:x}) into {2}", idx, arg,
221 reg_info->name);
222 return false;
223 }
224 }
225
226 if (!UpdateRegister(reg_ctx: reg_ctx_sp.get(), reg_kind: eRegisterKindGeneric,
227 LLDB_REGNUM_GENERIC_PC, value: func_addr))
228 return false;
229 if (!UpdateRegister(reg_ctx: reg_ctx_sp.get(), reg_kind: eRegisterKindGeneric,
230 LLDB_REGNUM_GENERIC_SP, value: sp))
231 return false;
232 if (!UpdateRegister(reg_ctx: reg_ctx_sp.get(), reg_kind: eRegisterKindGeneric,
233 LLDB_REGNUM_GENERIC_RA, value: return_addr))
234 return false;
235
236 LLDB_LOG(log, "ABISysV_loongarch::{0}() success", __FUNCTION__);
237 return true;
238}
239
240bool ABISysV_loongarch::GetArgumentValues(Thread &thread,
241 ValueList &values) const {
242 // TODO: Implement
243 return false;
244}
245
246Status ABISysV_loongarch::SetReturnValueObject(StackFrameSP &frame_sp,
247 ValueObjectSP &new_value_sp) {
248 Status result;
249 if (!new_value_sp) {
250 result = Status::FromErrorString(str: "Empty value object for return value.");
251 return result;
252 }
253
254 CompilerType compiler_type = new_value_sp->GetCompilerType();
255 if (!compiler_type) {
256 result = Status::FromErrorString(str: "Null clang type for return value.");
257 return result;
258 }
259
260 auto &reg_ctx = *frame_sp->GetThread()->GetRegisterContext();
261
262 bool is_signed = false;
263 if (!compiler_type.IsIntegerOrEnumerationType(is_signed) &&
264 !compiler_type.IsPointerType()) {
265 result = Status::FromErrorString(
266 str: "We don't support returning other types at present");
267 return result;
268 }
269
270 DataExtractor data;
271 size_t num_bytes = new_value_sp->GetData(data, error&: result);
272
273 if (result.Fail()) {
274 result = Status::FromErrorStringWithFormat(
275 format: "Couldn't convert return value to raw data: %s", result.AsCString());
276 return result;
277 }
278
279 size_t reg_size = m_is_la64 ? 8 : 4;
280 // Currently, we only support sizeof(data) <= 2 * reg_size.
281 // 1. If the (`size` <= reg_size), the `data` will be returned through `ARG1`.
282 // 2. If the (`size` > reg_size && `size` <= 2 * reg_size), the `data` will be
283 // returned through a pair of registers (ARG1 and ARG2), and the lower-ordered
284 // bits in the `ARG1`.
285 if (num_bytes > 2 * reg_size) {
286 result = Status::FromErrorString(
287 str: "We don't support returning large integer values at present.");
288 return result;
289 }
290
291 offset_t offset = 0;
292 uint64_t raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes);
293 // According to psABI, i32 (no matter signed or unsigned) should be
294 // sign-extended in register.
295 if (4 == num_bytes && m_is_la64)
296 raw_value = llvm::SignExtend64<32>(x: raw_value);
297 auto reg_info =
298 reg_ctx.GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
299 if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, uval: raw_value)) {
300 result = Status::FromErrorStringWithFormat(
301 format: "Couldn't write value to register %s", reg_info->name);
302 return result;
303 }
304
305 if (num_bytes <= reg_size)
306 return result; // Successfully written.
307
308 // For loongarch32, get the upper 32 bits from raw_value and write them.
309 // For loongarch64, get the next 64 bits from data and write them.
310 if (4 == reg_size)
311 raw_value >>= 32;
312 else
313 raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes - reg_size);
314
315 reg_info =
316 reg_ctx.GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
317 if (!reg_ctx.WriteRegisterFromUnsigned(reg_info, uval: raw_value))
318 result = Status::FromErrorStringWithFormat(
319 format: "Couldn't write value to register %s", reg_info->name);
320
321 return result;
322}
323
324template <typename T>
325static void SetInteger(Scalar &scalar, uint64_t raw_value, bool is_signed) {
326 static_assert(std::is_unsigned<T>::value, "T must be an unsigned type.");
327 raw_value &= std::numeric_limits<T>::max();
328 if (is_signed)
329 scalar = static_cast<typename std::make_signed<T>::type>(raw_value);
330 else
331 scalar = static_cast<T>(raw_value);
332}
333
334static bool SetSizedInteger(Scalar &scalar, uint64_t raw_value,
335 uint8_t size_in_bytes, bool is_signed) {
336 switch (size_in_bytes) {
337 default:
338 return false;
339
340 case sizeof(uint64_t):
341 SetInteger<uint64_t>(scalar, raw_value, is_signed);
342 break;
343
344 case sizeof(uint32_t):
345 SetInteger<uint32_t>(scalar, raw_value, is_signed);
346 break;
347
348 case sizeof(uint16_t):
349 SetInteger<uint16_t>(scalar, raw_value, is_signed);
350 break;
351
352 case sizeof(uint8_t):
353 SetInteger<uint8_t>(scalar, raw_value, is_signed);
354 break;
355 }
356
357 return true;
358}
359
360static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value,
361 uint8_t size_in_bytes) {
362 switch (size_in_bytes) {
363 default:
364 return false;
365
366 case sizeof(uint64_t):
367 scalar = *reinterpret_cast<double *>(&raw_value);
368 break;
369
370 case sizeof(uint32_t):
371 scalar = *reinterpret_cast<float *>(&raw_value);
372 break;
373 }
374
375 return true;
376}
377
378static ValueObjectSP GetValObjFromIntRegs(Thread &thread,
379 const RegisterContextSP &reg_ctx,
380 llvm::Triple::ArchType machine,
381 uint32_t type_flags,
382 uint32_t byte_size) {
383 Value value;
384 ValueObjectSP return_valobj_sp;
385 auto *reg_info_a0 =
386 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
387 auto *reg_info_a1 =
388 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
389 uint64_t raw_value = 0;
390
391 switch (byte_size) {
392 case sizeof(uint32_t):
393 // Read a0 to get the arg
394 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0) & UINT32_MAX;
395 break;
396 case sizeof(uint64_t):
397 // Read a0 to get the arg on loongarch64, a0 and a1 on loongarch32
398 if (llvm::Triple::loongarch32 == machine) {
399 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0) & UINT32_MAX;
400 raw_value |=
401 (reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a1, fail_value: 0) & UINT32_MAX) << 32U;
402 } else {
403 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0);
404 }
405 break;
406 case 16: {
407 // Read a0 and a1 to get the arg on loongarch64, not supported on
408 // loongarch32
409 if (llvm::Triple::loongarch32 == machine)
410 return return_valobj_sp;
411
412 // Create the ValueObjectSP here and return
413 std::unique_ptr<DataBufferHeap> heap_data_up(
414 new DataBufferHeap(byte_size, 0));
415 const ByteOrder byte_order = thread.GetProcess()->GetByteOrder();
416 RegisterValue reg_value_a0, reg_value_a1;
417 if (reg_ctx->ReadRegister(reg_info: reg_info_a0, reg_value&: reg_value_a0) &&
418 reg_ctx->ReadRegister(reg_info: reg_info_a1, reg_value&: reg_value_a1)) {
419 Status error;
420 if (reg_value_a0.GetAsMemoryData(reg_info: *reg_info_a0,
421 dst: heap_data_up->GetBytes() + 0, dst_len: 8,
422 dst_byte_order: byte_order, error) &&
423 reg_value_a1.GetAsMemoryData(reg_info: *reg_info_a1,
424 dst: heap_data_up->GetBytes() + 8, dst_len: 8,
425 dst_byte_order: byte_order, error)) {
426 value.SetBytes(bytes: heap_data_up.release(), len: byte_size);
427 return ValueObjectConstResult::Create(
428 exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString(""));
429 }
430 }
431 break;
432 }
433 default:
434 return return_valobj_sp;
435 }
436
437 if (type_flags & eTypeIsInteger) {
438 if (!SetSizedInteger(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size,
439 is_signed: type_flags & eTypeIsSigned))
440 return return_valobj_sp;
441 } else if (type_flags & eTypeIsFloat) {
442 if (!SetSizedFloat(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size))
443 return return_valobj_sp;
444 } else
445 return return_valobj_sp;
446
447 value.SetValueType(Value::ValueType::Scalar);
448 return_valobj_sp = ValueObjectConstResult::Create(
449 exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: ConstString(""));
450 return return_valobj_sp;
451}
452
453static ValueObjectSP GetValObjFromFPRegs(Thread &thread,
454 const RegisterContextSP &reg_ctx,
455 llvm::Triple::ArchType machine,
456 uint32_t type_flags,
457 uint32_t byte_size) {
458 auto *reg_info_fa0 = reg_ctx->GetRegisterInfoByName(reg_name: "f0");
459 bool use_fp_regs = false;
460 ValueObjectSP return_valobj_sp;
461
462 if (byte_size <= 8)
463 use_fp_regs = true;
464
465 if (use_fp_regs) {
466 uint64_t raw_value;
467 Value value;
468 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_fa0, fail_value: 0);
469 if (!SetSizedFloat(scalar&: value.GetScalar(), raw_value, size_in_bytes: byte_size))
470 return return_valobj_sp;
471 value.SetValueType(Value::ValueType::Scalar);
472 return ValueObjectConstResult::Create(exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(),
473 value, name: ConstString(""));
474 }
475 // we should never reach this, but if we do, use the integer registers
476 return GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
477}
478
479ValueObjectSP ABISysV_loongarch::GetReturnValueObjectSimple(
480 Thread &thread, CompilerType &compiler_type) const {
481 ValueObjectSP return_valobj_sp;
482
483 if (!compiler_type)
484 return return_valobj_sp;
485
486 auto reg_ctx = thread.GetRegisterContext();
487 if (!reg_ctx)
488 return return_valobj_sp;
489
490 Value value;
491 value.SetCompilerType(compiler_type);
492
493 const uint32_t type_flags = compiler_type.GetTypeInfo();
494 const size_t byte_size =
495 llvm::expectedToOptional(E: compiler_type.GetByteSize(exe_scope: &thread)).value_or(u: 0);
496 const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture();
497 const llvm::Triple::ArchType machine = arch.GetMachine();
498
499 if (type_flags & eTypeIsInteger) {
500 return_valobj_sp =
501 GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
502 return return_valobj_sp;
503 }
504 if (type_flags & eTypeIsPointer) {
505 const auto *reg_info_a0 = reg_ctx->GetRegisterInfo(
506 reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
507 value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info: reg_info_a0, fail_value: 0);
508 value.SetValueType(Value::ValueType::Scalar);
509 return ValueObjectConstResult::Create(exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(),
510 value, name: ConstString(""));
511 }
512 if (type_flags & eTypeIsFloat) {
513 uint32_t float_count = 0;
514 bool is_complex = false;
515
516 if (compiler_type.IsFloatingPointType(count&: float_count, is_complex) &&
517 float_count == 1 && !is_complex) {
518 return_valobj_sp =
519 GetValObjFromFPRegs(thread, reg_ctx, machine, type_flags, byte_size);
520 return return_valobj_sp;
521 }
522 }
523 return return_valobj_sp;
524}
525
526ValueObjectSP ABISysV_loongarch::GetReturnValueObjectImpl(
527 Thread &thread, CompilerType &return_compiler_type) const {
528 ValueObjectSP return_valobj_sp;
529
530 if (!return_compiler_type)
531 return return_valobj_sp;
532
533 ExecutionContext exe_ctx(thread.shared_from_this());
534 return GetReturnValueObjectSimple(thread, compiler_type&: return_compiler_type);
535}
536
537UnwindPlanSP ABISysV_loongarch::CreateFunctionEntryUnwindPlan() {
538 uint32_t pc_reg_num = loongarch_dwarf::dwarf_gpr_pc;
539 uint32_t sp_reg_num = loongarch_dwarf::dwarf_gpr_sp;
540 uint32_t ra_reg_num = loongarch_dwarf::dwarf_gpr_ra;
541
542 UnwindPlan::Row row;
543
544 // Define CFA as the stack pointer
545 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: sp_reg_num, offset: 0);
546
547 // Previous frame's pc is in ra
548 row.SetRegisterLocationToRegister(reg_num: pc_reg_num, other_reg_num: ra_reg_num, can_replace: true);
549
550 auto plan_sp = std::make_shared<UnwindPlan>(args: eRegisterKindDWARF);
551 plan_sp->AppendRow(row: std::move(row));
552 plan_sp->SetSourceName("loongarch function-entry unwind plan");
553 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);
554 return plan_sp;
555}
556
557UnwindPlanSP ABISysV_loongarch::CreateDefaultUnwindPlan() {
558 uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC;
559 uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP;
560
561 UnwindPlan::Row row;
562
563 // Define the CFA as the current frame pointer value.
564 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: fp_reg_num, offset: 0);
565
566 int reg_size = 4;
567 if (m_is_la64)
568 reg_size = 8;
569
570 // Assume the ra reg (return pc) and caller's frame pointer
571 // have been spilled to stack already.
572 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: fp_reg_num, offset: reg_size * -2, can_replace: true);
573 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: pc_reg_num, offset: reg_size * -1, can_replace: true);
574
575 auto plan_sp = std::make_shared<UnwindPlan>(args: eRegisterKindGeneric);
576 plan_sp->AppendRow(row: std::move(row));
577 plan_sp->SetSourceName("loongarch default unwind plan");
578 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);
579 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
580 return plan_sp;
581}
582
583bool ABISysV_loongarch::RegisterIsVolatile(const RegisterInfo *reg_info) {
584 return !RegisterIsCalleeSaved(reg_info);
585}
586
587bool ABISysV_loongarch::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
588 if (!reg_info)
589 return false;
590
591 const char *name = reg_info->name;
592 ArchSpec arch = GetProcessSP()->GetTarget().GetArchitecture();
593 uint32_t arch_flags = arch.GetFlags();
594 // Floating point registers are only callee saved when using
595 // F or D hardware floating point ABIs.
596 bool is_hw_fp = (arch_flags & ArchSpec::eLoongArch_abi_mask) != 0;
597
598 return llvm::StringSwitch<bool>(name)
599 // integer ABI names
600 .Cases(S0: "ra", S1: "sp", S2: "fp", Value: true)
601 .Cases(S0: "s0", S1: "s1", S2: "s2", S3: "s3", S4: "s4", S5: "s5", S6: "s6", S7: "s7", S8: "s8", S9: "s9", Value: true)
602 // integer hardware names
603 .Cases(S0: "r1", S1: "r3", S2: "r22", Value: true)
604 .Cases(S0: "r23", S1: "r24", S2: "r25", S3: "r26", S4: "r27", S5: "r28", S6: "r29", S7: "r30", S8: "31", Value: true)
605 // floating point ABI names
606 .Cases(S0: "fs0", S1: "fs1", S2: "fs2", S3: "fs3", S4: "fs4", S5: "fs5", S6: "fs6", S7: "fs7", Value: is_hw_fp)
607 // floating point hardware names
608 .Cases(S0: "f24", S1: "f25", S2: "f26", S3: "f27", S4: "f28", S5: "f29", S6: "f30", S7: "f31", Value: is_hw_fp)
609 .Default(Value: false);
610}
611
612void ABISysV_loongarch::Initialize() {
613 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
614 description: "System V ABI for LoongArch targets",
615 create_callback: CreateInstance);
616}
617
618void ABISysV_loongarch::Terminate() {
619 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
620}
621
622static uint32_t GetGenericNum(llvm::StringRef name) {
623 return llvm::StringSwitch<uint32_t>(name)
624 .Case(S: "pc", LLDB_REGNUM_GENERIC_PC)
625 .Cases(S0: "ra", S1: "r1", LLDB_REGNUM_GENERIC_RA)
626 .Cases(S0: "sp", S1: "r3", LLDB_REGNUM_GENERIC_SP)
627 .Cases(S0: "fp", S1: "r22", LLDB_REGNUM_GENERIC_FP)
628 .Cases(S0: "a0", S1: "r4", LLDB_REGNUM_GENERIC_ARG1)
629 .Cases(S0: "a1", S1: "r5", LLDB_REGNUM_GENERIC_ARG2)
630 .Cases(S0: "a2", S1: "r6", LLDB_REGNUM_GENERIC_ARG3)
631 .Cases(S0: "a3", S1: "r7", LLDB_REGNUM_GENERIC_ARG4)
632 .Cases(S0: "a4", S1: "r8", LLDB_REGNUM_GENERIC_ARG5)
633 .Cases(S0: "a5", S1: "r9", LLDB_REGNUM_GENERIC_ARG6)
634 .Cases(S0: "a6", S1: "r10", LLDB_REGNUM_GENERIC_ARG7)
635 .Cases(S0: "a7", S1: "r11", LLDB_REGNUM_GENERIC_ARG8)
636 .Default(LLDB_INVALID_REGNUM);
637}
638
639void ABISysV_loongarch::AugmentRegisterInfo(
640 std::vector<lldb_private::DynamicRegisterInfo::Register> &regs) {
641 lldb_private::RegInfoBasedABI::AugmentRegisterInfo(regs);
642
643 static const llvm::StringMap<llvm::StringRef> isa_to_abi_alias_map = {
644 {"r0", "zero"}, {"r1", "ra"}, {"r2", "tp"}, {"r3", "sp"},
645 {"r4", "a0"}, {"r5", "a1"}, {"r6", "a2"}, {"r7", "a3"},
646 {"r8", "a4"}, {"r9", "a5"}, {"r10", "a6"}, {"r11", "a7"},
647 {"r12", "t0"}, {"r13", "t1"}, {"r14", "t2"}, {"r15", "t3"},
648 {"r16", "t4"}, {"r17", "t5"}, {"r18", "t6"}, {"r19", "t7"},
649 {"r20", "t8"}, {"r22", "fp"}, {"r23", "s0"}, {"r24", "s1"},
650 {"r25", "s2"}, {"r26", "s3"}, {"r27", "s4"}, {"r28", "s5"},
651 {"r29", "s6"}, {"r30", "s7"}, {"r31", "s8"}};
652
653 for (auto it : llvm::enumerate(First&: regs)) {
654 llvm::StringRef reg_name = it.value().name.GetStringRef();
655
656 // Set alt name for certain registers for convenience
657 llvm::StringRef alias_name = isa_to_abi_alias_map.lookup(Key: reg_name);
658 if (!alias_name.empty())
659 it.value().alt_name.SetString(alias_name);
660
661 // Set generic regnum so lldb knows what the PC, etc is
662 it.value().regnum_generic = GetGenericNum(name: reg_name);
663 }
664}
665

source code of lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp