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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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