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