Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / ABI / Mips / ABISysV_mips.cpp
blob0f99afa35a719acce5847116535f2527a6826690
1 //===-- ABISysV_mips.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 //===----------------------------------------------------------------------===//
9 #include "ABISysV_mips.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/TargetParser/Triple.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/Value.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/Core/ValueObjectMemory.h"
19 #include "lldb/Core/ValueObjectRegister.h"
20 #include "lldb/Symbol/UnwindPlan.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Utility/ConstString.h"
27 #include "lldb/Utility/DataExtractor.h"
28 #include "lldb/Utility/LLDBLog.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/RegisterValue.h"
31 #include "lldb/Utility/Status.h"
32 #include <optional>
34 using namespace lldb;
35 using namespace lldb_private;
37 LLDB_PLUGIN_DEFINE(ABISysV_mips)
39 enum dwarf_regnums {
40 dwarf_r0 = 0,
41 dwarf_r1,
42 dwarf_r2,
43 dwarf_r3,
44 dwarf_r4,
45 dwarf_r5,
46 dwarf_r6,
47 dwarf_r7,
48 dwarf_r8,
49 dwarf_r9,
50 dwarf_r10,
51 dwarf_r11,
52 dwarf_r12,
53 dwarf_r13,
54 dwarf_r14,
55 dwarf_r15,
56 dwarf_r16,
57 dwarf_r17,
58 dwarf_r18,
59 dwarf_r19,
60 dwarf_r20,
61 dwarf_r21,
62 dwarf_r22,
63 dwarf_r23,
64 dwarf_r24,
65 dwarf_r25,
66 dwarf_r26,
67 dwarf_r27,
68 dwarf_r28,
69 dwarf_r29,
70 dwarf_r30,
71 dwarf_r31,
72 dwarf_sr,
73 dwarf_lo,
74 dwarf_hi,
75 dwarf_bad,
76 dwarf_cause,
77 dwarf_pc
80 static const RegisterInfo g_register_infos[] = {
81 // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME
82 // DWARF GENERIC PROCESS PLUGINS
83 // LLDB NATIVE VALUE REGS INVALIDATE REGS
84 // ======== ====== == === ============= =========== ============
85 // ============== ============ =================
86 // =================== ========== =================
87 {"r0",
88 "zero",
91 eEncodingUint,
92 eFormatHex,
93 {dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
94 LLDB_INVALID_REGNUM},
95 nullptr,
96 nullptr,
97 nullptr,
99 {"r1",
100 "AT",
103 eEncodingUint,
104 eFormatHex,
105 {dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
106 LLDB_INVALID_REGNUM},
107 nullptr,
108 nullptr,
109 nullptr,
111 {"r2",
112 "v0",
115 eEncodingUint,
116 eFormatHex,
117 {dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
118 LLDB_INVALID_REGNUM},
119 nullptr,
120 nullptr,
121 nullptr,
123 {"r3",
124 "v1",
127 eEncodingUint,
128 eFormatHex,
129 {dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
130 LLDB_INVALID_REGNUM},
131 nullptr,
132 nullptr,
133 nullptr,
135 {"r4",
136 nullptr,
139 eEncodingUint,
140 eFormatHex,
141 {dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,
142 LLDB_INVALID_REGNUM},
143 nullptr,
144 nullptr,
145 nullptr,
147 {"r5",
148 nullptr,
151 eEncodingUint,
152 eFormatHex,
153 {dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,
154 LLDB_INVALID_REGNUM},
155 nullptr,
156 nullptr,
157 nullptr,
159 {"r6",
160 nullptr,
163 eEncodingUint,
164 eFormatHex,
165 {dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,
166 LLDB_INVALID_REGNUM},
167 nullptr,
168 nullptr,
169 nullptr,
171 {"r7",
172 nullptr,
175 eEncodingUint,
176 eFormatHex,
177 {dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,
178 LLDB_INVALID_REGNUM},
179 nullptr,
180 nullptr,
181 nullptr,
183 {"r8",
184 "arg5",
187 eEncodingUint,
188 eFormatHex,
189 {dwarf_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
190 LLDB_INVALID_REGNUM},
191 nullptr,
192 nullptr,
193 nullptr,
195 {"r9",
196 "arg6",
199 eEncodingUint,
200 eFormatHex,
201 {dwarf_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
202 LLDB_INVALID_REGNUM},
203 nullptr,
204 nullptr,
205 nullptr,
207 {"r10",
208 "arg7",
211 eEncodingUint,
212 eFormatHex,
213 {dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
214 LLDB_INVALID_REGNUM},
215 nullptr,
216 nullptr,
217 nullptr,
219 {"r11",
220 "arg8",
223 eEncodingUint,
224 eFormatHex,
225 {dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
226 LLDB_INVALID_REGNUM},
227 nullptr,
228 nullptr,
229 nullptr,
231 {"r12",
232 nullptr,
235 eEncodingUint,
236 eFormatHex,
237 {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
238 LLDB_INVALID_REGNUM},
239 nullptr,
240 nullptr,
241 nullptr,
243 {"r13",
244 nullptr,
247 eEncodingUint,
248 eFormatHex,
249 {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
250 LLDB_INVALID_REGNUM},
251 nullptr,
252 nullptr,
253 nullptr,
255 {"r14",
256 nullptr,
259 eEncodingUint,
260 eFormatHex,
261 {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
262 LLDB_INVALID_REGNUM},
263 nullptr,
264 nullptr,
265 nullptr,
267 {"r15",
268 nullptr,
271 eEncodingUint,
272 eFormatHex,
273 {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
274 LLDB_INVALID_REGNUM},
275 nullptr,
276 nullptr,
277 nullptr,
279 {"r16",
280 nullptr,
283 eEncodingUint,
284 eFormatHex,
285 {dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
286 LLDB_INVALID_REGNUM},
287 nullptr,
288 nullptr,
289 nullptr,
291 {"r17",
292 nullptr,
295 eEncodingUint,
296 eFormatHex,
297 {dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
298 LLDB_INVALID_REGNUM},
299 nullptr,
300 nullptr,
301 nullptr,
303 {"r18",
304 nullptr,
307 eEncodingUint,
308 eFormatHex,
309 {dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
310 LLDB_INVALID_REGNUM},
311 nullptr,
312 nullptr,
313 nullptr,
315 {"r19",
316 nullptr,
319 eEncodingUint,
320 eFormatHex,
321 {dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
322 LLDB_INVALID_REGNUM},
323 nullptr,
324 nullptr,
325 nullptr,
327 {"r20",
328 nullptr,
331 eEncodingUint,
332 eFormatHex,
333 {dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
334 LLDB_INVALID_REGNUM},
335 nullptr,
336 nullptr,
337 nullptr,
339 {"r21",
340 nullptr,
343 eEncodingUint,
344 eFormatHex,
345 {dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
346 LLDB_INVALID_REGNUM},
347 nullptr,
348 nullptr,
349 nullptr,
351 {"r22",
352 nullptr,
355 eEncodingUint,
356 eFormatHex,
357 {dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
358 LLDB_INVALID_REGNUM},
359 nullptr,
360 nullptr,
361 nullptr,
363 {"r23",
364 nullptr,
367 eEncodingUint,
368 eFormatHex,
369 {dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
370 LLDB_INVALID_REGNUM},
371 nullptr,
372 nullptr,
373 nullptr,
375 {"r24",
376 nullptr,
379 eEncodingUint,
380 eFormatHex,
381 {dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
382 LLDB_INVALID_REGNUM},
383 nullptr,
384 nullptr,
385 nullptr,
387 {"r25",
388 nullptr,
391 eEncodingUint,
392 eFormatHex,
393 {dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
394 LLDB_INVALID_REGNUM},
395 nullptr,
396 nullptr,
397 nullptr,
399 {"r26",
400 nullptr,
403 eEncodingUint,
404 eFormatHex,
405 {dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
406 LLDB_INVALID_REGNUM},
407 nullptr,
408 nullptr,
409 nullptr,
411 {"r27",
412 nullptr,
415 eEncodingUint,
416 eFormatHex,
417 {dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
418 LLDB_INVALID_REGNUM},
419 nullptr,
420 nullptr,
421 nullptr,
423 {"r28",
424 "gp",
427 eEncodingUint,
428 eFormatHex,
429 {dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
430 LLDB_INVALID_REGNUM},
431 nullptr,
432 nullptr,
433 nullptr,
435 {"r29",
436 nullptr,
439 eEncodingUint,
440 eFormatHex,
441 {dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
442 LLDB_INVALID_REGNUM},
443 nullptr,
444 nullptr,
445 nullptr,
447 {"r30",
448 nullptr,
451 eEncodingUint,
452 eFormatHex,
453 {dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
454 LLDB_INVALID_REGNUM},
455 nullptr,
456 nullptr,
457 nullptr,
459 {"r31",
460 nullptr,
463 eEncodingUint,
464 eFormatHex,
465 {dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
466 LLDB_INVALID_REGNUM},
467 nullptr,
468 nullptr,
469 nullptr,
471 {"sr",
472 nullptr,
475 eEncodingUint,
476 eFormatHex,
477 {dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,
478 LLDB_INVALID_REGNUM},
479 nullptr,
480 nullptr,
481 nullptr,
483 {"lo",
484 nullptr,
487 eEncodingUint,
488 eFormatHex,
489 {dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
490 LLDB_INVALID_REGNUM},
491 nullptr,
492 nullptr,
493 nullptr,
495 {"hi",
496 nullptr,
499 eEncodingUint,
500 eFormatHex,
501 {dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
502 LLDB_INVALID_REGNUM},
503 nullptr,
504 nullptr,
505 nullptr,
507 {"bad",
508 nullptr,
511 eEncodingUint,
512 eFormatHex,
513 {dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
514 LLDB_INVALID_REGNUM},
515 nullptr,
516 nullptr,
517 nullptr,
519 {"cause",
520 nullptr,
523 eEncodingUint,
524 eFormatHex,
525 {dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
526 LLDB_INVALID_REGNUM},
527 nullptr,
528 nullptr,
529 nullptr,
531 {"pc",
532 nullptr,
535 eEncodingUint,
536 eFormatHex,
537 {dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
538 LLDB_INVALID_REGNUM},
539 nullptr,
540 nullptr,
541 nullptr,
545 static const uint32_t k_num_register_infos = std::size(g_register_infos);
547 const lldb_private::RegisterInfo *
548 ABISysV_mips::GetRegisterInfoArray(uint32_t &count) {
549 count = k_num_register_infos;
550 return g_register_infos;
553 size_t ABISysV_mips::GetRedZoneSize() const { return 0; }
555 // Static Functions
557 ABISP
558 ABISysV_mips::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
559 const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
560 if ((arch_type == llvm::Triple::mips) ||
561 (arch_type == llvm::Triple::mipsel)) {
562 return ABISP(
563 new ABISysV_mips(std::move(process_sp), MakeMCRegisterInfo(arch)));
565 return ABISP();
568 bool ABISysV_mips::PrepareTrivialCall(Thread &thread, addr_t sp,
569 addr_t func_addr, addr_t return_addr,
570 llvm::ArrayRef<addr_t> args) const {
571 Log *log = GetLog(LLDBLog::Expressions);
573 if (log) {
574 StreamString s;
575 s.Printf("ABISysV_mips::PrepareTrivialCall (tid = 0x%" PRIx64
576 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
577 ", return_addr = 0x%" PRIx64,
578 thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
579 (uint64_t)return_addr);
581 for (size_t i = 0; i < args.size(); ++i)
582 s.Printf(", arg%zd = 0x%" PRIx64, i + 1, args[i]);
583 s.PutCString(")");
584 log->PutString(s.GetString());
587 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
588 if (!reg_ctx)
589 return false;
591 const RegisterInfo *reg_info = nullptr;
593 RegisterValue reg_value;
595 // Argument registers
596 const char *reg_names[] = {"r4", "r5", "r6", "r7"};
598 llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
600 // Write arguments to registers
601 for (size_t i = 0; i < std::size(reg_names); ++i) {
602 if (ai == ae)
603 break;
605 reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
606 LLDB_REGNUM_GENERIC_ARG1 + i);
607 LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") into %s", i + 1,
608 args[i], reg_info->name);
610 if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
611 return false;
613 ++ai;
616 // If we have more than 4 arguments --Spill onto the stack
617 if (ai != ae) {
618 // No of arguments to go on stack
619 size_t num_stack_regs = args.size();
621 // Allocate needed space for args on the stack
622 sp -= (num_stack_regs * 4);
624 // Keep the stack 8 byte aligned
625 sp &= ~(8ull - 1ull);
627 // just using arg1 to get the right size
628 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
629 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
631 addr_t arg_pos = sp + 16;
633 size_t i = 4;
634 for (; ai != ae; ++ai) {
635 reg_value.SetUInt32(*ai);
636 LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") at 0x%" PRIx64 "",
637 i + 1, args[i], arg_pos);
639 if (reg_ctx
640 ->WriteRegisterValueToMemory(reg_info, arg_pos,
641 reg_info->byte_size, reg_value)
642 .Fail())
643 return false;
644 arg_pos += reg_info->byte_size;
645 i++;
649 Status error;
650 const RegisterInfo *pc_reg_info =
651 reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
652 const RegisterInfo *sp_reg_info =
653 reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
654 const RegisterInfo *ra_reg_info =
655 reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
656 const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0);
657 const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0);
659 LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0);
661 /* Write r0 with 0, in case we are stopped in syscall,
662 * such setting prevents automatic decrement of the PC.
663 * This clears the bug 23659 for MIPS.
665 if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0))
666 return false;
668 LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
670 // Set "sp" to the requested value
671 if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
672 return false;
674 LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
676 // Set "ra" to the return address
677 if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))
678 return false;
680 LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
682 // Set pc to the address of the called function.
683 if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
684 return false;
686 LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr);
688 // All callers of position independent functions must place the address of
689 // the called function in t9 (r25)
690 if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr))
691 return false;
693 return true;
696 bool ABISysV_mips::GetArgumentValues(Thread &thread, ValueList &values) const {
697 return false;
700 Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
701 lldb::ValueObjectSP &new_value_sp) {
702 Status error;
703 if (!new_value_sp) {
704 error.SetErrorString("Empty value object for return value.");
705 return error;
708 CompilerType compiler_type = new_value_sp->GetCompilerType();
709 if (!compiler_type) {
710 error.SetErrorString("Null clang type for return value.");
711 return error;
714 Thread *thread = frame_sp->GetThread().get();
716 bool is_signed;
717 uint32_t count;
718 bool is_complex;
720 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
722 bool set_it_simple = false;
723 if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
724 compiler_type.IsPointerType()) {
725 DataExtractor data;
726 Status data_error;
727 size_t num_bytes = new_value_sp->GetData(data, data_error);
728 if (data_error.Fail()) {
729 error.SetErrorStringWithFormat(
730 "Couldn't convert return value to raw data: %s",
731 data_error.AsCString());
732 return error;
735 lldb::offset_t offset = 0;
736 if (num_bytes <= 8) {
737 const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
738 if (num_bytes <= 4) {
739 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
741 if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value))
742 set_it_simple = true;
743 } else {
744 uint32_t raw_value = data.GetMaxU32(&offset, 4);
746 if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) {
747 const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);
748 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
750 if (reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value))
751 set_it_simple = true;
754 } else {
755 error.SetErrorString("We don't support returning longer than 64 bit "
756 "integer values at present.");
758 } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
759 if (is_complex)
760 error.SetErrorString(
761 "We don't support returning complex values at present");
762 else
763 error.SetErrorString(
764 "We don't support returning float values at present");
767 if (!set_it_simple)
768 error.SetErrorString(
769 "We only support setting simple integer return types at present.");
771 return error;
774 ValueObjectSP ABISysV_mips::GetReturnValueObjectSimple(
775 Thread &thread, CompilerType &return_compiler_type) const {
776 ValueObjectSP return_valobj_sp;
777 return return_valobj_sp;
780 ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
781 Thread &thread, CompilerType &return_compiler_type) const {
782 ValueObjectSP return_valobj_sp;
783 Value value;
785 if (!return_compiler_type)
786 return return_valobj_sp;
788 ExecutionContext exe_ctx(thread.shared_from_this());
789 if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
790 return return_valobj_sp;
792 Target *target = exe_ctx.GetTargetPtr();
793 const ArchSpec target_arch = target->GetArchitecture();
794 ByteOrder target_byte_order = target_arch.GetByteOrder();
795 value.SetCompilerType(return_compiler_type);
796 uint32_t fp_flag =
797 target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask;
799 RegisterContext *reg_ctx = thread.GetRegisterContext().get();
800 if (!reg_ctx)
801 return return_valobj_sp;
803 bool is_signed = false;
804 bool is_complex = false;
805 uint32_t count = 0;
807 // In MIPS register "r2" (v0) holds the integer function return values
808 const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);
809 std::optional<uint64_t> bit_width = return_compiler_type.GetBitSize(&thread);
810 if (!bit_width)
811 return return_valobj_sp;
812 if (return_compiler_type.IsIntegerOrEnumerationType(is_signed)) {
813 switch (*bit_width) {
814 default:
815 return return_valobj_sp;
816 case 64: {
817 const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
818 uint64_t raw_value;
819 raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX;
820 raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0) &
821 UINT32_MAX))
822 << 32;
823 if (is_signed)
824 value.GetScalar() = (int64_t)raw_value;
825 else
826 value.GetScalar() = (uint64_t)raw_value;
827 } break;
828 case 32:
829 if (is_signed)
830 value.GetScalar() = (int32_t)(
831 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
832 else
833 value.GetScalar() = (uint32_t)(
834 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
835 break;
836 case 16:
837 if (is_signed)
838 value.GetScalar() = (int16_t)(
839 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
840 else
841 value.GetScalar() = (uint16_t)(
842 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
843 break;
844 case 8:
845 if (is_signed)
846 value.GetScalar() = (int8_t)(
847 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
848 else
849 value.GetScalar() = (uint8_t)(
850 reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
851 break;
853 } else if (return_compiler_type.IsPointerType()) {
854 uint32_t ptr =
855 thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_reg_info, 0) &
856 UINT32_MAX;
857 value.GetScalar() = ptr;
858 } else if (return_compiler_type.IsAggregateType()) {
859 // Structure/Vector is always passed in memory and pointer to that memory
860 // is passed in r2.
861 uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(
862 reg_ctx->GetRegisterInfoByName("r2", 0), 0);
863 // We have got the address. Create a memory object out of it
864 return_valobj_sp = ValueObjectMemory::Create(
865 &thread, "", Address(mem_address, nullptr), return_compiler_type);
866 return return_valobj_sp;
867 } else if (return_compiler_type.IsFloatingPointType(count, is_complex)) {
868 if (IsSoftFloat(fp_flag)) {
869 uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
870 if (count != 1 && is_complex)
871 return return_valobj_sp;
872 switch (*bit_width) {
873 default:
874 return return_valobj_sp;
875 case 32:
876 static_assert(sizeof(float) == sizeof(uint32_t));
877 value.GetScalar() = *((float *)(&raw_value));
878 break;
879 case 64:
880 static_assert(sizeof(double) == sizeof(uint64_t));
881 const RegisterInfo *r3_reg_info =
882 reg_ctx->GetRegisterInfoByName("r3", 0);
883 if (target_byte_order == eByteOrderLittle)
884 raw_value =
885 ((reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0)) << 32) |
886 raw_value;
887 else
888 raw_value = (raw_value << 32) |
889 reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0);
890 value.GetScalar() = *((double *)(&raw_value));
891 break;
895 else {
896 const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);
897 RegisterValue f0_value;
898 DataExtractor f0_data;
899 reg_ctx->ReadRegister(f0_info, f0_value);
900 f0_value.GetData(f0_data);
901 lldb::offset_t offset = 0;
903 if (count == 1 && !is_complex) {
904 switch (*bit_width) {
905 default:
906 return return_valobj_sp;
907 case 64: {
908 static_assert(sizeof(double) == sizeof(uint64_t));
909 const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);
910 RegisterValue f1_value;
911 DataExtractor f1_data;
912 reg_ctx->ReadRegister(f1_info, f1_value);
913 DataExtractor *copy_from_extractor = nullptr;
914 WritableDataBufferSP data_sp(new DataBufferHeap(8, 0));
915 DataExtractor return_ext(
916 data_sp, target_byte_order,
917 target->GetArchitecture().GetAddressByteSize());
919 if (target_byte_order == eByteOrderLittle) {
920 copy_from_extractor = &f0_data;
921 copy_from_extractor->CopyByteOrderedData(
922 offset, 4, data_sp->GetBytes(), 4, target_byte_order);
923 f1_value.GetData(f1_data);
924 copy_from_extractor = &f1_data;
925 copy_from_extractor->CopyByteOrderedData(
926 offset, 4, data_sp->GetBytes() + 4, 4, target_byte_order);
927 } else {
928 copy_from_extractor = &f0_data;
929 copy_from_extractor->CopyByteOrderedData(
930 offset, 4, data_sp->GetBytes() + 4, 4, target_byte_order);
931 f1_value.GetData(f1_data);
932 copy_from_extractor = &f1_data;
933 copy_from_extractor->CopyByteOrderedData(
934 offset, 4, data_sp->GetBytes(), 4, target_byte_order);
936 value.GetScalar() = (double)return_ext.GetDouble(&offset);
937 break;
939 case 32: {
940 static_assert(sizeof(float) == sizeof(uint32_t));
941 value.GetScalar() = (float)f0_data.GetFloat(&offset);
942 break;
945 } else {
946 // not handled yet
947 return return_valobj_sp;
950 } else {
951 // not handled yet
952 return return_valobj_sp;
955 // If we get here, we have a valid Value, so make our ValueObject out of it:
957 return_valobj_sp = ValueObjectConstResult::Create(
958 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
959 return return_valobj_sp;
962 bool ABISysV_mips::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
963 unwind_plan.Clear();
964 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
966 UnwindPlan::RowSP row(new UnwindPlan::Row);
968 // Our Call Frame Address is the stack pointer value
969 row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
971 // The previous PC is in the RA
972 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
973 unwind_plan.AppendRow(row);
975 // All other registers are the same.
977 unwind_plan.SetSourceName("mips at-func-entry default");
978 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
979 unwind_plan.SetReturnAddressRegister(dwarf_r31);
980 return true;
983 bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
984 unwind_plan.Clear();
985 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
987 UnwindPlan::RowSP row(new UnwindPlan::Row);
989 row->SetUnspecifiedRegistersAreUndefined(true);
990 row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
992 row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
994 unwind_plan.AppendRow(row);
995 unwind_plan.SetSourceName("mips default unwind plan");
996 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
997 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
998 unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
999 return true;
1002 bool ABISysV_mips::RegisterIsVolatile(const RegisterInfo *reg_info) {
1003 return !RegisterIsCalleeSaved(reg_info);
1006 bool ABISysV_mips::IsSoftFloat(uint32_t fp_flags) const {
1007 return (fp_flags == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);
1010 bool ABISysV_mips::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
1011 if (reg_info) {
1012 // Preserved registers are :
1013 // r16-r23, r28, r29, r30, r31
1014 const char *name = reg_info->name;
1016 if (name[0] == 'r') {
1017 switch (name[1]) {
1018 case '1':
1019 if (name[2] == '6' || name[2] == '7' || name[2] == '8' ||
1020 name[2] == '9') // r16-r19
1021 return name[3] == '\0';
1022 break;
1023 case '2':
1024 if (name[2] == '0' || name[2] == '1' || name[2] == '2' ||
1025 name[2] == '3' // r20-r23
1026 || name[2] == '8' || name[2] == '9') // r28 and r29
1027 return name[3] == '\0';
1028 break;
1029 case '3':
1030 if (name[2] == '0' || name[2] == '1') // r30 and r31
1031 return name[3] == '\0';
1032 break;
1035 if (name[0] == 'g' && name[1] == 'p' && name[2] == '\0') // gp (r28)
1036 return true;
1037 if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp (r29)
1038 return true;
1039 if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp (r30)
1040 return true;
1041 if (name[0] == 'r' && name[1] == 'a' && name[2] == '\0') // ra (r31)
1042 return true;
1045 return false;
1048 void ABISysV_mips::Initialize() {
1049 PluginManager::RegisterPlugin(
1050 GetPluginNameStatic(), "System V ABI for mips targets", CreateInstance);
1053 void ABISysV_mips::Terminate() {
1054 PluginManager::UnregisterPlugin(CreateInstance);