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