Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
39645 views
1
//===-- ABISysV_mips64.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_mips64.h"
10
11
#include "llvm/ADT/STLExtras.h"
12
#include "llvm/TargetParser/Triple.h"
13
14
#include "lldb/Core/Module.h"
15
#include "lldb/Core/PluginManager.h"
16
#include "lldb/Core/Value.h"
17
#include "lldb/Core/ValueObjectConstResult.h"
18
#include "lldb/Core/ValueObjectMemory.h"
19
#include "lldb/Core/ValueObjectRegister.h"
20
#include "lldb/Symbol/UnwindPlan.h"
21
#include "lldb/Target/Process.h"
22
#include "lldb/Target/RegisterContext.h"
23
#include "lldb/Target/StackFrame.h"
24
#include "lldb/Target/Target.h"
25
#include "lldb/Target/Thread.h"
26
#include "lldb/Utility/ConstString.h"
27
#include "lldb/Utility/DataExtractor.h"
28
#include "lldb/Utility/LLDBLog.h"
29
#include "lldb/Utility/Log.h"
30
#include "lldb/Utility/RegisterValue.h"
31
#include "lldb/Utility/Status.h"
32
#include <optional>
33
34
using namespace lldb;
35
using namespace lldb_private;
36
37
LLDB_PLUGIN_DEFINE(ABISysV_mips64)
38
39
enum dwarf_regnums {
40
dwarf_r0 = 0,
41
dwarf_r1,
42
dwarf_r2,
43
dwarf_r3,
44
dwarf_r4,
45
dwarf_r5,
46
dwarf_r6,
47
dwarf_r7,
48
dwarf_r8,
49
dwarf_r9,
50
dwarf_r10,
51
dwarf_r11,
52
dwarf_r12,
53
dwarf_r13,
54
dwarf_r14,
55
dwarf_r15,
56
dwarf_r16,
57
dwarf_r17,
58
dwarf_r18,
59
dwarf_r19,
60
dwarf_r20,
61
dwarf_r21,
62
dwarf_r22,
63
dwarf_r23,
64
dwarf_r24,
65
dwarf_r25,
66
dwarf_r26,
67
dwarf_r27,
68
dwarf_r28,
69
dwarf_r29,
70
dwarf_r30,
71
dwarf_r31,
72
dwarf_sr,
73
dwarf_lo,
74
dwarf_hi,
75
dwarf_bad,
76
dwarf_cause,
77
dwarf_pc
78
};
79
80
static const RegisterInfo g_register_infos_mips64[] = {
81
// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME
82
// DWARF GENERIC PROCESS PLUGIN
83
// LLDB NATIVE
84
// ======== ====== == === ============= ========== =============
85
// ================= ==================== =================
86
// ====================
87
{"r0",
88
"zero",
89
8,
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
8,
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
},
112
{"r2",
113
"v0",
114
8,
115
0,
116
eEncodingUint,
117
eFormatHex,
118
{dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
119
LLDB_INVALID_REGNUM},
120
nullptr,
121
nullptr,
122
nullptr,
123
},
124
{"r3",
125
"v1",
126
8,
127
0,
128
eEncodingUint,
129
eFormatHex,
130
{dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
131
LLDB_INVALID_REGNUM},
132
nullptr,
133
nullptr,
134
nullptr,
135
},
136
{"r4",
137
nullptr,
138
8,
139
0,
140
eEncodingUint,
141
eFormatHex,
142
{dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,
143
LLDB_INVALID_REGNUM},
144
nullptr,
145
nullptr,
146
nullptr,
147
},
148
{"r5",
149
nullptr,
150
8,
151
0,
152
eEncodingUint,
153
eFormatHex,
154
{dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,
155
LLDB_INVALID_REGNUM},
156
nullptr,
157
nullptr,
158
nullptr,
159
},
160
{"r6",
161
nullptr,
162
8,
163
0,
164
eEncodingUint,
165
eFormatHex,
166
{dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,
167
LLDB_INVALID_REGNUM},
168
nullptr,
169
nullptr,
170
nullptr,
171
},
172
{"r7",
173
nullptr,
174
8,
175
0,
176
eEncodingUint,
177
eFormatHex,
178
{dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,
179
LLDB_INVALID_REGNUM},
180
nullptr,
181
nullptr,
182
nullptr,
183
},
184
{"r8",
185
nullptr,
186
8,
187
0,
188
eEncodingUint,
189
eFormatHex,
190
{dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM,
191
LLDB_INVALID_REGNUM},
192
nullptr,
193
nullptr,
194
nullptr,
195
},
196
{"r9",
197
nullptr,
198
8,
199
0,
200
eEncodingUint,
201
eFormatHex,
202
{dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM,
203
LLDB_INVALID_REGNUM},
204
nullptr,
205
nullptr,
206
nullptr,
207
},
208
{"r10",
209
nullptr,
210
8,
211
0,
212
eEncodingUint,
213
eFormatHex,
214
{dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM,
215
LLDB_INVALID_REGNUM},
216
nullptr,
217
nullptr,
218
nullptr,
219
},
220
{"r11",
221
nullptr,
222
8,
223
0,
224
eEncodingUint,
225
eFormatHex,
226
{dwarf_r11, dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM,
227
LLDB_INVALID_REGNUM},
228
nullptr,
229
nullptr,
230
nullptr,
231
},
232
{"r12",
233
nullptr,
234
8,
235
0,
236
eEncodingUint,
237
eFormatHex,
238
{dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
239
LLDB_INVALID_REGNUM},
240
nullptr,
241
nullptr,
242
nullptr,
243
},
244
{"r13",
245
nullptr,
246
8,
247
0,
248
eEncodingUint,
249
eFormatHex,
250
{dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
251
LLDB_INVALID_REGNUM},
252
nullptr,
253
nullptr,
254
nullptr,
255
},
256
{"r14",
257
nullptr,
258
8,
259
0,
260
eEncodingUint,
261
eFormatHex,
262
{dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
263
LLDB_INVALID_REGNUM},
264
nullptr,
265
nullptr,
266
nullptr,
267
},
268
{"r15",
269
nullptr,
270
8,
271
0,
272
eEncodingUint,
273
eFormatHex,
274
{dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
275
LLDB_INVALID_REGNUM},
276
nullptr,
277
nullptr,
278
nullptr,
279
},
280
{"r16",
281
nullptr,
282
8,
283
0,
284
eEncodingUint,
285
eFormatHex,
286
{dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
287
LLDB_INVALID_REGNUM},
288
nullptr,
289
nullptr,
290
nullptr,
291
},
292
{"r17",
293
nullptr,
294
8,
295
0,
296
eEncodingUint,
297
eFormatHex,
298
{dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
299
LLDB_INVALID_REGNUM},
300
nullptr,
301
nullptr,
302
nullptr,
303
},
304
{"r18",
305
nullptr,
306
8,
307
0,
308
eEncodingUint,
309
eFormatHex,
310
{dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
311
LLDB_INVALID_REGNUM},
312
nullptr,
313
nullptr,
314
nullptr,
315
},
316
{"r19",
317
nullptr,
318
8,
319
0,
320
eEncodingUint,
321
eFormatHex,
322
{dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
323
LLDB_INVALID_REGNUM},
324
nullptr,
325
nullptr,
326
nullptr,
327
},
328
{"r20",
329
nullptr,
330
8,
331
0,
332
eEncodingUint,
333
eFormatHex,
334
{dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
335
LLDB_INVALID_REGNUM},
336
nullptr,
337
nullptr,
338
nullptr,
339
},
340
{"r21",
341
nullptr,
342
8,
343
0,
344
eEncodingUint,
345
eFormatHex,
346
{dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
347
LLDB_INVALID_REGNUM},
348
nullptr,
349
nullptr,
350
nullptr,
351
},
352
{"r22",
353
nullptr,
354
8,
355
0,
356
eEncodingUint,
357
eFormatHex,
358
{dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
359
LLDB_INVALID_REGNUM},
360
nullptr,
361
nullptr,
362
nullptr,
363
},
364
{"r23",
365
nullptr,
366
8,
367
0,
368
eEncodingUint,
369
eFormatHex,
370
{dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
371
LLDB_INVALID_REGNUM},
372
nullptr,
373
nullptr,
374
nullptr,
375
},
376
{"r24",
377
nullptr,
378
8,
379
0,
380
eEncodingUint,
381
eFormatHex,
382
{dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
383
LLDB_INVALID_REGNUM},
384
nullptr,
385
nullptr,
386
nullptr,
387
},
388
{"r25",
389
nullptr,
390
8,
391
0,
392
eEncodingUint,
393
eFormatHex,
394
{dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
395
LLDB_INVALID_REGNUM},
396
nullptr,
397
nullptr,
398
nullptr,
399
},
400
{"r26",
401
nullptr,
402
8,
403
0,
404
eEncodingUint,
405
eFormatHex,
406
{dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
407
LLDB_INVALID_REGNUM},
408
nullptr,
409
nullptr,
410
nullptr,
411
},
412
{"r27",
413
nullptr,
414
8,
415
0,
416
eEncodingUint,
417
eFormatHex,
418
{dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
419
LLDB_INVALID_REGNUM},
420
nullptr,
421
nullptr,
422
nullptr,
423
},
424
{"r28",
425
"gp",
426
8,
427
0,
428
eEncodingUint,
429
eFormatHex,
430
{dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
431
LLDB_INVALID_REGNUM},
432
nullptr,
433
nullptr,
434
nullptr,
435
},
436
{"r29",
437
nullptr,
438
8,
439
0,
440
eEncodingUint,
441
eFormatHex,
442
{dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
443
LLDB_INVALID_REGNUM},
444
nullptr,
445
nullptr,
446
nullptr,
447
},
448
{"r30",
449
nullptr,
450
8,
451
0,
452
eEncodingUint,
453
eFormatHex,
454
{dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
455
LLDB_INVALID_REGNUM},
456
nullptr,
457
nullptr,
458
nullptr,
459
},
460
{"r31",
461
nullptr,
462
8,
463
0,
464
eEncodingUint,
465
eFormatHex,
466
{dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
467
LLDB_INVALID_REGNUM},
468
nullptr,
469
nullptr,
470
nullptr,
471
},
472
{"sr",
473
nullptr,
474
4,
475
0,
476
eEncodingUint,
477
eFormatHex,
478
{dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,
479
LLDB_INVALID_REGNUM},
480
nullptr,
481
nullptr,
482
nullptr,
483
},
484
{"lo",
485
nullptr,
486
8,
487
0,
488
eEncodingUint,
489
eFormatHex,
490
{dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
491
LLDB_INVALID_REGNUM},
492
nullptr,
493
nullptr,
494
nullptr,
495
},
496
{"hi",
497
nullptr,
498
8,
499
0,
500
eEncodingUint,
501
eFormatHex,
502
{dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
503
LLDB_INVALID_REGNUM},
504
nullptr,
505
nullptr,
506
nullptr,
507
},
508
{"bad",
509
nullptr,
510
8,
511
0,
512
eEncodingUint,
513
eFormatHex,
514
{dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
515
LLDB_INVALID_REGNUM},
516
nullptr,
517
nullptr,
518
nullptr,
519
},
520
{"cause",
521
nullptr,
522
8,
523
0,
524
eEncodingUint,
525
eFormatHex,
526
{dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
527
LLDB_INVALID_REGNUM},
528
nullptr,
529
nullptr,
530
nullptr,
531
},
532
{"pc",
533
nullptr,
534
8,
535
0,
536
eEncodingUint,
537
eFormatHex,
538
{dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
539
LLDB_INVALID_REGNUM},
540
nullptr,
541
nullptr,
542
nullptr,
543
},
544
};
545
546
static const uint32_t k_num_register_infos = std::size(g_register_infos_mips64);
547
548
const lldb_private::RegisterInfo *
549
ABISysV_mips64::GetRegisterInfoArray(uint32_t &count) {
550
count = k_num_register_infos;
551
return g_register_infos_mips64;
552
}
553
554
size_t ABISysV_mips64::GetRedZoneSize() const { return 0; }
555
556
// Static Functions
557
558
ABISP
559
ABISysV_mips64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
560
if (arch.GetTriple().isMIPS64())
561
return ABISP(
562
new ABISysV_mips64(std::move(process_sp), MakeMCRegisterInfo(arch)));
563
return ABISP();
564
}
565
566
bool ABISysV_mips64::PrepareTrivialCall(Thread &thread, addr_t sp,
567
addr_t func_addr, addr_t return_addr,
568
llvm::ArrayRef<addr_t> args) const {
569
Log *log = GetLog(LLDBLog::Expressions);
570
571
if (log) {
572
StreamString s;
573
s.Printf("ABISysV_mips64::PrepareTrivialCall (tid = 0x%" PRIx64
574
", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
575
", return_addr = 0x%" PRIx64,
576
thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
577
(uint64_t)return_addr);
578
579
for (size_t i = 0; i < args.size(); ++i)
580
s.Printf(", arg%zd = 0x%" PRIx64, i + 1, args[i]);
581
s.PutCString(")");
582
log->PutString(s.GetString());
583
}
584
585
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
586
if (!reg_ctx)
587
return false;
588
589
const RegisterInfo *reg_info = nullptr;
590
591
if (args.size() > 8) // TODO handle more than 8 arguments
592
return false;
593
594
for (size_t i = 0; i < args.size(); ++i) {
595
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
596
LLDB_REGNUM_GENERIC_ARG1 + i);
597
LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") into %s", i + 1,
598
args[i], reg_info->name);
599
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
600
return false;
601
}
602
603
// First, align the SP
604
605
LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,
606
(uint64_t)sp, (uint64_t)(sp & ~0xfull));
607
608
sp &= ~(0xfull); // 16-byte alignment
609
610
Status error;
611
const RegisterInfo *pc_reg_info =
612
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
613
const RegisterInfo *sp_reg_info =
614
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
615
const RegisterInfo *ra_reg_info =
616
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
617
const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0);
618
const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0);
619
620
LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0);
621
622
/* Write r0 with 0, in case we are stopped in syscall,
623
* such setting prevents automatic decrement of the PC.
624
* This clears the bug 23659 for MIPS.
625
*/
626
if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0))
627
return false;
628
629
LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
630
631
// Set "sp" to the requested value
632
if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
633
return false;
634
635
LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
636
637
// Set "ra" to the return address
638
if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))
639
return false;
640
641
LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
642
643
// Set pc to the address of the called function.
644
if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
645
return false;
646
647
LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr);
648
649
// All callers of position independent functions must place the address of
650
// the called function in t9 (r25)
651
if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr))
652
return false;
653
654
return true;
655
}
656
657
bool ABISysV_mips64::GetArgumentValues(Thread &thread,
658
ValueList &values) const {
659
return false;
660
}
661
662
Status ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
663
lldb::ValueObjectSP &new_value_sp) {
664
Status error;
665
if (!new_value_sp) {
666
error.SetErrorString("Empty value object for return value.");
667
return error;
668
}
669
670
CompilerType compiler_type = new_value_sp->GetCompilerType();
671
if (!compiler_type) {
672
error.SetErrorString("Null clang type for return value.");
673
return error;
674
}
675
676
Thread *thread = frame_sp->GetThread().get();
677
678
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
679
680
if (!reg_ctx)
681
error.SetErrorString("no registers are available");
682
683
DataExtractor data;
684
Status data_error;
685
size_t num_bytes = new_value_sp->GetData(data, data_error);
686
if (data_error.Fail()) {
687
error.SetErrorStringWithFormat(
688
"Couldn't convert return value to raw data: %s",
689
data_error.AsCString());
690
return error;
691
}
692
693
const uint32_t type_flags = compiler_type.GetTypeInfo(nullptr);
694
695
if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {
696
if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {
697
lldb::offset_t offset = 0;
698
699
if (num_bytes <= 16) {
700
const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
701
if (num_bytes <= 8) {
702
uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
703
704
if (!reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value))
705
error.SetErrorString("failed to write register r2");
706
} else {
707
uint64_t raw_value = data.GetMaxU64(&offset, 8);
708
if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) {
709
const RegisterInfo *r3_info =
710
reg_ctx->GetRegisterInfoByName("r3", 0);
711
raw_value = data.GetMaxU64(&offset, num_bytes - offset);
712
713
if (!reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value))
714
error.SetErrorString("failed to write register r3");
715
} else
716
error.SetErrorString("failed to write register r2");
717
}
718
} else {
719
error.SetErrorString("We don't support returning longer than 128 bit "
720
"integer values at present.");
721
}
722
} else if (type_flags & eTypeIsFloat) {
723
error.SetErrorString("TODO: Handle Float Types.");
724
}
725
} else if (type_flags & eTypeIsVector) {
726
error.SetErrorString("returning vector values are not supported");
727
}
728
729
return error;
730
}
731
732
ValueObjectSP ABISysV_mips64::GetReturnValueObjectSimple(
733
Thread &thread, CompilerType &return_compiler_type) const {
734
ValueObjectSP return_valobj_sp;
735
return return_valobj_sp;
736
}
737
738
ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(
739
Thread &thread, CompilerType &return_compiler_type) const {
740
ValueObjectSP return_valobj_sp;
741
Value value;
742
Status error;
743
744
ExecutionContext exe_ctx(thread.shared_from_this());
745
if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
746
return return_valobj_sp;
747
748
value.SetCompilerType(return_compiler_type);
749
750
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
751
if (!reg_ctx)
752
return return_valobj_sp;
753
754
Target *target = exe_ctx.GetTargetPtr();
755
const ArchSpec target_arch = target->GetArchitecture();
756
ByteOrder target_byte_order = target_arch.GetByteOrder();
757
std::optional<uint64_t> byte_size = return_compiler_type.GetByteSize(&thread);
758
if (!byte_size)
759
return return_valobj_sp;
760
const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr);
761
uint32_t fp_flag =
762
target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask;
763
764
const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
765
const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);
766
assert(r2_info && r3_info && "Basic registers should always be present.");
767
768
if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {
769
value.SetValueType(Value::ValueType::Scalar);
770
771
bool success = false;
772
if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {
773
// Extract the register context so we can read arguments from registers
774
// In MIPS register "r2" (v0) holds the integer function return values
775
776
uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0);
777
778
const bool is_signed = (type_flags & eTypeIsSigned) != 0;
779
switch (*byte_size) {
780
default:
781
break;
782
783
case sizeof(uint64_t):
784
if (is_signed)
785
value.GetScalar() = (int64_t)(raw_value);
786
else
787
value.GetScalar() = (uint64_t)(raw_value);
788
success = true;
789
break;
790
791
case sizeof(uint32_t):
792
if (is_signed)
793
value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
794
else
795
value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
796
success = true;
797
break;
798
799
case sizeof(uint16_t):
800
if (is_signed)
801
value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
802
else
803
value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
804
success = true;
805
break;
806
807
case sizeof(uint8_t):
808
if (is_signed)
809
value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
810
else
811
value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
812
success = true;
813
break;
814
}
815
} else if (type_flags & eTypeIsFloat) {
816
if (type_flags & eTypeIsComplex) {
817
// Don't handle complex yet.
818
} else if (IsSoftFloat(fp_flag)) {
819
uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0);
820
switch (*byte_size) {
821
case 4:
822
value.GetScalar() = *((float *)(&raw_value));
823
success = true;
824
break;
825
case 8:
826
value.GetScalar() = *((double *)(&raw_value));
827
success = true;
828
break;
829
case 16:
830
uint64_t result[2];
831
if (target_byte_order == eByteOrderLittle) {
832
result[0] = raw_value;
833
result[1] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0);
834
value.GetScalar() = *((long double *)(result));
835
} else {
836
result[0] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0);
837
result[1] = raw_value;
838
value.GetScalar() = *((long double *)(result));
839
}
840
success = true;
841
break;
842
}
843
844
} else {
845
if (*byte_size <= sizeof(long double)) {
846
const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);
847
848
RegisterValue f0_value;
849
DataExtractor f0_data;
850
851
reg_ctx->ReadRegister(f0_info, f0_value);
852
853
f0_value.GetData(f0_data);
854
855
lldb::offset_t offset = 0;
856
if (*byte_size == sizeof(float)) {
857
value.GetScalar() = (float)f0_data.GetFloat(&offset);
858
success = true;
859
} else if (*byte_size == sizeof(double)) {
860
value.GetScalar() = (double)f0_data.GetDouble(&offset);
861
success = true;
862
} else if (*byte_size == sizeof(long double)) {
863
const RegisterInfo *f2_info =
864
reg_ctx->GetRegisterInfoByName("f2", 0);
865
RegisterValue f2_value;
866
DataExtractor f2_data;
867
reg_ctx->ReadRegister(f2_info, f2_value);
868
DataExtractor *copy_from_extractor = nullptr;
869
WritableDataBufferSP data_sp(new DataBufferHeap(16, 0));
870
DataExtractor return_ext(
871
data_sp, target_byte_order,
872
target->GetArchitecture().GetAddressByteSize());
873
874
if (target_byte_order == eByteOrderLittle) {
875
copy_from_extractor = &f0_data;
876
copy_from_extractor->CopyByteOrderedData(
877
0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order);
878
f2_value.GetData(f2_data);
879
copy_from_extractor = &f2_data;
880
copy_from_extractor->CopyByteOrderedData(
881
0, 8, data_sp->GetBytes() + 8, *byte_size - 8,
882
target_byte_order);
883
} else {
884
copy_from_extractor = &f0_data;
885
copy_from_extractor->CopyByteOrderedData(
886
0, 8, data_sp->GetBytes() + 8, *byte_size - 8,
887
target_byte_order);
888
f2_value.GetData(f2_data);
889
copy_from_extractor = &f2_data;
890
copy_from_extractor->CopyByteOrderedData(
891
0, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order);
892
}
893
894
return_valobj_sp = ValueObjectConstResult::Create(
895
&thread, return_compiler_type, ConstString(""), return_ext);
896
return return_valobj_sp;
897
}
898
}
899
}
900
}
901
902
if (success)
903
return_valobj_sp = ValueObjectConstResult::Create(
904
thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
905
} else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass ||
906
type_flags & eTypeIsVector) {
907
// Any structure of up to 16 bytes in size is returned in the registers.
908
if (*byte_size <= 16) {
909
WritableDataBufferSP data_sp(new DataBufferHeap(16, 0));
910
DataExtractor return_ext(data_sp, target_byte_order,
911
target->GetArchitecture().GetAddressByteSize());
912
913
RegisterValue r2_value, r3_value, f0_value, f1_value, f2_value;
914
// Tracks how much bytes of r2 and r3 registers we've consumed so far
915
uint32_t integer_bytes = 0;
916
917
// True if return values are in FP return registers.
918
bool use_fp_regs = false;
919
// True if we found any non floating point field in structure.
920
bool found_non_fp_field = false;
921
// True if return values are in r2 register.
922
bool use_r2 = false;
923
// True if return values are in r3 register.
924
bool use_r3 = false;
925
// True if the result is copied into our data buffer
926
bool sucess = false;
927
std::string name;
928
bool is_complex;
929
uint32_t count;
930
const uint32_t num_children = return_compiler_type.GetNumFields();
931
932
// A structure consisting of one or two FP values (and nothing else) will
933
// be returned in the two FP return-value registers i.e fp0 and fp2.
934
if (num_children <= 2) {
935
uint64_t field_bit_offset = 0;
936
937
// Check if this structure contains only floating point fields
938
for (uint32_t idx = 0; idx < num_children; idx++) {
939
CompilerType field_compiler_type =
940
return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset,
941
nullptr, nullptr);
942
943
if (field_compiler_type.IsFloatingPointType(count, is_complex))
944
use_fp_regs = true;
945
else
946
found_non_fp_field = true;
947
}
948
949
if (use_fp_regs && !found_non_fp_field) {
950
// We have one or two FP-only values in this structure. Get it from
951
// f0/f2 registers.
952
DataExtractor f0_data, f1_data, f2_data;
953
const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);
954
const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);
955
const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0);
956
957
reg_ctx->ReadRegister(f0_info, f0_value);
958
reg_ctx->ReadRegister(f2_info, f2_value);
959
960
f0_value.GetData(f0_data);
961
962
for (uint32_t idx = 0; idx < num_children; idx++) {
963
CompilerType field_compiler_type =
964
return_compiler_type.GetFieldAtIndex(
965
idx, name, &field_bit_offset, nullptr, nullptr);
966
std::optional<uint64_t> field_byte_width =
967
field_compiler_type.GetByteSize(&thread);
968
if (!field_byte_width)
969
return return_valobj_sp;
970
971
DataExtractor *copy_from_extractor = nullptr;
972
uint64_t return_value[2];
973
offset_t offset = 0;
974
975
if (idx == 0) {
976
// This case is for long double type.
977
if (*field_byte_width == 16) {
978
979
// If structure contains long double type, then it is returned
980
// in fp0/fp1 registers.
981
if (target_byte_order == eByteOrderLittle) {
982
return_value[0] = f0_data.GetU64(&offset);
983
reg_ctx->ReadRegister(f1_info, f1_value);
984
f1_value.GetData(f1_data);
985
offset = 0;
986
return_value[1] = f1_data.GetU64(&offset);
987
} else {
988
return_value[1] = f0_data.GetU64(&offset);
989
reg_ctx->ReadRegister(f1_info, f1_value);
990
f1_value.GetData(f1_data);
991
offset = 0;
992
return_value[0] = f1_data.GetU64(&offset);
993
}
994
995
f0_data.SetData(return_value, *field_byte_width,
996
target_byte_order);
997
}
998
copy_from_extractor = &f0_data; // This is in f0, copy from
999
// register to our result
1000
// structure
1001
} else {
1002
f2_value.GetData(f2_data);
1003
// This is in f2, copy from register to our result structure
1004
copy_from_extractor = &f2_data;
1005
}
1006
1007
// Sanity check to avoid crash
1008
if (!copy_from_extractor ||
1009
*field_byte_width > copy_from_extractor->GetByteSize())
1010
return return_valobj_sp;
1011
1012
// copy the register contents into our data buffer
1013
copy_from_extractor->CopyByteOrderedData(
1014
0, *field_byte_width,
1015
data_sp->GetBytes() + (field_bit_offset / 8), *field_byte_width,
1016
target_byte_order);
1017
}
1018
1019
// The result is in our data buffer. Create a variable object out of
1020
// it
1021
return_valobj_sp = ValueObjectConstResult::Create(
1022
&thread, return_compiler_type, ConstString(""), return_ext);
1023
1024
return return_valobj_sp;
1025
}
1026
}
1027
1028
// If we reach here, it means this structure either contains more than
1029
// two fields or it contains at least one non floating point type. In
1030
// that case, all fields are returned in GP return registers.
1031
for (uint32_t idx = 0; idx < num_children; idx++) {
1032
uint64_t field_bit_offset = 0;
1033
bool is_signed;
1034
uint32_t padding;
1035
1036
CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(
1037
idx, name, &field_bit_offset, nullptr, nullptr);
1038
std::optional<uint64_t> field_byte_width =
1039
field_compiler_type.GetByteSize(&thread);
1040
1041
// if we don't know the size of the field (e.g. invalid type), just
1042
// bail out
1043
if (!field_byte_width || *field_byte_width == 0)
1044
break;
1045
1046
uint32_t field_byte_offset = field_bit_offset / 8;
1047
1048
if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||
1049
field_compiler_type.IsPointerType() ||
1050
field_compiler_type.IsFloatingPointType(count, is_complex)) {
1051
padding = field_byte_offset - integer_bytes;
1052
1053
if (integer_bytes < 8) {
1054
// We have not yet consumed r2 completely.
1055
if (integer_bytes + *field_byte_width + padding <= 8) {
1056
// This field fits in r2, copy its value from r2 to our result
1057
// structure
1058
integer_bytes = integer_bytes + *field_byte_width +
1059
padding; // Increase the consumed bytes.
1060
use_r2 = true;
1061
} else {
1062
// There isn't enough space left in r2 for this field, so this
1063
// will be in r3.
1064
integer_bytes = integer_bytes + *field_byte_width +
1065
padding; // Increase the consumed bytes.
1066
use_r3 = true;
1067
}
1068
}
1069
// We already have consumed at-least 8 bytes that means r2 is done,
1070
// and this field will be in r3. Check if this field can fit in r3.
1071
else if (integer_bytes + *field_byte_width + padding <= 16) {
1072
integer_bytes = integer_bytes + *field_byte_width + padding;
1073
use_r3 = true;
1074
} else {
1075
// There isn't any space left for this field, this should not
1076
// happen as we have already checked the overall size is not
1077
// greater than 16 bytes. For now, return a nullptr return value
1078
// object.
1079
return return_valobj_sp;
1080
}
1081
}
1082
}
1083
// Vector types up to 16 bytes are returned in GP return registers
1084
if (type_flags & eTypeIsVector) {
1085
if (*byte_size <= 8)
1086
use_r2 = true;
1087
else {
1088
use_r2 = true;
1089
use_r3 = true;
1090
}
1091
}
1092
1093
if (use_r2) {
1094
reg_ctx->ReadRegister(r2_info, r2_value);
1095
1096
const size_t bytes_copied = r2_value.GetAsMemoryData(
1097
*r2_info, data_sp->GetBytes(), r2_info->byte_size,
1098
target_byte_order, error);
1099
if (bytes_copied != r2_info->byte_size)
1100
return return_valobj_sp;
1101
sucess = true;
1102
}
1103
if (use_r3) {
1104
reg_ctx->ReadRegister(r3_info, r3_value);
1105
const size_t bytes_copied = r3_value.GetAsMemoryData(
1106
*r3_info, data_sp->GetBytes() + r2_info->byte_size,
1107
r3_info->byte_size, target_byte_order, error);
1108
1109
if (bytes_copied != r3_info->byte_size)
1110
return return_valobj_sp;
1111
sucess = true;
1112
}
1113
if (sucess) {
1114
// The result is in our data buffer. Create a variable object out of
1115
// it
1116
return_valobj_sp = ValueObjectConstResult::Create(
1117
&thread, return_compiler_type, ConstString(""), return_ext);
1118
}
1119
return return_valobj_sp;
1120
}
1121
1122
// Any structure/vector greater than 16 bytes in size is returned in
1123
// memory. The pointer to that memory is returned in r2.
1124
uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(
1125
reg_ctx->GetRegisterInfoByName("r2", 0), 0);
1126
1127
// We have got the address. Create a memory object out of it
1128
return_valobj_sp = ValueObjectMemory::Create(
1129
&thread, "", Address(mem_address, nullptr), return_compiler_type);
1130
}
1131
return return_valobj_sp;
1132
}
1133
1134
bool ABISysV_mips64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
1135
unwind_plan.Clear();
1136
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
1137
1138
UnwindPlan::RowSP row(new UnwindPlan::Row);
1139
1140
// Our Call Frame Address is the stack pointer value
1141
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
1142
1143
// The previous PC is in the RA
1144
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
1145
unwind_plan.AppendRow(row);
1146
1147
// All other registers are the same.
1148
1149
unwind_plan.SetSourceName("mips64 at-func-entry default");
1150
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1151
unwind_plan.SetReturnAddressRegister(dwarf_r31);
1152
return true;
1153
}
1154
1155
bool ABISysV_mips64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
1156
unwind_plan.Clear();
1157
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
1158
1159
UnwindPlan::RowSP row(new UnwindPlan::Row);
1160
1161
row->SetUnspecifiedRegistersAreUndefined(true);
1162
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
1163
1164
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
1165
1166
unwind_plan.AppendRow(row);
1167
unwind_plan.SetSourceName("mips64 default unwind plan");
1168
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1169
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1170
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1171
return true;
1172
}
1173
1174
bool ABISysV_mips64::RegisterIsVolatile(const RegisterInfo *reg_info) {
1175
return !RegisterIsCalleeSaved(reg_info);
1176
}
1177
1178
bool ABISysV_mips64::IsSoftFloat(uint32_t fp_flag) const {
1179
return (fp_flag == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);
1180
}
1181
1182
bool ABISysV_mips64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
1183
if (reg_info) {
1184
// Preserved registers are :
1185
// r16-r23, r28, r29, r30, r31
1186
1187
int reg = ((reg_info->byte_offset) / 8);
1188
1189
bool save = (reg >= 16) && (reg <= 23);
1190
save |= (reg >= 28) && (reg <= 31);
1191
1192
return save;
1193
}
1194
return false;
1195
}
1196
1197
void ABISysV_mips64::Initialize() {
1198
PluginManager::RegisterPlugin(
1199
GetPluginNameStatic(), "System V ABI for mips64 targets", CreateInstance);
1200
}
1201
1202
void ABISysV_mips64::Terminate() {
1203
PluginManager::UnregisterPlugin(CreateInstance);
1204
}
1205
1206