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 | {.name: "r0" , |
88 | .alt_name: "zero" , |
89 | .byte_size: 8, |
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: 8, |
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 | }, |
112 | {.name: "r2" , |
113 | .alt_name: "v0" , |
114 | .byte_size: 8, |
115 | .byte_offset: 0, |
116 | .encoding: eEncodingUint, |
117 | .format: eFormatHex, |
118 | .kinds: {dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
119 | LLDB_INVALID_REGNUM}, |
120 | .value_regs: nullptr, |
121 | .invalidate_regs: nullptr, |
122 | .flags_type: nullptr, |
123 | }, |
124 | {.name: "r3" , |
125 | .alt_name: "v1" , |
126 | .byte_size: 8, |
127 | .byte_offset: 0, |
128 | .encoding: eEncodingUint, |
129 | .format: eFormatHex, |
130 | .kinds: {dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
131 | LLDB_INVALID_REGNUM}, |
132 | .value_regs: nullptr, |
133 | .invalidate_regs: nullptr, |
134 | .flags_type: nullptr, |
135 | }, |
136 | {.name: "r4" , |
137 | .alt_name: nullptr, |
138 | .byte_size: 8, |
139 | .byte_offset: 0, |
140 | .encoding: eEncodingUint, |
141 | .format: eFormatHex, |
142 | .kinds: {dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, |
143 | LLDB_INVALID_REGNUM}, |
144 | .value_regs: nullptr, |
145 | .invalidate_regs: nullptr, |
146 | .flags_type: nullptr, |
147 | }, |
148 | {.name: "r5" , |
149 | .alt_name: nullptr, |
150 | .byte_size: 8, |
151 | .byte_offset: 0, |
152 | .encoding: eEncodingUint, |
153 | .format: eFormatHex, |
154 | .kinds: {dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, |
155 | LLDB_INVALID_REGNUM}, |
156 | .value_regs: nullptr, |
157 | .invalidate_regs: nullptr, |
158 | .flags_type: nullptr, |
159 | }, |
160 | {.name: "r6" , |
161 | .alt_name: nullptr, |
162 | .byte_size: 8, |
163 | .byte_offset: 0, |
164 | .encoding: eEncodingUint, |
165 | .format: eFormatHex, |
166 | .kinds: {dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, |
167 | LLDB_INVALID_REGNUM}, |
168 | .value_regs: nullptr, |
169 | .invalidate_regs: nullptr, |
170 | .flags_type: nullptr, |
171 | }, |
172 | {.name: "r7" , |
173 | .alt_name: nullptr, |
174 | .byte_size: 8, |
175 | .byte_offset: 0, |
176 | .encoding: eEncodingUint, |
177 | .format: eFormatHex, |
178 | .kinds: {dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, |
179 | LLDB_INVALID_REGNUM}, |
180 | .value_regs: nullptr, |
181 | .invalidate_regs: nullptr, |
182 | .flags_type: nullptr, |
183 | }, |
184 | {.name: "r8" , |
185 | .alt_name: nullptr, |
186 | .byte_size: 8, |
187 | .byte_offset: 0, |
188 | .encoding: eEncodingUint, |
189 | .format: eFormatHex, |
190 | .kinds: {dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, |
191 | LLDB_INVALID_REGNUM}, |
192 | .value_regs: nullptr, |
193 | .invalidate_regs: nullptr, |
194 | .flags_type: nullptr, |
195 | }, |
196 | {.name: "r9" , |
197 | .alt_name: nullptr, |
198 | .byte_size: 8, |
199 | .byte_offset: 0, |
200 | .encoding: eEncodingUint, |
201 | .format: eFormatHex, |
202 | .kinds: {dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, |
203 | LLDB_INVALID_REGNUM}, |
204 | .value_regs: nullptr, |
205 | .invalidate_regs: nullptr, |
206 | .flags_type: nullptr, |
207 | }, |
208 | {.name: "r10" , |
209 | .alt_name: nullptr, |
210 | .byte_size: 8, |
211 | .byte_offset: 0, |
212 | .encoding: eEncodingUint, |
213 | .format: eFormatHex, |
214 | .kinds: {dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, |
215 | LLDB_INVALID_REGNUM}, |
216 | .value_regs: nullptr, |
217 | .invalidate_regs: nullptr, |
218 | .flags_type: nullptr, |
219 | }, |
220 | {.name: "r11" , |
221 | .alt_name: nullptr, |
222 | .byte_size: 8, |
223 | .byte_offset: 0, |
224 | .encoding: eEncodingUint, |
225 | .format: eFormatHex, |
226 | .kinds: {dwarf_r11, dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, |
227 | LLDB_INVALID_REGNUM}, |
228 | .value_regs: nullptr, |
229 | .invalidate_regs: nullptr, |
230 | .flags_type: nullptr, |
231 | }, |
232 | {.name: "r12" , |
233 | .alt_name: nullptr, |
234 | .byte_size: 8, |
235 | .byte_offset: 0, |
236 | .encoding: eEncodingUint, |
237 | .format: eFormatHex, |
238 | .kinds: {dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
239 | LLDB_INVALID_REGNUM}, |
240 | .value_regs: nullptr, |
241 | .invalidate_regs: nullptr, |
242 | .flags_type: nullptr, |
243 | }, |
244 | {.name: "r13" , |
245 | .alt_name: nullptr, |
246 | .byte_size: 8, |
247 | .byte_offset: 0, |
248 | .encoding: eEncodingUint, |
249 | .format: eFormatHex, |
250 | .kinds: {dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
251 | LLDB_INVALID_REGNUM}, |
252 | .value_regs: nullptr, |
253 | .invalidate_regs: nullptr, |
254 | .flags_type: nullptr, |
255 | }, |
256 | {.name: "r14" , |
257 | .alt_name: nullptr, |
258 | .byte_size: 8, |
259 | .byte_offset: 0, |
260 | .encoding: eEncodingUint, |
261 | .format: eFormatHex, |
262 | .kinds: {dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
263 | LLDB_INVALID_REGNUM}, |
264 | .value_regs: nullptr, |
265 | .invalidate_regs: nullptr, |
266 | .flags_type: nullptr, |
267 | }, |
268 | {.name: "r15" , |
269 | .alt_name: nullptr, |
270 | .byte_size: 8, |
271 | .byte_offset: 0, |
272 | .encoding: eEncodingUint, |
273 | .format: eFormatHex, |
274 | .kinds: {dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
275 | LLDB_INVALID_REGNUM}, |
276 | .value_regs: nullptr, |
277 | .invalidate_regs: nullptr, |
278 | .flags_type: nullptr, |
279 | }, |
280 | {.name: "r16" , |
281 | .alt_name: nullptr, |
282 | .byte_size: 8, |
283 | .byte_offset: 0, |
284 | .encoding: eEncodingUint, |
285 | .format: eFormatHex, |
286 | .kinds: {dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
287 | LLDB_INVALID_REGNUM}, |
288 | .value_regs: nullptr, |
289 | .invalidate_regs: nullptr, |
290 | .flags_type: nullptr, |
291 | }, |
292 | {.name: "r17" , |
293 | .alt_name: nullptr, |
294 | .byte_size: 8, |
295 | .byte_offset: 0, |
296 | .encoding: eEncodingUint, |
297 | .format: eFormatHex, |
298 | .kinds: {dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
299 | LLDB_INVALID_REGNUM}, |
300 | .value_regs: nullptr, |
301 | .invalidate_regs: nullptr, |
302 | .flags_type: nullptr, |
303 | }, |
304 | {.name: "r18" , |
305 | .alt_name: nullptr, |
306 | .byte_size: 8, |
307 | .byte_offset: 0, |
308 | .encoding: eEncodingUint, |
309 | .format: eFormatHex, |
310 | .kinds: {dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
311 | LLDB_INVALID_REGNUM}, |
312 | .value_regs: nullptr, |
313 | .invalidate_regs: nullptr, |
314 | .flags_type: nullptr, |
315 | }, |
316 | {.name: "r19" , |
317 | .alt_name: nullptr, |
318 | .byte_size: 8, |
319 | .byte_offset: 0, |
320 | .encoding: eEncodingUint, |
321 | .format: eFormatHex, |
322 | .kinds: {dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
323 | LLDB_INVALID_REGNUM}, |
324 | .value_regs: nullptr, |
325 | .invalidate_regs: nullptr, |
326 | .flags_type: nullptr, |
327 | }, |
328 | {.name: "r20" , |
329 | .alt_name: nullptr, |
330 | .byte_size: 8, |
331 | .byte_offset: 0, |
332 | .encoding: eEncodingUint, |
333 | .format: eFormatHex, |
334 | .kinds: {dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
335 | LLDB_INVALID_REGNUM}, |
336 | .value_regs: nullptr, |
337 | .invalidate_regs: nullptr, |
338 | .flags_type: nullptr, |
339 | }, |
340 | {.name: "r21" , |
341 | .alt_name: nullptr, |
342 | .byte_size: 8, |
343 | .byte_offset: 0, |
344 | .encoding: eEncodingUint, |
345 | .format: eFormatHex, |
346 | .kinds: {dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
347 | LLDB_INVALID_REGNUM}, |
348 | .value_regs: nullptr, |
349 | .invalidate_regs: nullptr, |
350 | .flags_type: nullptr, |
351 | }, |
352 | {.name: "r22" , |
353 | .alt_name: nullptr, |
354 | .byte_size: 8, |
355 | .byte_offset: 0, |
356 | .encoding: eEncodingUint, |
357 | .format: eFormatHex, |
358 | .kinds: {dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
359 | LLDB_INVALID_REGNUM}, |
360 | .value_regs: nullptr, |
361 | .invalidate_regs: nullptr, |
362 | .flags_type: nullptr, |
363 | }, |
364 | {.name: "r23" , |
365 | .alt_name: nullptr, |
366 | .byte_size: 8, |
367 | .byte_offset: 0, |
368 | .encoding: eEncodingUint, |
369 | .format: eFormatHex, |
370 | .kinds: {dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
371 | LLDB_INVALID_REGNUM}, |
372 | .value_regs: nullptr, |
373 | .invalidate_regs: nullptr, |
374 | .flags_type: nullptr, |
375 | }, |
376 | {.name: "r24" , |
377 | .alt_name: nullptr, |
378 | .byte_size: 8, |
379 | .byte_offset: 0, |
380 | .encoding: eEncodingUint, |
381 | .format: eFormatHex, |
382 | .kinds: {dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
383 | LLDB_INVALID_REGNUM}, |
384 | .value_regs: nullptr, |
385 | .invalidate_regs: nullptr, |
386 | .flags_type: nullptr, |
387 | }, |
388 | {.name: "r25" , |
389 | .alt_name: nullptr, |
390 | .byte_size: 8, |
391 | .byte_offset: 0, |
392 | .encoding: eEncodingUint, |
393 | .format: eFormatHex, |
394 | .kinds: {dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
395 | LLDB_INVALID_REGNUM}, |
396 | .value_regs: nullptr, |
397 | .invalidate_regs: nullptr, |
398 | .flags_type: nullptr, |
399 | }, |
400 | {.name: "r26" , |
401 | .alt_name: nullptr, |
402 | .byte_size: 8, |
403 | .byte_offset: 0, |
404 | .encoding: eEncodingUint, |
405 | .format: eFormatHex, |
406 | .kinds: {dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
407 | LLDB_INVALID_REGNUM}, |
408 | .value_regs: nullptr, |
409 | .invalidate_regs: nullptr, |
410 | .flags_type: nullptr, |
411 | }, |
412 | {.name: "r27" , |
413 | .alt_name: nullptr, |
414 | .byte_size: 8, |
415 | .byte_offset: 0, |
416 | .encoding: eEncodingUint, |
417 | .format: eFormatHex, |
418 | .kinds: {dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
419 | LLDB_INVALID_REGNUM}, |
420 | .value_regs: nullptr, |
421 | .invalidate_regs: nullptr, |
422 | .flags_type: nullptr, |
423 | }, |
424 | {.name: "r28" , |
425 | .alt_name: "gp" , |
426 | .byte_size: 8, |
427 | .byte_offset: 0, |
428 | .encoding: eEncodingUint, |
429 | .format: eFormatHex, |
430 | .kinds: {dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
431 | LLDB_INVALID_REGNUM}, |
432 | .value_regs: nullptr, |
433 | .invalidate_regs: nullptr, |
434 | .flags_type: nullptr, |
435 | }, |
436 | {.name: "r29" , |
437 | .alt_name: nullptr, |
438 | .byte_size: 8, |
439 | .byte_offset: 0, |
440 | .encoding: eEncodingUint, |
441 | .format: eFormatHex, |
442 | .kinds: {dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, |
443 | LLDB_INVALID_REGNUM}, |
444 | .value_regs: nullptr, |
445 | .invalidate_regs: nullptr, |
446 | .flags_type: nullptr, |
447 | }, |
448 | {.name: "r30" , |
449 | .alt_name: nullptr, |
450 | .byte_size: 8, |
451 | .byte_offset: 0, |
452 | .encoding: eEncodingUint, |
453 | .format: eFormatHex, |
454 | .kinds: {dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, |
455 | LLDB_INVALID_REGNUM}, |
456 | .value_regs: nullptr, |
457 | .invalidate_regs: nullptr, |
458 | .flags_type: nullptr, |
459 | }, |
460 | {.name: "r31" , |
461 | .alt_name: nullptr, |
462 | .byte_size: 8, |
463 | .byte_offset: 0, |
464 | .encoding: eEncodingUint, |
465 | .format: eFormatHex, |
466 | .kinds: {dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, |
467 | LLDB_INVALID_REGNUM}, |
468 | .value_regs: nullptr, |
469 | .invalidate_regs: nullptr, |
470 | .flags_type: nullptr, |
471 | }, |
472 | {.name: "sr" , |
473 | .alt_name: nullptr, |
474 | .byte_size: 4, |
475 | .byte_offset: 0, |
476 | .encoding: eEncodingUint, |
477 | .format: eFormatHex, |
478 | .kinds: {dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, |
479 | LLDB_INVALID_REGNUM}, |
480 | .value_regs: nullptr, |
481 | .invalidate_regs: nullptr, |
482 | .flags_type: nullptr, |
483 | }, |
484 | {.name: "lo" , |
485 | .alt_name: nullptr, |
486 | .byte_size: 8, |
487 | .byte_offset: 0, |
488 | .encoding: eEncodingUint, |
489 | .format: eFormatHex, |
490 | .kinds: {dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
491 | LLDB_INVALID_REGNUM}, |
492 | .value_regs: nullptr, |
493 | .invalidate_regs: nullptr, |
494 | .flags_type: nullptr, |
495 | }, |
496 | {.name: "hi" , |
497 | .alt_name: nullptr, |
498 | .byte_size: 8, |
499 | .byte_offset: 0, |
500 | .encoding: eEncodingUint, |
501 | .format: eFormatHex, |
502 | .kinds: {dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
503 | LLDB_INVALID_REGNUM}, |
504 | .value_regs: nullptr, |
505 | .invalidate_regs: nullptr, |
506 | .flags_type: nullptr, |
507 | }, |
508 | {.name: "bad" , |
509 | .alt_name: nullptr, |
510 | .byte_size: 8, |
511 | .byte_offset: 0, |
512 | .encoding: eEncodingUint, |
513 | .format: eFormatHex, |
514 | .kinds: {dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
515 | LLDB_INVALID_REGNUM}, |
516 | .value_regs: nullptr, |
517 | .invalidate_regs: nullptr, |
518 | .flags_type: nullptr, |
519 | }, |
520 | {.name: "cause" , |
521 | .alt_name: nullptr, |
522 | .byte_size: 8, |
523 | .byte_offset: 0, |
524 | .encoding: eEncodingUint, |
525 | .format: eFormatHex, |
526 | .kinds: {dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, |
527 | LLDB_INVALID_REGNUM}, |
528 | .value_regs: nullptr, |
529 | .invalidate_regs: nullptr, |
530 | .flags_type: nullptr, |
531 | }, |
532 | {.name: "pc" , |
533 | .alt_name: nullptr, |
534 | .byte_size: 8, |
535 | .byte_offset: 0, |
536 | .encoding: eEncodingUint, |
537 | .format: eFormatHex, |
538 | .kinds: {dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, |
539 | LLDB_INVALID_REGNUM}, |
540 | .value_regs: nullptr, |
541 | .invalidate_regs: nullptr, |
542 | .flags_type: 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(mask: LLDBLog::Expressions); |
570 | |
571 | if (log) { |
572 | StreamString s; |
573 | s.Printf(format: "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(format: ", arg%zd = 0x%" PRIx64, i + 1, args[i]); |
581 | s.PutCString(cstr: ")" ); |
582 | log->PutString(str: 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(reg_kind: 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, uval: 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(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); |
613 | const RegisterInfo *sp_reg_info = |
614 | reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); |
615 | const RegisterInfo *ra_reg_info = |
616 | reg_ctx->GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); |
617 | const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName(reg_name: "r25" , start_idx: 0); |
618 | const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName(reg_name: "zero" , start_idx: 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(reg_info: r0_info, uval: (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(reg_info: sp_reg_info, uval: 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(reg_info: ra_reg_info, uval: 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(reg_info: pc_reg_info, uval: 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(reg_info: r25_info, uval: 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, error&: 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(pointee_or_element_compiler_type: 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(reg_name: "r2" , start_idx: 0); |
701 | if (num_bytes <= 8) { |
702 | uint64_t raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes); |
703 | |
704 | if (!reg_ctx->WriteRegisterFromUnsigned(reg_info: r2_info, uval: raw_value)) |
705 | error.SetErrorString("failed to write register r2" ); |
706 | } else { |
707 | uint64_t raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: 8); |
708 | if (reg_ctx->WriteRegisterFromUnsigned(reg_info: r2_info, uval: raw_value)) { |
709 | const RegisterInfo *r3_info = |
710 | reg_ctx->GetRegisterInfoByName(reg_name: "r3" , start_idx: 0); |
711 | raw_value = data.GetMaxU64(offset_ptr: &offset, byte_size: num_bytes - offset); |
712 | |
713 | if (!reg_ctx->WriteRegisterFromUnsigned(reg_info: r3_info, uval: 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(exe_scope: &thread); |
758 | if (!byte_size) |
759 | return return_valobj_sp; |
760 | const uint32_t type_flags = return_compiler_type.GetTypeInfo(pointee_or_element_compiler_type: 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(reg_name: "r2" , start_idx: 0); |
765 | const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName(reg_name: "r3" , start_idx: 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(reg_info: r2_info, fail_value: 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(reg_info: r2_info, fail_value: 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(reg_info: r3_info, fail_value: 0); |
834 | value.GetScalar() = *((long double *)(result)); |
835 | } else { |
836 | result[0] = reg_ctx->ReadRegisterAsUnsigned(reg_info: r3_info, fail_value: 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(reg_name: "f0" , start_idx: 0); |
847 | |
848 | RegisterValue f0_value; |
849 | DataExtractor f0_data; |
850 | |
851 | reg_ctx->ReadRegister(reg_info: f0_info, reg_value&: f0_value); |
852 | |
853 | f0_value.GetData(data&: f0_data); |
854 | |
855 | lldb::offset_t offset = 0; |
856 | if (*byte_size == sizeof(float)) { |
857 | value.GetScalar() = (float)f0_data.GetFloat(offset_ptr: &offset); |
858 | success = true; |
859 | } else if (*byte_size == sizeof(double)) { |
860 | value.GetScalar() = (double)f0_data.GetDouble(offset_ptr: &offset); |
861 | success = true; |
862 | } else if (*byte_size == sizeof(long double)) { |
863 | const RegisterInfo *f2_info = |
864 | reg_ctx->GetRegisterInfoByName(reg_name: "f2" , start_idx: 0); |
865 | RegisterValue f2_value; |
866 | DataExtractor f2_data; |
867 | reg_ctx->ReadRegister(reg_info: f2_info, reg_value&: f2_value); |
868 | DataExtractor * = 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 | src_offset: 0, src_len: 8, dst: data_sp->GetBytes(), dst_len: *byte_size - 8, dst_byte_order: target_byte_order); |
878 | f2_value.GetData(data&: f2_data); |
879 | copy_from_extractor = &f2_data; |
880 | copy_from_extractor->CopyByteOrderedData( |
881 | src_offset: 0, src_len: 8, dst: data_sp->GetBytes() + 8, dst_len: *byte_size - 8, |
882 | dst_byte_order: target_byte_order); |
883 | } else { |
884 | copy_from_extractor = &f0_data; |
885 | copy_from_extractor->CopyByteOrderedData( |
886 | src_offset: 0, src_len: 8, dst: data_sp->GetBytes() + 8, dst_len: *byte_size - 8, |
887 | dst_byte_order: target_byte_order); |
888 | f2_value.GetData(data&: f2_data); |
889 | copy_from_extractor = &f2_data; |
890 | copy_from_extractor->CopyByteOrderedData( |
891 | src_offset: 0, src_len: 8, dst: data_sp->GetBytes(), dst_len: *byte_size - 8, dst_byte_order: target_byte_order); |
892 | } |
893 | |
894 | return_valobj_sp = ValueObjectConstResult::Create( |
895 | exe_scope: &thread, compiler_type: return_compiler_type, name: ConstString("" ), data: return_ext); |
896 | return return_valobj_sp; |
897 | } |
898 | } |
899 | } |
900 | } |
901 | |
902 | if (success) |
903 | return_valobj_sp = ValueObjectConstResult::Create( |
904 | exe_scope: thread.GetStackFrameAtIndex(idx: 0).get(), value, name: 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, bit_offset_ptr: &field_bit_offset, |
941 | bitfield_bit_size_ptr: nullptr, is_bitfield_ptr: 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(reg_name: "f0" , start_idx: 0); |
954 | const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName(reg_name: "f1" , start_idx: 0); |
955 | const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName(reg_name: "f2" , start_idx: 0); |
956 | |
957 | reg_ctx->ReadRegister(reg_info: f0_info, reg_value&: f0_value); |
958 | reg_ctx->ReadRegister(reg_info: f2_info, reg_value&: f2_value); |
959 | |
960 | f0_value.GetData(data&: 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, bit_offset_ptr: &field_bit_offset, bitfield_bit_size_ptr: nullptr, is_bitfield_ptr: nullptr); |
966 | std::optional<uint64_t> field_byte_width = |
967 | field_compiler_type.GetByteSize(exe_scope: &thread); |
968 | if (!field_byte_width) |
969 | return return_valobj_sp; |
970 | |
971 | DataExtractor * = 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_ptr: &offset); |
983 | reg_ctx->ReadRegister(reg_info: f1_info, reg_value&: f1_value); |
984 | f1_value.GetData(data&: f1_data); |
985 | offset = 0; |
986 | return_value[1] = f1_data.GetU64(offset_ptr: &offset); |
987 | } else { |
988 | return_value[1] = f0_data.GetU64(offset_ptr: &offset); |
989 | reg_ctx->ReadRegister(reg_info: f1_info, reg_value&: f1_value); |
990 | f1_value.GetData(data&: f1_data); |
991 | offset = 0; |
992 | return_value[0] = f1_data.GetU64(offset_ptr: &offset); |
993 | } |
994 | |
995 | f0_data.SetData(bytes: return_value, length: *field_byte_width, |
996 | byte_order: 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(data&: 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 | src_offset: 0, src_len: *field_byte_width, |
1015 | dst: data_sp->GetBytes() + (field_bit_offset / 8), dst_len: *field_byte_width, |
1016 | dst_byte_order: 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 | exe_scope: &thread, compiler_type: return_compiler_type, name: ConstString("" ), data: 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, bit_offset_ptr: &field_bit_offset, bitfield_bit_size_ptr: nullptr, is_bitfield_ptr: nullptr); |
1038 | std::optional<uint64_t> field_byte_width = |
1039 | field_compiler_type.GetByteSize(exe_scope: &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(reg_info: r2_info, reg_value&: r2_value); |
1095 | |
1096 | const size_t bytes_copied = r2_value.GetAsMemoryData( |
1097 | reg_info: *r2_info, dst: data_sp->GetBytes(), dst_len: r2_info->byte_size, |
1098 | dst_byte_order: 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(reg_info: r3_info, reg_value&: r3_value); |
1105 | const size_t bytes_copied = r3_value.GetAsMemoryData( |
1106 | reg_info: *r3_info, dst: data_sp->GetBytes() + r2_info->byte_size, |
1107 | dst_len: r3_info->byte_size, dst_byte_order: 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 | exe_scope: &thread, compiler_type: return_compiler_type, name: ConstString("" ), data: 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_info: reg_ctx->GetRegisterInfoByName(reg_name: "r2" , start_idx: 0), fail_value: 0); |
1126 | |
1127 | // We have got the address. Create a memory object out of it |
1128 | return_valobj_sp = ValueObjectMemory::Create( |
1129 | exe_scope: &thread, name: "" , address: Address(mem_address, nullptr), ast_type: 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(reg_num: dwarf_r29, offset: 0); |
1142 | |
1143 | // The previous PC is in the RA |
1144 | row->SetRegisterLocationToRegister(reg_num: dwarf_pc, other_reg_num: dwarf_r31, can_replace: true); |
1145 | unwind_plan.AppendRow(row_sp: 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(reg_num: dwarf_r29, offset: 0); |
1163 | |
1164 | row->SetRegisterLocationToRegister(reg_num: dwarf_pc, other_reg_num: dwarf_r31, can_replace: true); |
1165 | |
1166 | unwind_plan.AppendRow(row_sp: 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 | name: GetPluginNameStatic(), description: "System V ABI for mips64 targets" , create_callback: CreateInstance); |
1200 | } |
1201 | |
1202 | void ABISysV_mips64::Terminate() { |
1203 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
1204 | } |
1205 | |