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