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 {.name: "r0",
88 .alt_name: "zero",
89 .byte_size: 4,
90 .byte_offset: 0,
91 .encoding: eEncodingUint,
92 .format: eFormatHex,
93 .kinds: {dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
94 LLDB_INVALID_REGNUM},
95 .value_regs: nullptr,
96 .invalidate_regs: nullptr,
97 .flags_type: nullptr,
98 },
99 {.name: "r1",
100 .alt_name: "AT",
101 .byte_size: 4,
102 .byte_offset: 0,
103 .encoding: eEncodingUint,
104 .format: eFormatHex,
105 .kinds: {dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
106 LLDB_INVALID_REGNUM},
107 .value_regs: nullptr,
108 .invalidate_regs: nullptr,
109 .flags_type: nullptr,
110 },
111 {.name: "r2",
112 .alt_name: "v0",
113 .byte_size: 4,
114 .byte_offset: 0,
115 .encoding: eEncodingUint,
116 .format: eFormatHex,
117 .kinds: {dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
118 LLDB_INVALID_REGNUM},
119 .value_regs: nullptr,
120 .invalidate_regs: nullptr,
121 .flags_type: nullptr,
122 },
123 {.name: "r3",
124 .alt_name: "v1",
125 .byte_size: 4,
126 .byte_offset: 0,
127 .encoding: eEncodingUint,
128 .format: eFormatHex,
129 .kinds: {dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
130 LLDB_INVALID_REGNUM},
131 .value_regs: nullptr,
132 .invalidate_regs: nullptr,
133 .flags_type: nullptr,
134 },
135 {.name: "r4",
136 .alt_name: nullptr,
137 .byte_size: 4,
138 .byte_offset: 0,
139 .encoding: eEncodingUint,
140 .format: eFormatHex,
141 .kinds: {dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,
142 LLDB_INVALID_REGNUM},
143 .value_regs: nullptr,
144 .invalidate_regs: nullptr,
145 .flags_type: nullptr,
146 },
147 {.name: "r5",
148 .alt_name: nullptr,
149 .byte_size: 4,
150 .byte_offset: 0,
151 .encoding: eEncodingUint,
152 .format: eFormatHex,
153 .kinds: {dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,
154 LLDB_INVALID_REGNUM},
155 .value_regs: nullptr,
156 .invalidate_regs: nullptr,
157 .flags_type: nullptr,
158 },
159 {.name: "r6",
160 .alt_name: nullptr,
161 .byte_size: 4,
162 .byte_offset: 0,
163 .encoding: eEncodingUint,
164 .format: eFormatHex,
165 .kinds: {dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,
166 LLDB_INVALID_REGNUM},
167 .value_regs: nullptr,
168 .invalidate_regs: nullptr,
169 .flags_type: nullptr,
170 },
171 {.name: "r7",
172 .alt_name: nullptr,
173 .byte_size: 4,
174 .byte_offset: 0,
175 .encoding: eEncodingUint,
176 .format: eFormatHex,
177 .kinds: {dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,
178 LLDB_INVALID_REGNUM},
179 .value_regs: nullptr,
180 .invalidate_regs: nullptr,
181 .flags_type: nullptr,
182 },
183 {.name: "r8",
184 .alt_name: "arg5",
185 .byte_size: 4,
186 .byte_offset: 0,
187 .encoding: eEncodingUint,
188 .format: eFormatHex,
189 .kinds: {dwarf_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
190 LLDB_INVALID_REGNUM},
191 .value_regs: nullptr,
192 .invalidate_regs: nullptr,
193 .flags_type: nullptr,
194 },
195 {.name: "r9",
196 .alt_name: "arg6",
197 .byte_size: 4,
198 .byte_offset: 0,
199 .encoding: eEncodingUint,
200 .format: eFormatHex,
201 .kinds: {dwarf_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
202 LLDB_INVALID_REGNUM},
203 .value_regs: nullptr,
204 .invalidate_regs: nullptr,
205 .flags_type: nullptr,
206 },
207 {.name: "r10",
208 .alt_name: "arg7",
209 .byte_size: 4,
210 .byte_offset: 0,
211 .encoding: eEncodingUint,
212 .format: eFormatHex,
213 .kinds: {dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
214 LLDB_INVALID_REGNUM},
215 .value_regs: nullptr,
216 .invalidate_regs: nullptr,
217 .flags_type: nullptr,
218 },
219 {.name: "r11",
220 .alt_name: "arg8",
221 .byte_size: 4,
222 .byte_offset: 0,
223 .encoding: eEncodingUint,
224 .format: eFormatHex,
225 .kinds: {dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
226 LLDB_INVALID_REGNUM},
227 .value_regs: nullptr,
228 .invalidate_regs: nullptr,
229 .flags_type: nullptr,
230 },
231 {.name: "r12",
232 .alt_name: nullptr,
233 .byte_size: 4,
234 .byte_offset: 0,
235 .encoding: eEncodingUint,
236 .format: eFormatHex,
237 .kinds: {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
238 LLDB_INVALID_REGNUM},
239 .value_regs: nullptr,
240 .invalidate_regs: nullptr,
241 .flags_type: nullptr,
242 },
243 {.name: "r13",
244 .alt_name: nullptr,
245 .byte_size: 4,
246 .byte_offset: 0,
247 .encoding: eEncodingUint,
248 .format: eFormatHex,
249 .kinds: {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
250 LLDB_INVALID_REGNUM},
251 .value_regs: nullptr,
252 .invalidate_regs: nullptr,
253 .flags_type: nullptr,
254 },
255 {.name: "r14",
256 .alt_name: nullptr,
257 .byte_size: 4,
258 .byte_offset: 0,
259 .encoding: eEncodingUint,
260 .format: eFormatHex,
261 .kinds: {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
262 LLDB_INVALID_REGNUM},
263 .value_regs: nullptr,
264 .invalidate_regs: nullptr,
265 .flags_type: nullptr,
266 },
267 {.name: "r15",
268 .alt_name: nullptr,
269 .byte_size: 4,
270 .byte_offset: 0,
271 .encoding: eEncodingUint,
272 .format: eFormatHex,
273 .kinds: {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
274 LLDB_INVALID_REGNUM},
275 .value_regs: nullptr,
276 .invalidate_regs: nullptr,
277 .flags_type: nullptr,
278 },
279 {.name: "r16",
280 .alt_name: nullptr,
281 .byte_size: 4,
282 .byte_offset: 0,
283 .encoding: eEncodingUint,
284 .format: eFormatHex,
285 .kinds: {dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
286 LLDB_INVALID_REGNUM},
287 .value_regs: nullptr,
288 .invalidate_regs: nullptr,
289 .flags_type: nullptr,
290 },
291 {.name: "r17",
292 .alt_name: nullptr,
293 .byte_size: 4,
294 .byte_offset: 0,
295 .encoding: eEncodingUint,
296 .format: eFormatHex,
297 .kinds: {dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
298 LLDB_INVALID_REGNUM},
299 .value_regs: nullptr,
300 .invalidate_regs: nullptr,
301 .flags_type: nullptr,
302 },
303 {.name: "r18",
304 .alt_name: nullptr,
305 .byte_size: 4,
306 .byte_offset: 0,
307 .encoding: eEncodingUint,
308 .format: eFormatHex,
309 .kinds: {dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
310 LLDB_INVALID_REGNUM},
311 .value_regs: nullptr,
312 .invalidate_regs: nullptr,
313 .flags_type: nullptr,
314 },
315 {.name: "r19",
316 .alt_name: nullptr,
317 .byte_size: 4,
318 .byte_offset: 0,
319 .encoding: eEncodingUint,
320 .format: eFormatHex,
321 .kinds: {dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
322 LLDB_INVALID_REGNUM},
323 .value_regs: nullptr,
324 .invalidate_regs: nullptr,
325 .flags_type: nullptr,
326 },
327 {.name: "r20",
328 .alt_name: nullptr,
329 .byte_size: 4,
330 .byte_offset: 0,
331 .encoding: eEncodingUint,
332 .format: eFormatHex,
333 .kinds: {dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
334 LLDB_INVALID_REGNUM},
335 .value_regs: nullptr,
336 .invalidate_regs: nullptr,
337 .flags_type: nullptr,
338 },
339 {.name: "r21",
340 .alt_name: nullptr,
341 .byte_size: 4,
342 .byte_offset: 0,
343 .encoding: eEncodingUint,
344 .format: eFormatHex,
345 .kinds: {dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
346 LLDB_INVALID_REGNUM},
347 .value_regs: nullptr,
348 .invalidate_regs: nullptr,
349 .flags_type: nullptr,
350 },
351 {.name: "r22",
352 .alt_name: nullptr,
353 .byte_size: 4,
354 .byte_offset: 0,
355 .encoding: eEncodingUint,
356 .format: eFormatHex,
357 .kinds: {dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
358 LLDB_INVALID_REGNUM},
359 .value_regs: nullptr,
360 .invalidate_regs: nullptr,
361 .flags_type: nullptr,
362 },
363 {.name: "r23",
364 .alt_name: nullptr,
365 .byte_size: 4,
366 .byte_offset: 0,
367 .encoding: eEncodingUint,
368 .format: eFormatHex,
369 .kinds: {dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
370 LLDB_INVALID_REGNUM},
371 .value_regs: nullptr,
372 .invalidate_regs: nullptr,
373 .flags_type: nullptr,
374 },
375 {.name: "r24",
376 .alt_name: nullptr,
377 .byte_size: 4,
378 .byte_offset: 0,
379 .encoding: eEncodingUint,
380 .format: eFormatHex,
381 .kinds: {dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
382 LLDB_INVALID_REGNUM},
383 .value_regs: nullptr,
384 .invalidate_regs: nullptr,
385 .flags_type: nullptr,
386 },
387 {.name: "r25",
388 .alt_name: nullptr,
389 .byte_size: 4,
390 .byte_offset: 0,
391 .encoding: eEncodingUint,
392 .format: eFormatHex,
393 .kinds: {dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
394 LLDB_INVALID_REGNUM},
395 .value_regs: nullptr,
396 .invalidate_regs: nullptr,
397 .flags_type: nullptr,
398 },
399 {.name: "r26",
400 .alt_name: nullptr,
401 .byte_size: 4,
402 .byte_offset: 0,
403 .encoding: eEncodingUint,
404 .format: eFormatHex,
405 .kinds: {dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
406 LLDB_INVALID_REGNUM},
407 .value_regs: nullptr,
408 .invalidate_regs: nullptr,
409 .flags_type: nullptr,
410 },
411 {.name: "r27",
412 .alt_name: nullptr,
413 .byte_size: 4,
414 .byte_offset: 0,
415 .encoding: eEncodingUint,
416 .format: eFormatHex,
417 .kinds: {dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
418 LLDB_INVALID_REGNUM},
419 .value_regs: nullptr,
420 .invalidate_regs: nullptr,
421 .flags_type: nullptr,
422 },
423 {.name: "r28",
424 .alt_name: "gp",
425 .byte_size: 4,
426 .byte_offset: 0,
427 .encoding: eEncodingUint,
428 .format: eFormatHex,
429 .kinds: {dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
430 LLDB_INVALID_REGNUM},
431 .value_regs: nullptr,
432 .invalidate_regs: nullptr,
433 .flags_type: nullptr,
434 },
435 {.name: "r29",
436 .alt_name: nullptr,
437 .byte_size: 4,
438 .byte_offset: 0,
439 .encoding: eEncodingUint,
440 .format: eFormatHex,
441 .kinds: {dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
442 LLDB_INVALID_REGNUM},
443 .value_regs: nullptr,
444 .invalidate_regs: nullptr,
445 .flags_type: nullptr,
446 },
447 {.name: "r30",
448 .alt_name: nullptr,
449 .byte_size: 4,
450 .byte_offset: 0,
451 .encoding: eEncodingUint,
452 .format: eFormatHex,
453 .kinds: {dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
454 LLDB_INVALID_REGNUM},
455 .value_regs: nullptr,
456 .invalidate_regs: nullptr,
457 .flags_type: nullptr,
458 },
459 {.name: "r31",
460 .alt_name: nullptr,
461 .byte_size: 4,
462 .byte_offset: 0,
463 .encoding: eEncodingUint,
464 .format: eFormatHex,
465 .kinds: {dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
466 LLDB_INVALID_REGNUM},
467 .value_regs: nullptr,
468 .invalidate_regs: nullptr,
469 .flags_type: nullptr,
470 },
471 {.name: "sr",
472 .alt_name: nullptr,
473 .byte_size: 4,
474 .byte_offset: 0,
475 .encoding: eEncodingUint,
476 .format: eFormatHex,
477 .kinds: {dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,
478 LLDB_INVALID_REGNUM},
479 .value_regs: nullptr,
480 .invalidate_regs: nullptr,
481 .flags_type: nullptr,
482 },
483 {.name: "lo",
484 .alt_name: nullptr,
485 .byte_size: 4,
486 .byte_offset: 0,
487 .encoding: eEncodingUint,
488 .format: eFormatHex,
489 .kinds: {dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
490 LLDB_INVALID_REGNUM},
491 .value_regs: nullptr,
492 .invalidate_regs: nullptr,
493 .flags_type: nullptr,
494 },
495 {.name: "hi",
496 .alt_name: nullptr,
497 .byte_size: 4,
498 .byte_offset: 0,
499 .encoding: eEncodingUint,
500 .format: eFormatHex,
501 .kinds: {dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
502 LLDB_INVALID_REGNUM},
503 .value_regs: nullptr,
504 .invalidate_regs: nullptr,
505 .flags_type: nullptr,
506 },
507 {.name: "bad",
508 .alt_name: nullptr,
509 .byte_size: 4,
510 .byte_offset: 0,
511 .encoding: eEncodingUint,
512 .format: eFormatHex,
513 .kinds: {dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
514 LLDB_INVALID_REGNUM},
515 .value_regs: nullptr,
516 .invalidate_regs: nullptr,
517 .flags_type: nullptr,
518 },
519 {.name: "cause",
520 .alt_name: nullptr,
521 .byte_size: 4,
522 .byte_offset: 0,
523 .encoding: eEncodingUint,
524 .format: eFormatHex,
525 .kinds: {dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
526 LLDB_INVALID_REGNUM},
527 .value_regs: nullptr,
528 .invalidate_regs: nullptr,
529 .flags_type: nullptr,
530 },
531 {.name: "pc",
532 .alt_name: nullptr,
533 .byte_size: 4,
534 .byte_offset: 0,
535 .encoding: eEncodingUint,
536 .format: eFormatHex,
537 .kinds: {dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
538 LLDB_INVALID_REGNUM},
539 .value_regs: nullptr,
540 .invalidate_regs: nullptr,
541 .flags_type: 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(mask: LLDBLog::Expressions);
572
573 if (log) {
574 StreamString s;
575 s.Printf(format: "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(format: ", arg%zd = 0x%" PRIx64, i + 1, args[i]);
583 s.PutCString(cstr: ")");
584 log->PutString(str: 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(reg_kind: 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, uval: 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 reg_kind: 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(uint: *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, dst_addr: arg_pos,
641 dst_len: 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(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
652 const RegisterInfo *sp_reg_info =
653 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
654 const RegisterInfo *ra_reg_info =
655 reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
656 const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName(reg_name: "r25", start_idx: 0);
657 const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName(reg_name: "zero", start_idx: 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(reg_info: r0_info, uval: (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(reg_info: sp_reg_info, uval: 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(reg_info: ra_reg_info, uval: 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(reg_info: pc_reg_info, uval: 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(reg_info: r25_info, uval: 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, error&: 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(reg_name: "r2", start_idx: 0);
738 if (num_bytes <= 4) {
739 uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes);
740
741 if (reg_ctx->WriteRegisterFromUnsigned(reg_info: r2_info, uval: raw_value))
742 set_it_simple = true;
743 } else {
744 uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: 4);
745
746 if (reg_ctx->WriteRegisterFromUnsigned(reg_info: r2_info, uval: raw_value)) {
747 const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName(reg_name: "r3", start_idx: 0);
748 uint32_t raw_value = data.GetMaxU32(offset_ptr: &offset, byte_size: num_bytes - offset);
749
750 if (reg_ctx->WriteRegisterFromUnsigned(reg_info: r3_info, uval: 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(reg_name: "r2", start_idx: 0);
809 std::optional<uint64_t> bit_width = return_compiler_type.GetBitSize(exe_scope: &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(reg_name: "r3", start_idx: 0);
818 uint64_t raw_value;
819 raw_value = reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT32_MAX;
820 raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(reg_info: r3_reg_info, fail_value: 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(reg_info: r2_reg_info, fail_value: 0) & UINT32_MAX);
832 else
833 value.GetScalar() = (uint32_t)(
834 reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT32_MAX);
835 break;
836 case 16:
837 if (is_signed)
838 value.GetScalar() = (int16_t)(
839 reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT16_MAX);
840 else
841 value.GetScalar() = (uint16_t)(
842 reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT16_MAX);
843 break;
844 case 8:
845 if (is_signed)
846 value.GetScalar() = (int8_t)(
847 reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT8_MAX);
848 else
849 value.GetScalar() = (uint8_t)(
850 reg_ctx->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 0) & UINT8_MAX);
851 break;
852 }
853 } else if (return_compiler_type.IsPointerType()) {
854 uint32_t ptr =
855 thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_info: r2_reg_info, fail_value: 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_info: reg_ctx->GetRegisterInfoByName(reg_name: "r2", start_idx: 0), fail_value: 0);
863 // We have got the address. Create a memory object out of it
864 return_valobj_sp = ValueObjectMemory::Create(
865 exe_scope: &thread, name: "", address: Address(mem_address, nullptr), ast_type: 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(reg_info: r2_reg_info, fail_value: 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(reg_name: "r3", start_idx: 0);
883 if (target_byte_order == eByteOrderLittle)
884 raw_value =
885 ((reg_ctx->ReadRegisterAsUnsigned(reg_info: r3_reg_info, fail_value: 0)) << 32) |
886 raw_value;
887 else
888 raw_value = (raw_value << 32) |
889 reg_ctx->ReadRegisterAsUnsigned(reg_info: r3_reg_info, fail_value: 0);
890 value.GetScalar() = *((double *)(&raw_value));
891 break;
892 }
893 }
894
895 else {
896 const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName(reg_name: "f0", start_idx: 0);
897 RegisterValue f0_value;
898 DataExtractor f0_data;
899 reg_ctx->ReadRegister(reg_info: f0_info, reg_value&: f0_value);
900 f0_value.GetData(data&: 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(reg_name: "f1", start_idx: 0);
910 RegisterValue f1_value;
911 DataExtractor f1_data;
912 reg_ctx->ReadRegister(reg_info: f1_info, reg_value&: 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 src_offset: offset, src_len: 4, dst: data_sp->GetBytes(), dst_len: 4, dst_byte_order: target_byte_order);
923 f1_value.GetData(data&: f1_data);
924 copy_from_extractor = &f1_data;
925 copy_from_extractor->CopyByteOrderedData(
926 src_offset: offset, src_len: 4, dst: data_sp->GetBytes() + 4, dst_len: 4, dst_byte_order: target_byte_order);
927 } else {
928 copy_from_extractor = &f0_data;
929 copy_from_extractor->CopyByteOrderedData(
930 src_offset: offset, src_len: 4, dst: data_sp->GetBytes() + 4, dst_len: 4, dst_byte_order: target_byte_order);
931 f1_value.GetData(data&: f1_data);
932 copy_from_extractor = &f1_data;
933 copy_from_extractor->CopyByteOrderedData(
934 src_offset: offset, src_len: 4, dst: data_sp->GetBytes(), dst_len: 4, dst_byte_order: target_byte_order);
935 }
936 value.GetScalar() = (double)return_ext.GetDouble(offset_ptr: &offset);
937 break;
938 }
939 case 32: {
940 static_assert(sizeof(float) == sizeof(uint32_t));
941 value.GetScalar() = (float)f0_data.GetFloat(offset_ptr: &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 exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: 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(reg_num: dwarf_r29, offset: 0);
970
971 // The previous PC is in the RA
972 row->SetRegisterLocationToRegister(reg_num: dwarf_pc, other_reg_num: dwarf_r31, can_replace: true);
973 unwind_plan.AppendRow(row_sp: 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(reg_num: dwarf_r29, offset: 0);
991
992 row->SetRegisterLocationToRegister(reg_num: dwarf_pc, other_reg_num: dwarf_r31, can_replace: true);
993
994 unwind_plan.AppendRow(row_sp: 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 name: GetPluginNameStatic(), description: "System V ABI for mips targets", create_callback: CreateInstance);
1051}
1052
1053void ABISysV_mips::Terminate() {
1054 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
1055}
1056

source code of lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp