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/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>
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     //  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",
89      4,
90      0,
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,
98     },
99     {"r1",
100      "AT",
101      4,
102      0,
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,
110     },
111     {"r2",
112      "v0",
113      4,
114      0,
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,
122     },
123     {"r3",
124      "v1",
125      4,
126      0,
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,
134     },
135     {"r4",
136      nullptr,
137      4,
138      0,
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,
146     },
147     {"r5",
148      nullptr,
149      4,
150      0,
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,
158     },
159     {"r6",
160      nullptr,
161      4,
162      0,
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,
170     },
171     {"r7",
172      nullptr,
173      4,
174      0,
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,
182     },
183     {"r8",
184      "arg5",
185      4,
186      0,
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,
194     },
195     {"r9",
196      "arg6",
197      4,
198      0,
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,
206     },
207     {"r10",
208      "arg7",
209      4,
210      0,
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,
218     },
219     {"r11",
220      "arg8",
221      4,
222      0,
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,
230     },
231     {"r12",
232      nullptr,
233      4,
234      0,
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,
242     },
243     {"r13",
244      nullptr,
245      4,
246      0,
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,
254     },
255     {"r14",
256      nullptr,
257      4,
258      0,
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,
266     },
267     {"r15",
268      nullptr,
269      4,
270      0,
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,
278     },
279     {"r16",
280      nullptr,
281      4,
282      0,
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,
290     },
291     {"r17",
292      nullptr,
293      4,
294      0,
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,
302     },
303     {"r18",
304      nullptr,
305      4,
306      0,
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,
314     },
315     {"r19",
316      nullptr,
317      4,
318      0,
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,
326     },
327     {"r20",
328      nullptr,
329      4,
330      0,
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,
338     },
339     {"r21",
340      nullptr,
341      4,
342      0,
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,
350     },
351     {"r22",
352      nullptr,
353      4,
354      0,
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,
362     },
363     {"r23",
364      nullptr,
365      4,
366      0,
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,
374     },
375     {"r24",
376      nullptr,
377      4,
378      0,
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,
386     },
387     {"r25",
388      nullptr,
389      4,
390      0,
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,
398     },
399     {"r26",
400      nullptr,
401      4,
402      0,
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,
410     },
411     {"r27",
412      nullptr,
413      4,
414      0,
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,
422     },
423     {"r28",
424      "gp",
425      4,
426      0,
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,
434     },
435     {"r29",
436      nullptr,
437      4,
438      0,
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,
446     },
447     {"r30",
448      nullptr,
449      4,
450      0,
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,
458     },
459     {"r31",
460      nullptr,
461      4,
462      0,
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,
470     },
471     {"sr",
472      nullptr,
473      4,
474      0,
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,
482     },
483     {"lo",
484      nullptr,
485      4,
486      0,
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,
494     },
495     {"hi",
496      nullptr,
497      4,
498      0,
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,
506     },
507     {"bad",
508      nullptr,
509      4,
510      0,
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,
518     },
519     {"cause",
520      nullptr,
521      4,
522      0,
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,
530     },
531     {"pc",
532      nullptr,
533      4,
534      0,
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,
542     },
543 };
544 
545 static const uint32_t k_num_register_infos = std::size(g_register_infos);
546 
547 const lldb_private::RegisterInfo *
548 ABISysV_mips::GetRegisterInfoArray(uint32_t &count) {
549   count = k_num_register_infos;
550   return g_register_infos;
551 }
552 
553 size_t ABISysV_mips::GetRedZoneSize() const { return 0; }
554 
555 // Static Functions
556 
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)));
564   }
565   return ABISP();
566 }
567 
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);
572 
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);
580 
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());
585   }
586 
587   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
588   if (!reg_ctx)
589     return false;
590 
591   const RegisterInfo *reg_info = nullptr;
592 
593   RegisterValue reg_value;
594 
595   // Argument registers
596   const char *reg_names[] = {"r4", "r5", "r6", "r7"};
597 
598   llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
599 
600   // Write arguments to registers
601   for (size_t i = 0; i < std::size(reg_names); ++i) {
602     if (ai == ae)
603       break;
604 
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);
609 
610     if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
611       return false;
612 
613     ++ai;
614   }
615 
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();
620 
621     // Allocate needed space for args on the stack
622     sp -= (num_stack_regs * 4);
623 
624     // Keep the stack 8 byte aligned
625     sp &= ~(8ull - 1ull);
626 
627     // just using arg1 to get the right size
628     const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
629         eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
630 
631     addr_t arg_pos = sp + 16;
632 
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);
638 
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++;
646     }
647   }
648 
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);
658 
659   LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0);
660 
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.
664   */
665   if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0))
666     return false;
667 
668   LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
669 
670   // Set "sp" to the requested value
671   if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
672     return false;
673 
674   LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
675 
676   // Set "ra" to the return address
677   if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))
678     return false;
679 
680   LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
681 
682   // Set pc to the address of the called function.
683   if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
684     return false;
685 
686   LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr);
687 
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;
692 
693   return true;
694 }
695 
696 bool ABISysV_mips::GetArgumentValues(Thread &thread, ValueList &values) const {
697   return false;
698 }
699 
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;
706   }
707 
708   CompilerType compiler_type = new_value_sp->GetCompilerType();
709   if (!compiler_type) {
710     error.SetErrorString("Null clang type for return value.");
711     return error;
712   }
713 
714   Thread *thread = frame_sp->GetThread().get();
715 
716   bool is_signed;
717   uint32_t count;
718   bool is_complex;
719 
720   RegisterContext *reg_ctx = thread->GetRegisterContext().get();
721 
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;
733     }
734 
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);
740 
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);
745 
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);
749 
750           if (reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value))
751             set_it_simple = true;
752         }
753       }
754     } else {
755       error.SetErrorString("We don't support returning longer than 64 bit "
756                            "integer values at present.");
757     }
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");
765   }
766 
767   if (!set_it_simple)
768     error.SetErrorString(
769         "We only support setting simple integer return types at present.");
770 
771   return error;
772 }
773 
774 ValueObjectSP ABISysV_mips::GetReturnValueObjectSimple(
775     Thread &thread, CompilerType &return_compiler_type) const {
776   ValueObjectSP return_valobj_sp;
777   return return_valobj_sp;
778 }
779 
780 ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
781     Thread &thread, CompilerType &return_compiler_type) const {
782   ValueObjectSP return_valobj_sp;
783   Value value;
784 
785   if (!return_compiler_type)
786     return return_valobj_sp;
787 
788   ExecutionContext exe_ctx(thread.shared_from_this());
789   if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
790     return return_valobj_sp;
791 
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;
798 
799   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
800   if (!reg_ctx)
801     return return_valobj_sp;
802 
803   bool is_signed = false;
804   bool is_complex = false;
805   uint32_t count = 0;
806 
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;
852     }
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;
892       }
893     }
894 
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;
902 
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());
918 
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);
935           }
936           value.GetScalar() = (double)return_ext.GetDouble(&offset);
937           break;
938         }
939         case 32: {
940           static_assert(sizeof(float) == sizeof(uint32_t));
941           value.GetScalar() = (float)f0_data.GetFloat(&offset);
942           break;
943         }
944         }
945       } else {
946         // not handled yet
947         return return_valobj_sp;
948       }
949     }
950   } else {
951     // not handled yet
952     return return_valobj_sp;
953   }
954 
955   // If we get here, we have a valid Value, so make our ValueObject out of it:
956 
957   return_valobj_sp = ValueObjectConstResult::Create(
958       thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
959   return return_valobj_sp;
960 }
961 
962 bool ABISysV_mips::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
963   unwind_plan.Clear();
964   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
965 
966   UnwindPlan::RowSP row(new UnwindPlan::Row);
967 
968   // Our Call Frame Address is the stack pointer value
969   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
970 
971   // The previous PC is in the RA
972   row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
973   unwind_plan.AppendRow(row);
974 
975   // All other registers are the same.
976 
977   unwind_plan.SetSourceName("mips at-func-entry default");
978   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
979   unwind_plan.SetReturnAddressRegister(dwarf_r31);
980   return true;
981 }
982 
983 bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
984   unwind_plan.Clear();
985   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
986 
987   UnwindPlan::RowSP row(new UnwindPlan::Row);
988 
989   row->SetUnspecifiedRegistersAreUndefined(true);
990   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
991 
992   row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
993 
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;
1000 }
1001 
1002 bool ABISysV_mips::RegisterIsVolatile(const RegisterInfo *reg_info) {
1003   return !RegisterIsCalleeSaved(reg_info);
1004 }
1005 
1006 bool ABISysV_mips::IsSoftFloat(uint32_t fp_flags) const {
1007   return (fp_flags == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);
1008 }
1009 
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;
1015 
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;
1033       }
1034 
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;
1043     }
1044   }
1045   return false;
1046 }
1047 
1048 void ABISysV_mips::Initialize() {
1049   PluginManager::RegisterPlugin(
1050       GetPluginNameStatic(), "System V ABI for mips targets", CreateInstance);
1051 }
1052 
1053 void ABISysV_mips::Terminate() {
1054   PluginManager::UnregisterPlugin(CreateInstance);
1055 }
1056