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
34using namespace lldb;
35using namespace lldb_private;
36
37LLDB_PLUGIN_DEFINE(ABISysV_mips)
38
39enum 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
80static 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
545static const uint32_t k_num_register_infos = std::size(g_register_infos);
546
547const lldb_private::RegisterInfo *
548ABISysV_mips::GetRegisterInfoArray(uint32_t &count) {
549  count = k_num_register_infos;
550  return g_register_infos;
551}
552
553size_t ABISysV_mips::GetRedZoneSize() const { return 0; }
554
555// Static Functions
556
557ABISP
558ABISysV_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
568bool 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
696bool ABISysV_mips::GetArgumentValues(Thread &thread, ValueList &values) const {
697  return false;
698}
699
700Status 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
774ValueObjectSP ABISysV_mips::GetReturnValueObjectSimple(
775    Thread &thread, CompilerType &return_compiler_type) const {
776  ValueObjectSP return_valobj_sp;
777  return return_valobj_sp;
778}
779
780ValueObjectSP 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
962bool 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
983bool 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
1002bool ABISysV_mips::RegisterIsVolatile(const RegisterInfo *reg_info) {
1003  return !RegisterIsCalleeSaved(reg_info);
1004}
1005
1006bool ABISysV_mips::IsSoftFloat(uint32_t fp_flags) const {
1007  return (fp_flags == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);
1008}
1009
1010bool 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
1048void ABISysV_mips::Initialize() {
1049  PluginManager::RegisterPlugin(
1050      GetPluginNameStatic(), "System V ABI for mips targets", CreateInstance);
1051}
1052
1053void ABISysV_mips::Terminate() {
1054  PluginManager::UnregisterPlugin(CreateInstance);
1055}
1056