1//===-- EmulateInstructionMIPS64.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 "EmulateInstructionMIPS64.h"
10
11#include <cstdlib>
12#include <optional>
13
14#include "lldb/Core/Address.h"
15#include "lldb/Core/Opcode.h"
16#include "lldb/Core/PluginManager.h"
17#include "lldb/Host/PosixApi.h"
18#include "lldb/Symbol/UnwindPlan.h"
19#include "lldb/Utility/ArchSpec.h"
20#include "lldb/Utility/ConstString.h"
21#include "lldb/Utility/DataExtractor.h"
22#include "lldb/Utility/RegisterValue.h"
23#include "lldb/Utility/Stream.h"
24#include "llvm-c/Disassembler.h"
25#include "llvm/MC/MCAsmInfo.h"
26#include "llvm/MC/MCContext.h"
27#include "llvm/MC/MCDisassembler/MCDisassembler.h"
28#include "llvm/MC/MCInst.h"
29#include "llvm/MC/MCInstrInfo.h"
30#include "llvm/MC/MCRegisterInfo.h"
31#include "llvm/MC/MCSubtargetInfo.h"
32#include "llvm/MC/MCTargetOptions.h"
33#include "llvm/MC/TargetRegistry.h"
34#include "llvm/Support/TargetSelect.h"
35
36#include "llvm/ADT/STLExtras.h"
37
38#include "Plugins/Process/Utility/InstructionUtils.h"
39#include "Plugins/Process/Utility/RegisterContext_mips.h"
40
41using namespace lldb;
42using namespace lldb_private;
43
44LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS64, InstructionMIPS64)
45
46#define UInt(x) ((uint64_t)x)
47#define integer int64_t
48
49//
50// EmulateInstructionMIPS64 implementation
51//
52
53#ifdef __mips__
54extern "C" {
55void LLVMInitializeMipsTargetInfo();
56void LLVMInitializeMipsTarget();
57void LLVMInitializeMipsAsmPrinter();
58void LLVMInitializeMipsTargetMC();
59void LLVMInitializeMipsDisassembler();
60}
61#endif
62
63EmulateInstructionMIPS64::EmulateInstructionMIPS64(
64 const lldb_private::ArchSpec &arch)
65 : EmulateInstruction(arch) {
66 /* Create instance of llvm::MCDisassembler */
67 std::string Status;
68 llvm::Triple triple = arch.GetTriple();
69 const llvm::Target *target =
70 llvm::TargetRegistry::lookupTarget(Triple: triple.getTriple(), Error&: Status);
71
72/*
73 * If we fail to get the target then we haven't registered it. The
74 * SystemInitializerCommon
75 * does not initialize targets, MCs and disassemblers. However we need the
76 * MCDisassembler
77 * to decode the instructions so that the decoding complexity stays with LLVM.
78 * Initialize the MIPS targets and disassemblers.
79*/
80#ifdef __mips__
81 if (!target) {
82 LLVMInitializeMipsTargetInfo();
83 LLVMInitializeMipsTarget();
84 LLVMInitializeMipsAsmPrinter();
85 LLVMInitializeMipsTargetMC();
86 LLVMInitializeMipsDisassembler();
87 target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
88 }
89#endif
90
91 assert(target);
92
93 llvm::StringRef cpu;
94
95 switch (arch.GetCore()) {
96 case ArchSpec::eCore_mips32:
97 case ArchSpec::eCore_mips32el:
98 cpu = "mips32";
99 break;
100 case ArchSpec::eCore_mips32r2:
101 case ArchSpec::eCore_mips32r2el:
102 cpu = "mips32r2";
103 break;
104 case ArchSpec::eCore_mips32r3:
105 case ArchSpec::eCore_mips32r3el:
106 cpu = "mips32r3";
107 break;
108 case ArchSpec::eCore_mips32r5:
109 case ArchSpec::eCore_mips32r5el:
110 cpu = "mips32r5";
111 break;
112 case ArchSpec::eCore_mips32r6:
113 case ArchSpec::eCore_mips32r6el:
114 cpu = "mips32r6";
115 break;
116 case ArchSpec::eCore_mips64:
117 case ArchSpec::eCore_mips64el:
118 cpu = "mips64";
119 break;
120 case ArchSpec::eCore_mips64r2:
121 case ArchSpec::eCore_mips64r2el:
122 cpu = "mips64r2";
123 break;
124 case ArchSpec::eCore_mips64r3:
125 case ArchSpec::eCore_mips64r3el:
126 cpu = "mips64r3";
127 break;
128 case ArchSpec::eCore_mips64r5:
129 case ArchSpec::eCore_mips64r5el:
130 cpu = "mips64r5";
131 break;
132 case ArchSpec::eCore_mips64r6:
133 case ArchSpec::eCore_mips64r6el:
134 cpu = "mips64r6";
135 break;
136 default:
137 cpu = "generic";
138 break;
139 }
140
141 std::string features;
142 uint32_t arch_flags = arch.GetFlags();
143 if (arch_flags & ArchSpec::eMIPSAse_msa)
144 features += "+msa,";
145 if (arch_flags & ArchSpec::eMIPSAse_dsp)
146 features += "+dsp,";
147 if (arch_flags & ArchSpec::eMIPSAse_dspr2)
148 features += "+dspr2,";
149 if (arch_flags & ArchSpec::eMIPSAse_mips16)
150 features += "+mips16,";
151 if (arch_flags & ArchSpec::eMIPSAse_micromips)
152 features += "+micromips,";
153
154 m_reg_info.reset(p: target->createMCRegInfo(TT: triple.getTriple()));
155 assert(m_reg_info.get());
156
157 m_insn_info.reset(p: target->createMCInstrInfo());
158 assert(m_insn_info.get());
159
160 llvm::MCTargetOptions MCOptions;
161 m_asm_info.reset(
162 p: target->createMCAsmInfo(MRI: *m_reg_info, TheTriple: triple.getTriple(), Options: MCOptions));
163 m_subtype_info.reset(
164 p: target->createMCSubtargetInfo(TheTriple: triple.getTriple(), CPU: cpu, Features: features));
165 assert(m_asm_info.get() && m_subtype_info.get());
166
167 m_context = std::make_unique<llvm::MCContext>(
168 args&: triple, args: m_asm_info.get(), args: m_reg_info.get(), args: m_subtype_info.get());
169 assert(m_context.get());
170
171 m_disasm.reset(p: target->createMCDisassembler(STI: *m_subtype_info, Ctx&: *m_context));
172 assert(m_disasm.get());
173}
174
175void EmulateInstructionMIPS64::Initialize() {
176 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
177 description: GetPluginDescriptionStatic(), create_callback: CreateInstance);
178}
179
180void EmulateInstructionMIPS64::Terminate() {
181 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
182}
183
184llvm::StringRef EmulateInstructionMIPS64::GetPluginDescriptionStatic() {
185 return "Emulate instructions for the MIPS64 architecture.";
186}
187
188EmulateInstruction *
189EmulateInstructionMIPS64::CreateInstance(const ArchSpec &arch,
190 InstructionType inst_type) {
191 if (EmulateInstructionMIPS64::SupportsEmulatingInstructionsOfTypeStatic(
192 inst_type)) {
193 if (arch.GetTriple().getArch() == llvm::Triple::mips64 ||
194 arch.GetTriple().getArch() == llvm::Triple::mips64el) {
195 return new EmulateInstructionMIPS64(arch);
196 }
197 }
198
199 return nullptr;
200}
201
202bool EmulateInstructionMIPS64::SetTargetTriple(const ArchSpec &arch) {
203 return arch.GetTriple().getArch() == llvm::Triple::mips64 ||
204 arch.GetTriple().getArch() == llvm::Triple::mips64el;
205}
206
207const char *EmulateInstructionMIPS64::GetRegisterName(unsigned reg_num,
208 bool alternate_name) {
209 if (alternate_name) {
210 switch (reg_num) {
211 case dwarf_sp_mips64:
212 return "r29";
213 case dwarf_r30_mips64:
214 return "r30";
215 case dwarf_ra_mips64:
216 return "r31";
217 case dwarf_f0_mips64:
218 return "f0";
219 case dwarf_f1_mips64:
220 return "f1";
221 case dwarf_f2_mips64:
222 return "f2";
223 case dwarf_f3_mips64:
224 return "f3";
225 case dwarf_f4_mips64:
226 return "f4";
227 case dwarf_f5_mips64:
228 return "f5";
229 case dwarf_f6_mips64:
230 return "f6";
231 case dwarf_f7_mips64:
232 return "f7";
233 case dwarf_f8_mips64:
234 return "f8";
235 case dwarf_f9_mips64:
236 return "f9";
237 case dwarf_f10_mips64:
238 return "f10";
239 case dwarf_f11_mips64:
240 return "f11";
241 case dwarf_f12_mips64:
242 return "f12";
243 case dwarf_f13_mips64:
244 return "f13";
245 case dwarf_f14_mips64:
246 return "f14";
247 case dwarf_f15_mips64:
248 return "f15";
249 case dwarf_f16_mips64:
250 return "f16";
251 case dwarf_f17_mips64:
252 return "f17";
253 case dwarf_f18_mips64:
254 return "f18";
255 case dwarf_f19_mips64:
256 return "f19";
257 case dwarf_f20_mips64:
258 return "f20";
259 case dwarf_f21_mips64:
260 return "f21";
261 case dwarf_f22_mips64:
262 return "f22";
263 case dwarf_f23_mips64:
264 return "f23";
265 case dwarf_f24_mips64:
266 return "f24";
267 case dwarf_f25_mips64:
268 return "f25";
269 case dwarf_f26_mips64:
270 return "f26";
271 case dwarf_f27_mips64:
272 return "f27";
273 case dwarf_f28_mips64:
274 return "f28";
275 case dwarf_f29_mips64:
276 return "f29";
277 case dwarf_f30_mips64:
278 return "f30";
279 case dwarf_f31_mips64:
280 return "f31";
281 case dwarf_w0_mips64:
282 return "w0";
283 case dwarf_w1_mips64:
284 return "w1";
285 case dwarf_w2_mips64:
286 return "w2";
287 case dwarf_w3_mips64:
288 return "w3";
289 case dwarf_w4_mips64:
290 return "w4";
291 case dwarf_w5_mips64:
292 return "w5";
293 case dwarf_w6_mips64:
294 return "w6";
295 case dwarf_w7_mips64:
296 return "w7";
297 case dwarf_w8_mips64:
298 return "w8";
299 case dwarf_w9_mips64:
300 return "w9";
301 case dwarf_w10_mips64:
302 return "w10";
303 case dwarf_w11_mips64:
304 return "w11";
305 case dwarf_w12_mips64:
306 return "w12";
307 case dwarf_w13_mips64:
308 return "w13";
309 case dwarf_w14_mips64:
310 return "w14";
311 case dwarf_w15_mips64:
312 return "w15";
313 case dwarf_w16_mips64:
314 return "w16";
315 case dwarf_w17_mips64:
316 return "w17";
317 case dwarf_w18_mips64:
318 return "w18";
319 case dwarf_w19_mips64:
320 return "w19";
321 case dwarf_w20_mips64:
322 return "w20";
323 case dwarf_w21_mips64:
324 return "w21";
325 case dwarf_w22_mips64:
326 return "w22";
327 case dwarf_w23_mips64:
328 return "w23";
329 case dwarf_w24_mips64:
330 return "w24";
331 case dwarf_w25_mips64:
332 return "w25";
333 case dwarf_w26_mips64:
334 return "w26";
335 case dwarf_w27_mips64:
336 return "w27";
337 case dwarf_w28_mips64:
338 return "w28";
339 case dwarf_w29_mips64:
340 return "w29";
341 case dwarf_w30_mips64:
342 return "w30";
343 case dwarf_w31_mips64:
344 return "w31";
345 case dwarf_mir_mips64:
346 return "mir";
347 case dwarf_mcsr_mips64:
348 return "mcsr";
349 case dwarf_config5_mips64:
350 return "config5";
351 default:
352 break;
353 }
354 return nullptr;
355 }
356
357 switch (reg_num) {
358 case dwarf_zero_mips64:
359 return "r0";
360 case dwarf_r1_mips64:
361 return "r1";
362 case dwarf_r2_mips64:
363 return "r2";
364 case dwarf_r3_mips64:
365 return "r3";
366 case dwarf_r4_mips64:
367 return "r4";
368 case dwarf_r5_mips64:
369 return "r5";
370 case dwarf_r6_mips64:
371 return "r6";
372 case dwarf_r7_mips64:
373 return "r7";
374 case dwarf_r8_mips64:
375 return "r8";
376 case dwarf_r9_mips64:
377 return "r9";
378 case dwarf_r10_mips64:
379 return "r10";
380 case dwarf_r11_mips64:
381 return "r11";
382 case dwarf_r12_mips64:
383 return "r12";
384 case dwarf_r13_mips64:
385 return "r13";
386 case dwarf_r14_mips64:
387 return "r14";
388 case dwarf_r15_mips64:
389 return "r15";
390 case dwarf_r16_mips64:
391 return "r16";
392 case dwarf_r17_mips64:
393 return "r17";
394 case dwarf_r18_mips64:
395 return "r18";
396 case dwarf_r19_mips64:
397 return "r19";
398 case dwarf_r20_mips64:
399 return "r20";
400 case dwarf_r21_mips64:
401 return "r21";
402 case dwarf_r22_mips64:
403 return "r22";
404 case dwarf_r23_mips64:
405 return "r23";
406 case dwarf_r24_mips64:
407 return "r24";
408 case dwarf_r25_mips64:
409 return "r25";
410 case dwarf_r26_mips64:
411 return "r26";
412 case dwarf_r27_mips64:
413 return "r27";
414 case dwarf_gp_mips64:
415 return "gp";
416 case dwarf_sp_mips64:
417 return "sp";
418 case dwarf_r30_mips64:
419 return "fp";
420 case dwarf_ra_mips64:
421 return "ra";
422 case dwarf_sr_mips64:
423 return "sr";
424 case dwarf_lo_mips64:
425 return "lo";
426 case dwarf_hi_mips64:
427 return "hi";
428 case dwarf_bad_mips64:
429 return "bad";
430 case dwarf_cause_mips64:
431 return "cause";
432 case dwarf_pc_mips64:
433 return "pc";
434 case dwarf_f0_mips64:
435 return "f0";
436 case dwarf_f1_mips64:
437 return "f1";
438 case dwarf_f2_mips64:
439 return "f2";
440 case dwarf_f3_mips64:
441 return "f3";
442 case dwarf_f4_mips64:
443 return "f4";
444 case dwarf_f5_mips64:
445 return "f5";
446 case dwarf_f6_mips64:
447 return "f6";
448 case dwarf_f7_mips64:
449 return "f7";
450 case dwarf_f8_mips64:
451 return "f8";
452 case dwarf_f9_mips64:
453 return "f9";
454 case dwarf_f10_mips64:
455 return "f10";
456 case dwarf_f11_mips64:
457 return "f11";
458 case dwarf_f12_mips64:
459 return "f12";
460 case dwarf_f13_mips64:
461 return "f13";
462 case dwarf_f14_mips64:
463 return "f14";
464 case dwarf_f15_mips64:
465 return "f15";
466 case dwarf_f16_mips64:
467 return "f16";
468 case dwarf_f17_mips64:
469 return "f17";
470 case dwarf_f18_mips64:
471 return "f18";
472 case dwarf_f19_mips64:
473 return "f19";
474 case dwarf_f20_mips64:
475 return "f20";
476 case dwarf_f21_mips64:
477 return "f21";
478 case dwarf_f22_mips64:
479 return "f22";
480 case dwarf_f23_mips64:
481 return "f23";
482 case dwarf_f24_mips64:
483 return "f24";
484 case dwarf_f25_mips64:
485 return "f25";
486 case dwarf_f26_mips64:
487 return "f26";
488 case dwarf_f27_mips64:
489 return "f27";
490 case dwarf_f28_mips64:
491 return "f28";
492 case dwarf_f29_mips64:
493 return "f29";
494 case dwarf_f30_mips64:
495 return "f30";
496 case dwarf_f31_mips64:
497 return "f31";
498 case dwarf_fcsr_mips64:
499 return "fcsr";
500 case dwarf_fir_mips64:
501 return "fir";
502 case dwarf_w0_mips64:
503 return "w0";
504 case dwarf_w1_mips64:
505 return "w1";
506 case dwarf_w2_mips64:
507 return "w2";
508 case dwarf_w3_mips64:
509 return "w3";
510 case dwarf_w4_mips64:
511 return "w4";
512 case dwarf_w5_mips64:
513 return "w5";
514 case dwarf_w6_mips64:
515 return "w6";
516 case dwarf_w7_mips64:
517 return "w7";
518 case dwarf_w8_mips64:
519 return "w8";
520 case dwarf_w9_mips64:
521 return "w9";
522 case dwarf_w10_mips64:
523 return "w10";
524 case dwarf_w11_mips64:
525 return "w11";
526 case dwarf_w12_mips64:
527 return "w12";
528 case dwarf_w13_mips64:
529 return "w13";
530 case dwarf_w14_mips64:
531 return "w14";
532 case dwarf_w15_mips64:
533 return "w15";
534 case dwarf_w16_mips64:
535 return "w16";
536 case dwarf_w17_mips64:
537 return "w17";
538 case dwarf_w18_mips64:
539 return "w18";
540 case dwarf_w19_mips64:
541 return "w19";
542 case dwarf_w20_mips64:
543 return "w20";
544 case dwarf_w21_mips64:
545 return "w21";
546 case dwarf_w22_mips64:
547 return "w22";
548 case dwarf_w23_mips64:
549 return "w23";
550 case dwarf_w24_mips64:
551 return "w24";
552 case dwarf_w25_mips64:
553 return "w25";
554 case dwarf_w26_mips64:
555 return "w26";
556 case dwarf_w27_mips64:
557 return "w27";
558 case dwarf_w28_mips64:
559 return "w28";
560 case dwarf_w29_mips64:
561 return "w29";
562 case dwarf_w30_mips64:
563 return "w30";
564 case dwarf_w31_mips64:
565 return "w31";
566 case dwarf_mcsr_mips64:
567 return "mcsr";
568 case dwarf_mir_mips64:
569 return "mir";
570 case dwarf_config5_mips64:
571 return "config5";
572 }
573 return nullptr;
574}
575
576std::optional<RegisterInfo>
577EmulateInstructionMIPS64::GetRegisterInfo(RegisterKind reg_kind,
578 uint32_t reg_num) {
579 if (reg_kind == eRegisterKindGeneric) {
580 switch (reg_num) {
581 case LLDB_REGNUM_GENERIC_PC:
582 reg_kind = eRegisterKindDWARF;
583 reg_num = dwarf_pc_mips64;
584 break;
585 case LLDB_REGNUM_GENERIC_SP:
586 reg_kind = eRegisterKindDWARF;
587 reg_num = dwarf_sp_mips64;
588 break;
589 case LLDB_REGNUM_GENERIC_FP:
590 reg_kind = eRegisterKindDWARF;
591 reg_num = dwarf_r30_mips64;
592 break;
593 case LLDB_REGNUM_GENERIC_RA:
594 reg_kind = eRegisterKindDWARF;
595 reg_num = dwarf_ra_mips64;
596 break;
597 case LLDB_REGNUM_GENERIC_FLAGS:
598 reg_kind = eRegisterKindDWARF;
599 reg_num = dwarf_sr_mips64;
600 break;
601 default:
602 return {};
603 }
604 }
605
606 if (reg_kind == eRegisterKindDWARF) {
607 RegisterInfo reg_info;
608 ::memset(s: &reg_info, c: 0, n: sizeof(RegisterInfo));
609 ::memset(s: reg_info.kinds, LLDB_INVALID_REGNUM, n: sizeof(reg_info.kinds));
610
611 if (reg_num == dwarf_sr_mips64 || reg_num == dwarf_fcsr_mips64 ||
612 reg_num == dwarf_fir_mips64 || reg_num == dwarf_mcsr_mips64 ||
613 reg_num == dwarf_mir_mips64 || reg_num == dwarf_config5_mips64) {
614 reg_info.byte_size = 4;
615 reg_info.format = eFormatHex;
616 reg_info.encoding = eEncodingUint;
617 } else if ((int)reg_num >= dwarf_zero_mips64 &&
618 (int)reg_num <= dwarf_f31_mips64) {
619 reg_info.byte_size = 8;
620 reg_info.format = eFormatHex;
621 reg_info.encoding = eEncodingUint;
622 } else if ((int)reg_num >= dwarf_w0_mips64 &&
623 (int)reg_num <= dwarf_w31_mips64) {
624 reg_info.byte_size = 16;
625 reg_info.format = eFormatVectorOfUInt8;
626 reg_info.encoding = eEncodingVector;
627 } else {
628 return {};
629 }
630
631 reg_info.name = GetRegisterName(reg_num, alternate_name: false);
632 reg_info.alt_name = GetRegisterName(reg_num, alternate_name: true);
633 reg_info.kinds[eRegisterKindDWARF] = reg_num;
634
635 switch (reg_num) {
636 case dwarf_r30_mips64:
637 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
638 break;
639 case dwarf_ra_mips64:
640 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
641 break;
642 case dwarf_sp_mips64:
643 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
644 break;
645 case dwarf_pc_mips64:
646 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
647 break;
648 case dwarf_sr_mips64:
649 reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
650 break;
651 default:
652 break;
653 }
654 return reg_info;
655 }
656 return {};
657}
658
659EmulateInstructionMIPS64::MipsOpcode *
660EmulateInstructionMIPS64::GetOpcodeForInstruction(llvm::StringRef op_name) {
661 static EmulateInstructionMIPS64::MipsOpcode g_opcodes[] = {
662 // Prologue/Epilogue instructions
663 {.op_name: "DADDiu", .callback: &EmulateInstructionMIPS64::Emulate_DADDiu,
664 .insn_name: "DADDIU rt, rs, immediate"},
665 {.op_name: "ADDiu", .callback: &EmulateInstructionMIPS64::Emulate_DADDiu,
666 .insn_name: "ADDIU rt, rs, immediate"},
667 {.op_name: "SD", .callback: &EmulateInstructionMIPS64::Emulate_SD, .insn_name: "SD rt, offset(rs)"},
668 {.op_name: "LD", .callback: &EmulateInstructionMIPS64::Emulate_LD, .insn_name: "LD rt, offset(base)"},
669 {.op_name: "DSUBU", .callback: &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU,
670 .insn_name: "DSUBU rd, rs, rt"},
671 {.op_name: "SUBU", .callback: &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU,
672 .insn_name: "SUBU rd, rs, rt"},
673 {.op_name: "DADDU", .callback: &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU,
674 .insn_name: "DADDU rd, rs, rt"},
675 {.op_name: "ADDU", .callback: &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU,
676 .insn_name: "ADDU rd, rs, rt"},
677 {.op_name: "LUI", .callback: &EmulateInstructionMIPS64::Emulate_LUI, .insn_name: "LUI rt, immediate"},
678
679 // Load/Store instructions
680 /* Following list of emulated instructions are required by implementation
681 of hardware watchpoint
682 for MIPS in lldb. As we just need the address accessed by instructions,
683 we have generalised
684 all these instructions in 2 functions depending on their addressing
685 modes */
686
687 {.op_name: "LB", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
688 .insn_name: "LB rt, offset(base)"},
689 {.op_name: "LBE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
690 .insn_name: "LBE rt, offset(base)"},
691 {.op_name: "LBU", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
692 .insn_name: "LBU rt, offset(base)"},
693 {.op_name: "LBUE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
694 .insn_name: "LBUE rt, offset(base)"},
695 {.op_name: "LDC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
696 .insn_name: "LDC1 ft, offset(base)"},
697 {.op_name: "LDL", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
698 .insn_name: "LDL rt, offset(base)"},
699 {.op_name: "LDR", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
700 .insn_name: "LDR rt, offset(base)"},
701 {.op_name: "LLD", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
702 .insn_name: "LLD rt, offset(base)"},
703 {.op_name: "LDC2", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
704 .insn_name: "LDC2 rt, offset(base)"},
705 {.op_name: "LDXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
706 .insn_name: "LDXC1 fd, index (base)"},
707 {.op_name: "LH", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
708 .insn_name: "LH rt, offset(base)"},
709 {.op_name: "LHE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
710 .insn_name: "LHE rt, offset(base)"},
711 {.op_name: "LHU", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
712 .insn_name: "LHU rt, offset(base)"},
713 {.op_name: "LHUE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
714 .insn_name: "LHUE rt, offset(base)"},
715 {.op_name: "LL", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
716 .insn_name: "LL rt, offset(base)"},
717 {.op_name: "LLE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
718 .insn_name: "LLE rt, offset(base)"},
719 {.op_name: "LUXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
720 .insn_name: "LUXC1 fd, index (base)"},
721 {.op_name: "LW", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
722 .insn_name: "LW rt, offset(rs)"},
723 {.op_name: "LWC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
724 .insn_name: "LWC1 ft, offset(base)"},
725 {.op_name: "LWC2", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
726 .insn_name: "LWC2 rt, offset(base)"},
727 {.op_name: "LWE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
728 .insn_name: "LWE rt, offset(base)"},
729 {.op_name: "LWL", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
730 .insn_name: "LWL rt, offset(base)"},
731 {.op_name: "LWLE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
732 .insn_name: "LWLE rt, offset(base)"},
733 {.op_name: "LWR", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
734 .insn_name: "LWR rt, offset(base)"},
735 {.op_name: "LWRE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
736 .insn_name: "LWRE rt, offset(base)"},
737 {.op_name: "LWXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
738 .insn_name: "LWXC1 fd, index (base)"},
739
740 {.op_name: "SB", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
741 .insn_name: "SB rt, offset(base)"},
742 {.op_name: "SBE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
743 .insn_name: "SBE rt, offset(base)"},
744 {.op_name: "SC", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
745 .insn_name: "SC rt, offset(base)"},
746 {.op_name: "SCE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
747 .insn_name: "SCE rt, offset(base)"},
748 {.op_name: "SCD", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
749 .insn_name: "SCD rt, offset(base)"},
750 {.op_name: "SDL", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
751 .insn_name: "SDL rt, offset(base)"},
752 {.op_name: "SDR", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
753 .insn_name: "SDR rt, offset(base)"},
754 {.op_name: "SDC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
755 .insn_name: "SDC1 ft, offset(base)"},
756 {.op_name: "SDC2", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
757 .insn_name: "SDC2 rt, offset(base)"},
758 {.op_name: "SDXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
759 .insn_name: "SDXC1 fs, index (base)"},
760 {.op_name: "SH", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
761 .insn_name: "SH rt, offset(base)"},
762 {.op_name: "SHE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
763 .insn_name: "SHE rt, offset(base)"},
764 {.op_name: "SUXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
765 .insn_name: "SUXC1 fs, index (base)"},
766 {.op_name: "SW", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
767 .insn_name: "SW rt, offset(rs)"},
768 {.op_name: "SWC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
769 .insn_name: "SWC1 ft, offset(base)"},
770 {.op_name: "SWC2", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
771 .insn_name: "SWC2 rt, offset(base)"},
772 {.op_name: "SWE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
773 .insn_name: "SWE rt, offset(base)"},
774 {.op_name: "SWL", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
775 .insn_name: "SWL rt, offset(base)"},
776 {.op_name: "SWLE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
777 .insn_name: "SWLE rt, offset(base)"},
778 {.op_name: "SWR", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
779 .insn_name: "SWR rt, offset(base)"},
780 {.op_name: "SWRE", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Imm,
781 .insn_name: "SWRE rt, offset(base)"},
782 {.op_name: "SWXC1", .callback: &EmulateInstructionMIPS64::Emulate_LDST_Reg,
783 .insn_name: "SWXC1 fs, index (base)"},
784
785 // Branch instructions
786 {.op_name: "BEQ", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops, .insn_name: "BEQ rs,rt,offset"},
787 {.op_name: "BEQ64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops, .insn_name: "BEQ rs,rt,offset"},
788 {.op_name: "BNE", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops, .insn_name: "BNE rs,rt,offset"},
789 {.op_name: "BNE64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops, .insn_name: "BNE rs,rt,offset"},
790 {.op_name: "BEQL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops,
791 .insn_name: "BEQL rs,rt,offset"},
792 {.op_name: "BNEL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops,
793 .insn_name: "BNEL rs,rt,offset"},
794 {.op_name: "BGEZALL", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link,
795 .insn_name: "BGEZALL rt,offset"},
796 {.op_name: "BAL", .callback: &EmulateInstructionMIPS64::Emulate_BAL, .insn_name: "BAL offset"},
797 {.op_name: "BGEZAL", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link,
798 .insn_name: "BGEZAL rs,offset"},
799 {.op_name: "BALC", .callback: &EmulateInstructionMIPS64::Emulate_BALC, .insn_name: "BALC offset"},
800 {.op_name: "BC", .callback: &EmulateInstructionMIPS64::Emulate_BC, .insn_name: "BC offset"},
801 {.op_name: "BGEZ", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGEZ rs,offset"},
802 {.op_name: "BGEZ64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGEZ rs,offset"},
803 {.op_name: "BLEZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
804 .insn_name: "BLEZALC rs,offset"},
805 {.op_name: "BGEZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
806 .insn_name: "BGEZALC rs,offset"},
807 {.op_name: "BLTZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
808 .insn_name: "BLTZALC rs,offset"},
809 {.op_name: "BGTZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
810 .insn_name: "BGTZALC rs,offset"},
811 {.op_name: "BEQZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
812 .insn_name: "BEQZALC rs,offset"},
813 {.op_name: "BNEZALC", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,
814 .insn_name: "BNEZALC rs,offset"},
815 {.op_name: "BEQC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
816 .insn_name: "BEQC rs,rt,offset"},
817 {.op_name: "BEQC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
818 .insn_name: "BEQC rs,rt,offset"},
819 {.op_name: "BNEC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
820 .insn_name: "BNEC rs,rt,offset"},
821 {.op_name: "BNEC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
822 .insn_name: "BNEC rs,rt,offset"},
823 {.op_name: "BLTC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
824 .insn_name: "BLTC rs,rt,offset"},
825 {.op_name: "BLTC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
826 .insn_name: "BLTC rs,rt,offset"},
827 {.op_name: "BGEC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
828 .insn_name: "BGEC rs,rt,offset"},
829 {.op_name: "BGEC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
830 .insn_name: "BGEC rs,rt,offset"},
831 {.op_name: "BLTUC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
832 .insn_name: "BLTUC rs,rt,offset"},
833 {.op_name: "BLTUC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
834 .insn_name: "BLTUC rs,rt,offset"},
835 {.op_name: "BGEUC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
836 .insn_name: "BGEUC rs,rt,offset"},
837 {.op_name: "BGEUC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
838 .insn_name: "BGEUC rs,rt,offset"},
839 {.op_name: "BLTZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
840 .insn_name: "BLTZC rt,offset"},
841 {.op_name: "BLTZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
842 .insn_name: "BLTZC rt,offset"},
843 {.op_name: "BLEZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
844 .insn_name: "BLEZC rt,offset"},
845 {.op_name: "BLEZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
846 .insn_name: "BLEZC rt,offset"},
847 {.op_name: "BGEZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
848 .insn_name: "BGEZC rt,offset"},
849 {.op_name: "BGEZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
850 .insn_name: "BGEZC rt,offset"},
851 {.op_name: "BGTZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
852 .insn_name: "BGTZC rt,offset"},
853 {.op_name: "BGTZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
854 .insn_name: "BGTZC rt,offset"},
855 {.op_name: "BEQZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
856 .insn_name: "BEQZC rt,offset"},
857 {.op_name: "BEQZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
858 .insn_name: "BEQZC rt,offset"},
859 {.op_name: "BNEZC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
860 .insn_name: "BNEZC rt,offset"},
861 {.op_name: "BNEZC64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops_C,
862 .insn_name: "BNEZC rt,offset"},
863 {.op_name: "BGEZL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGEZL rt,offset"},
864 {.op_name: "BGTZ", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGTZ rt,offset"},
865 {.op_name: "BGTZ64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGTZ rt,offset"},
866 {.op_name: "BGTZL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BGTZL rt,offset"},
867 {.op_name: "BLEZ", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLEZ rt,offset"},
868 {.op_name: "BLEZ64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLEZ rt,offset"},
869 {.op_name: "BLEZL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLEZL rt,offset"},
870 {.op_name: "BLTZ", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLTZ rt,offset"},
871 {.op_name: "BLTZ64", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLTZ rt,offset"},
872 {.op_name: "BLTZAL", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link,
873 .insn_name: "BLTZAL rt,offset"},
874 {.op_name: "BLTZALL", .callback: &EmulateInstructionMIPS64::Emulate_Bcond_Link,
875 .insn_name: "BLTZALL rt,offset"},
876 {.op_name: "BLTZL", .callback: &EmulateInstructionMIPS64::Emulate_BXX_2ops, .insn_name: "BLTZL rt,offset"},
877 {.op_name: "BOVC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
878 .insn_name: "BOVC rs,rt,offset"},
879 {.op_name: "BNVC", .callback: &EmulateInstructionMIPS64::Emulate_BXX_3ops_C,
880 .insn_name: "BNVC rs,rt,offset"},
881 {.op_name: "J", .callback: &EmulateInstructionMIPS64::Emulate_J, .insn_name: "J target"},
882 {.op_name: "JAL", .callback: &EmulateInstructionMIPS64::Emulate_JAL, .insn_name: "JAL target"},
883 {.op_name: "JALX", .callback: &EmulateInstructionMIPS64::Emulate_JAL, .insn_name: "JALX target"},
884 {.op_name: "JALR", .callback: &EmulateInstructionMIPS64::Emulate_JALR, .insn_name: "JALR target"},
885 {.op_name: "JALR64", .callback: &EmulateInstructionMIPS64::Emulate_JALR, .insn_name: "JALR target"},
886 {.op_name: "JALR_HB", .callback: &EmulateInstructionMIPS64::Emulate_JALR, .insn_name: "JALR.HB target"},
887 {.op_name: "JIALC", .callback: &EmulateInstructionMIPS64::Emulate_JIALC, .insn_name: "JIALC rt,offset"},
888 {.op_name: "JIALC64", .callback: &EmulateInstructionMIPS64::Emulate_JIALC, .insn_name: "JIALC rt,offset"},
889 {.op_name: "JIC", .callback: &EmulateInstructionMIPS64::Emulate_JIC, .insn_name: "JIC rt,offset"},
890 {.op_name: "JIC64", .callback: &EmulateInstructionMIPS64::Emulate_JIC, .insn_name: "JIC rt,offset"},
891 {.op_name: "JR", .callback: &EmulateInstructionMIPS64::Emulate_JR, .insn_name: "JR target"},
892 {.op_name: "JR64", .callback: &EmulateInstructionMIPS64::Emulate_JR, .insn_name: "JR target"},
893 {.op_name: "JR_HB", .callback: &EmulateInstructionMIPS64::Emulate_JR, .insn_name: "JR.HB target"},
894 {.op_name: "BC1F", .callback: &EmulateInstructionMIPS64::Emulate_FP_branch, .insn_name: "BC1F cc, offset"},
895 {.op_name: "BC1T", .callback: &EmulateInstructionMIPS64::Emulate_FP_branch, .insn_name: "BC1T cc, offset"},
896 {.op_name: "BC1FL", .callback: &EmulateInstructionMIPS64::Emulate_FP_branch,
897 .insn_name: "BC1FL cc, offset"},
898 {.op_name: "BC1TL", .callback: &EmulateInstructionMIPS64::Emulate_FP_branch,
899 .insn_name: "BC1TL cc, offset"},
900 {.op_name: "BC1EQZ", .callback: &EmulateInstructionMIPS64::Emulate_BC1EQZ,
901 .insn_name: "BC1EQZ ft, offset"},
902 {.op_name: "BC1NEZ", .callback: &EmulateInstructionMIPS64::Emulate_BC1NEZ,
903 .insn_name: "BC1NEZ ft, offset"},
904 {.op_name: "BC1ANY2F", .callback: &EmulateInstructionMIPS64::Emulate_3D_branch,
905 .insn_name: "BC1ANY2F cc, offset"},
906 {.op_name: "BC1ANY2T", .callback: &EmulateInstructionMIPS64::Emulate_3D_branch,
907 .insn_name: "BC1ANY2T cc, offset"},
908 {.op_name: "BC1ANY4F", .callback: &EmulateInstructionMIPS64::Emulate_3D_branch,
909 .insn_name: "BC1ANY4F cc, offset"},
910 {.op_name: "BC1ANY4T", .callback: &EmulateInstructionMIPS64::Emulate_3D_branch,
911 .insn_name: "BC1ANY4T cc, offset"},
912 {.op_name: "BNZ_B", .callback: &EmulateInstructionMIPS64::Emulate_BNZB, .insn_name: "BNZ.b wt,s16"},
913 {.op_name: "BNZ_H", .callback: &EmulateInstructionMIPS64::Emulate_BNZH, .insn_name: "BNZ.h wt,s16"},
914 {.op_name: "BNZ_W", .callback: &EmulateInstructionMIPS64::Emulate_BNZW, .insn_name: "BNZ.w wt,s16"},
915 {.op_name: "BNZ_D", .callback: &EmulateInstructionMIPS64::Emulate_BNZD, .insn_name: "BNZ.d wt,s16"},
916 {.op_name: "BZ_B", .callback: &EmulateInstructionMIPS64::Emulate_BZB, .insn_name: "BZ.b wt,s16"},
917 {.op_name: "BZ_H", .callback: &EmulateInstructionMIPS64::Emulate_BZH, .insn_name: "BZ.h wt,s16"},
918 {.op_name: "BZ_W", .callback: &EmulateInstructionMIPS64::Emulate_BZW, .insn_name: "BZ.w wt,s16"},
919 {.op_name: "BZ_D", .callback: &EmulateInstructionMIPS64::Emulate_BZD, .insn_name: "BZ.d wt,s16"},
920 {.op_name: "BNZ_V", .callback: &EmulateInstructionMIPS64::Emulate_BNZV, .insn_name: "BNZ.V wt,s16"},
921 {.op_name: "BZ_V", .callback: &EmulateInstructionMIPS64::Emulate_BZV, .insn_name: "BZ.V wt,s16"},
922 };
923
924 for (MipsOpcode &opcode : g_opcodes) {
925 if (op_name.equals_insensitive(RHS: opcode.op_name))
926 return &opcode;
927 }
928 return nullptr;
929}
930
931bool EmulateInstructionMIPS64::ReadInstruction() {
932 bool success = false;
933 m_addr = ReadRegisterUnsigned(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
934 LLDB_INVALID_ADDRESS, success_ptr: &success);
935 if (success) {
936 Context read_inst_context;
937 read_inst_context.type = eContextReadOpcode;
938 read_inst_context.SetNoArgs();
939 m_opcode.SetOpcode32(
940 inst: ReadMemoryUnsigned(context: read_inst_context, addr: m_addr, byte_size: 4, fail_value: 0, success_ptr: &success),
941 order: GetByteOrder());
942 }
943 if (!success)
944 m_addr = LLDB_INVALID_ADDRESS;
945 return success;
946}
947
948bool EmulateInstructionMIPS64::EvaluateInstruction(uint32_t evaluate_options) {
949 bool success = false;
950 llvm::MCInst mc_insn;
951 uint64_t insn_size;
952 DataExtractor data;
953
954 /* Keep the complexity of the decode logic with the llvm::MCDisassembler
955 * class. */
956 if (m_opcode.GetData(data)) {
957 llvm::MCDisassembler::DecodeStatus decode_status;
958 llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize());
959 decode_status = m_disasm->getInstruction(Instr&: mc_insn, Size&: insn_size, Bytes: raw_insn,
960 Address: m_addr, CStream&: llvm::nulls());
961 if (decode_status != llvm::MCDisassembler::Success)
962 return false;
963 }
964
965 /*
966 * mc_insn.getOpcode() returns decoded opcode. However to make use
967 * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc".
968 */
969 llvm::StringRef op_name = m_insn_info->getName(Opcode: mc_insn.getOpcode());
970
971 /*
972 * Decoding has been done already. Just get the call-back function
973 * and emulate the instruction.
974 */
975 MipsOpcode *opcode_data = GetOpcodeForInstruction(op_name);
976
977 if (opcode_data == nullptr)
978 return false;
979
980 uint64_t old_pc = 0, new_pc = 0;
981 const bool auto_advance_pc =
982 evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
983
984 if (auto_advance_pc) {
985 old_pc =
986 ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
987 if (!success)
988 return false;
989 }
990
991 /* emulate instruction */
992 success = (this->*opcode_data->callback)(mc_insn);
993 if (!success)
994 return false;
995
996 if (auto_advance_pc) {
997 new_pc =
998 ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
999 if (!success)
1000 return false;
1001
1002 /* If we haven't changed the PC, change it here */
1003 if (old_pc == new_pc) {
1004 new_pc += 4;
1005 Context context;
1006 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1007 reg_value: new_pc))
1008 return false;
1009 }
1010 }
1011
1012 return true;
1013}
1014
1015bool EmulateInstructionMIPS64::CreateFunctionEntryUnwind(
1016 UnwindPlan &unwind_plan) {
1017 unwind_plan.Clear();
1018 unwind_plan.SetRegisterKind(eRegisterKindDWARF);
1019
1020 UnwindPlan::RowSP row(new UnwindPlan::Row);
1021 const bool can_replace = false;
1022
1023 // Our previous Call Frame Address is the stack pointer
1024 row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: dwarf_sp_mips64, offset: 0);
1025
1026 // Our previous PC is in the RA
1027 row->SetRegisterLocationToRegister(reg_num: dwarf_pc_mips64, other_reg_num: dwarf_ra_mips64,
1028 can_replace);
1029
1030 unwind_plan.AppendRow(row_sp: row);
1031
1032 // All other registers are the same.
1033 unwind_plan.SetSourceName("EmulateInstructionMIPS64");
1034 unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1035 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
1036 unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1037 unwind_plan.SetReturnAddressRegister(dwarf_ra_mips64);
1038
1039 return true;
1040}
1041
1042bool EmulateInstructionMIPS64::nonvolatile_reg_p(uint64_t regnum) {
1043 switch (regnum) {
1044 case dwarf_r16_mips64:
1045 case dwarf_r17_mips64:
1046 case dwarf_r18_mips64:
1047 case dwarf_r19_mips64:
1048 case dwarf_r20_mips64:
1049 case dwarf_r21_mips64:
1050 case dwarf_r22_mips64:
1051 case dwarf_r23_mips64:
1052 case dwarf_gp_mips64:
1053 case dwarf_sp_mips64:
1054 case dwarf_r30_mips64:
1055 case dwarf_ra_mips64:
1056 return true;
1057 default:
1058 return false;
1059 }
1060 return false;
1061}
1062
1063bool EmulateInstructionMIPS64::Emulate_DADDiu(llvm::MCInst &insn) {
1064 // DADDIU rt, rs, immediate
1065 // GPR[rt] <- GPR[rs] + sign_extend(immediate)
1066
1067 uint8_t dst, src;
1068 bool success = false;
1069 const uint32_t imm16 = insn.getOperand(i: 2).getImm();
1070 int64_t imm = SignedBits(value: imm16, msbit: 15, lsbit: 0);
1071
1072 dst = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1073 src = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1074
1075 // If immediate is greater than 2^16 - 1 then clang generate LUI,
1076 // (D)ADDIU,(D)SUBU instructions in prolog. Example lui $1, 0x2 daddiu $1,
1077 // $1, -0x5920 dsubu $sp, $sp, $1 In this case, (D)ADDIU dst and src will be
1078 // same and not equal to sp
1079 if (dst == src) {
1080 Context context;
1081
1082 /* read <src> register */
1083 const uint64_t src_opd_val = ReadRegisterUnsigned(
1084 reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + src, fail_value: 0, success_ptr: &success);
1085 if (!success)
1086 return false;
1087
1088 /* Check if this is daddiu sp, sp, imm16 */
1089 if (dst == dwarf_sp_mips64) {
1090 /*
1091 * From the MIPS IV spec:
1092 *
1093 * The term “unsigned” in the instruction name is a misnomer; this
1094 * operation is 64-bit modulo arithmetic that does not trap on overflow.
1095 * It is appropriate for arithmetic which is not signed, such as address
1096 * arithmetic, or integer arithmetic environments that ignore overflow,
1097 * such as “C” language arithmetic.
1098 *
1099 * Assume 2's complement and rely on unsigned overflow here.
1100 */
1101 uint64_t result = src_opd_val + imm;
1102 std::optional<RegisterInfo> reg_info_sp =
1103 GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp_mips64);
1104 if (reg_info_sp)
1105 context.SetRegisterPlusOffset(base_reg: *reg_info_sp, signed_offset: imm);
1106
1107 /* We are allocating bytes on stack */
1108 context.type = eContextAdjustStackPointer;
1109
1110 WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp_mips64,
1111 reg_value: result);
1112 return true;
1113 }
1114
1115 imm += src_opd_val;
1116 context.SetImmediateSigned(imm);
1117 context.type = eContextImmediate;
1118
1119 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF,
1120 reg_num: dwarf_zero_mips64 + dst, reg_value: imm))
1121 return false;
1122 }
1123
1124 return true;
1125}
1126
1127bool EmulateInstructionMIPS64::Emulate_SD(llvm::MCInst &insn) {
1128 uint64_t address;
1129 bool success = false;
1130 uint32_t imm16 = insn.getOperand(i: 2).getImm();
1131 uint64_t imm = SignedBits(value: imm16, msbit: 15, lsbit: 0);
1132 uint32_t src, base;
1133 Context bad_vaddr_context;
1134
1135 src = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1136 base = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1137
1138 std::optional<RegisterInfo> reg_info_base =
1139 GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + base);
1140 std::optional<RegisterInfo> reg_info_src =
1141 GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + src);
1142 if (!reg_info_base || !reg_info_src)
1143 return false;
1144
1145 /* read SP */
1146 address = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + base,
1147 fail_value: 0, success_ptr: &success);
1148 if (!success)
1149 return false;
1150
1151 /* destination address */
1152 address = address + imm;
1153
1154 /* We look for sp based non-volatile register stores */
1155 if (nonvolatile_reg_p(regnum: src)) {
1156 Context context;
1157 context.type = eContextPushRegisterOnStack;
1158 context.SetRegisterToRegisterPlusOffset(data_reg: *reg_info_src, base_reg: *reg_info_base, offset: 0);
1159
1160 std::optional<RegisterValue> data_src = ReadRegister(reg_info: *reg_info_base);
1161 if (!data_src)
1162 return false;
1163
1164 Status error;
1165 RegisterValue::BytesContainer buffer(reg_info_src->byte_size);
1166 if (data_src->GetAsMemoryData(reg_info: *reg_info_src, dst: buffer.data(),
1167 dst_len: reg_info_src->byte_size, dst_byte_order: eByteOrderLittle,
1168 error) == 0)
1169 return false;
1170
1171 if (!WriteMemory(context, addr: address, src: buffer.data(), src_len: reg_info_src->byte_size))
1172 return false;
1173 }
1174
1175 /* Set the bad_vaddr register with base address used in the instruction */
1176 bad_vaddr_context.type = eContextInvalid;
1177 WriteRegisterUnsigned(context: bad_vaddr_context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_bad_mips64,
1178 reg_value: address);
1179
1180 return true;
1181}
1182
1183bool EmulateInstructionMIPS64::Emulate_LD(llvm::MCInst &insn) {
1184 bool success = false;
1185 uint32_t src, base;
1186 int64_t imm, address;
1187 Context bad_vaddr_context;
1188
1189 src = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1190 base = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1191 imm = insn.getOperand(i: 2).getImm();
1192
1193 if (!GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + base))
1194 return false;
1195
1196 /* read base register */
1197 address = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + base,
1198 fail_value: 0, success_ptr: &success);
1199 if (!success)
1200 return false;
1201
1202 /* destination address */
1203 address = address + imm;
1204
1205 /* Set the bad_vaddr register with base address used in the instruction */
1206 bad_vaddr_context.type = eContextInvalid;
1207 WriteRegisterUnsigned(context: bad_vaddr_context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_bad_mips64,
1208 reg_value: address);
1209
1210 if (nonvolatile_reg_p(regnum: src)) {
1211 RegisterValue data_src;
1212 std::optional<RegisterInfo> reg_info_src =
1213 GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + src);
1214 if (!reg_info_src)
1215 return false;
1216
1217 Context context;
1218 context.type = eContextRegisterLoad;
1219
1220 return WriteRegister(context, ref_info: *reg_info_src, reg_value: data_src);
1221 }
1222
1223 return false;
1224}
1225
1226bool EmulateInstructionMIPS64::Emulate_LUI(llvm::MCInst &insn) {
1227 // LUI rt, immediate
1228 // GPR[rt] <- sign_extend(immediate << 16)
1229
1230 const uint32_t imm32 = insn.getOperand(i: 1).getImm() << 16;
1231 int64_t imm = SignedBits(value: imm32, msbit: 31, lsbit: 0);
1232 uint8_t rt;
1233 Context context;
1234
1235 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1236 context.SetImmediateSigned(imm);
1237 context.type = eContextImmediate;
1238
1239 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF,
1240 reg_num: dwarf_zero_mips64 + rt, reg_value: imm);
1241}
1242
1243bool EmulateInstructionMIPS64::Emulate_DSUBU_DADDU(llvm::MCInst &insn) {
1244 // DSUBU sp, <src>, <rt>
1245 // DADDU sp, <src>, <rt>
1246 // DADDU dst, sp, <rt>
1247
1248 bool success = false;
1249 uint64_t result;
1250 uint8_t src, dst, rt;
1251 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1252
1253 dst = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1254 src = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1255
1256 /* Check if sp is destination register */
1257 if (dst == dwarf_sp_mips64) {
1258 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 2).getReg());
1259
1260 /* read <src> register */
1261 uint64_t src_opd_val = ReadRegisterUnsigned(
1262 reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + src, fail_value: 0, success_ptr: &success);
1263 if (!success)
1264 return false;
1265
1266 /* read <rt > register */
1267 uint64_t rt_opd_val = ReadRegisterUnsigned(
1268 reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1269 if (!success)
1270 return false;
1271
1272 if (op_name.equals_insensitive(RHS: "DSUBU") ||
1273 op_name.equals_insensitive(RHS: "SUBU"))
1274 result = src_opd_val - rt_opd_val;
1275 else
1276 result = src_opd_val + rt_opd_val;
1277
1278 Context context;
1279 std::optional<RegisterInfo> reg_info_sp =
1280 GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp_mips64);
1281 if (reg_info_sp)
1282 context.SetRegisterPlusOffset(base_reg: *reg_info_sp, signed_offset: rt_opd_val);
1283
1284 /* We are allocating bytes on stack */
1285 context.type = eContextAdjustStackPointer;
1286
1287 WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp_mips64, reg_value: result);
1288
1289 return true;
1290 } else if (src == dwarf_sp_mips64) {
1291 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 2).getReg());
1292
1293 /* read <src> register */
1294 uint64_t src_opd_val = ReadRegisterUnsigned(
1295 reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + src, fail_value: 0, success_ptr: &success);
1296 if (!success)
1297 return false;
1298
1299 /* read <rt> register */
1300 uint64_t rt_opd_val = ReadRegisterUnsigned(
1301 reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1302 if (!success)
1303 return false;
1304
1305 Context context;
1306
1307 if (op_name.equals_insensitive(RHS: "DSUBU") ||
1308 op_name.equals_insensitive(RHS: "SUBU"))
1309 result = src_opd_val - rt_opd_val;
1310 else
1311 result = src_opd_val + rt_opd_val;
1312
1313 context.SetImmediateSigned(result);
1314 context.type = eContextImmediate;
1315
1316 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF,
1317 reg_num: dwarf_zero_mips64 + dst, reg_value: result))
1318 return false;
1319 }
1320
1321 return true;
1322}
1323
1324/*
1325 Emulate below MIPS branch instructions.
1326 BEQ, BNE : Branch on condition
1327 BEQL, BNEL : Branch likely
1328*/
1329bool EmulateInstructionMIPS64::Emulate_BXX_3ops(llvm::MCInst &insn) {
1330 bool success = false;
1331 uint32_t rs, rt;
1332 int64_t offset, pc, rs_val, rt_val, target = 0;
1333 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1334
1335 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1336 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1337 offset = insn.getOperand(i: 2).getImm();
1338
1339 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1340 if (!success)
1341 return false;
1342
1343 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1344 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1345 if (!success)
1346 return false;
1347
1348 rt_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1349 reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1350 if (!success)
1351 return false;
1352
1353 if (op_name.equals_insensitive(RHS: "BEQ") || op_name.equals_insensitive(RHS: "BEQL") ||
1354 op_name.equals_insensitive(RHS: "BEQ64")) {
1355 if (rs_val == rt_val)
1356 target = pc + offset;
1357 else
1358 target = pc + 8;
1359 } else if (op_name.equals_insensitive(RHS: "BNE") ||
1360 op_name.equals_insensitive(RHS: "BNEL") ||
1361 op_name.equals_insensitive(RHS: "BNE64")) {
1362 if (rs_val != rt_val)
1363 target = pc + offset;
1364 else
1365 target = pc + 8;
1366 }
1367
1368 Context context;
1369 context.type = eContextRelativeBranchImmediate;
1370 context.SetImmediate(offset);
1371
1372 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1373 reg_value: target);
1374}
1375
1376/*
1377 Emulate below MIPS Non-Compact conditional branch and link instructions.
1378 BLTZAL, BGEZAL :
1379 BLTZALL, BGEZALL : Branch likely
1380*/
1381bool EmulateInstructionMIPS64::Emulate_Bcond_Link(llvm::MCInst &insn) {
1382 bool success = false;
1383 uint32_t rs;
1384 int64_t offset, pc, target = 0;
1385 int64_t rs_val;
1386 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1387
1388 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1389 offset = insn.getOperand(i: 1).getImm();
1390
1391 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1392 if (!success)
1393 return false;
1394
1395 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1396 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1397 if (!success)
1398 return false;
1399
1400 if (op_name.equals_insensitive(RHS: "BLTZAL") ||
1401 op_name.equals_insensitive(RHS: "BLTZALL")) {
1402 if (rs_val < 0)
1403 target = pc + offset;
1404 else
1405 target = pc + 8;
1406 } else if (op_name.equals_insensitive(RHS: "BGEZAL") ||
1407 op_name.equals_insensitive(RHS: "BGEZALL")) {
1408 if (rs_val >= 0)
1409 target = pc + offset;
1410 else
1411 target = pc + 8;
1412 }
1413
1414 Context context;
1415
1416 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1417 reg_value: target))
1418 return false;
1419
1420 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1421 reg_value: pc + 8))
1422 return false;
1423
1424 return true;
1425}
1426
1427bool EmulateInstructionMIPS64::Emulate_BAL(llvm::MCInst &insn) {
1428 bool success = false;
1429 int64_t offset, pc, target;
1430
1431 /*
1432 * BAL offset
1433 * offset = sign_ext (offset << 2)
1434 * RA = PC + 8
1435 * PC = PC + offset
1436 */
1437 offset = insn.getOperand(i: 0).getImm();
1438
1439 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1440 if (!success)
1441 return false;
1442
1443 target = pc + offset;
1444
1445 Context context;
1446
1447 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1448 reg_value: target))
1449 return false;
1450
1451 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1452 reg_value: pc + 8))
1453 return false;
1454
1455 return true;
1456}
1457
1458bool EmulateInstructionMIPS64::Emulate_BALC(llvm::MCInst &insn) {
1459 bool success = false;
1460 int64_t offset, pc, target;
1461
1462 /*
1463 * BALC offset
1464 * offset = sign_ext (offset << 2)
1465 * RA = PC + 4
1466 * PC = PC + 4 + offset
1467 */
1468 offset = insn.getOperand(i: 0).getImm();
1469
1470 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1471 if (!success)
1472 return false;
1473
1474 target = pc + offset;
1475
1476 Context context;
1477
1478 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1479 reg_value: target))
1480 return false;
1481
1482 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1483 reg_value: pc + 4))
1484 return false;
1485
1486 return true;
1487}
1488
1489/*
1490 Emulate below MIPS conditional branch and link instructions.
1491 BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches
1492*/
1493bool EmulateInstructionMIPS64::Emulate_Bcond_Link_C(llvm::MCInst &insn) {
1494 bool success = false;
1495 uint32_t rs;
1496 int64_t offset, pc, rs_val, target = 0;
1497 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1498
1499 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1500 offset = insn.getOperand(i: 1).getImm();
1501
1502 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1503 if (!success)
1504 return false;
1505
1506 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1507 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1508 if (!success)
1509 return false;
1510
1511 if (op_name.equals_insensitive(RHS: "BLEZALC")) {
1512 if (rs_val <= 0)
1513 target = pc + offset;
1514 else
1515 target = pc + 4;
1516 } else if (op_name.equals_insensitive(RHS: "BGEZALC")) {
1517 if (rs_val >= 0)
1518 target = pc + offset;
1519 else
1520 target = pc + 4;
1521 } else if (op_name.equals_insensitive(RHS: "BLTZALC")) {
1522 if (rs_val < 0)
1523 target = pc + offset;
1524 else
1525 target = pc + 4;
1526 } else if (op_name.equals_insensitive(RHS: "BGTZALC")) {
1527 if (rs_val > 0)
1528 target = pc + offset;
1529 else
1530 target = pc + 4;
1531 } else if (op_name.equals_insensitive(RHS: "BEQZALC")) {
1532 if (rs_val == 0)
1533 target = pc + offset;
1534 else
1535 target = pc + 4;
1536 } else if (op_name.equals_insensitive(RHS: "BNEZALC")) {
1537 if (rs_val != 0)
1538 target = pc + offset;
1539 else
1540 target = pc + 4;
1541 }
1542
1543 Context context;
1544
1545 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1546 reg_value: target))
1547 return false;
1548
1549 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1550 reg_value: pc + 4))
1551 return false;
1552
1553 return true;
1554}
1555
1556/*
1557 Emulate below MIPS branch instructions.
1558 BLTZL, BGEZL, BGTZL, BLEZL : Branch likely
1559 BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches
1560*/
1561bool EmulateInstructionMIPS64::Emulate_BXX_2ops(llvm::MCInst &insn) {
1562 bool success = false;
1563 uint32_t rs;
1564 int64_t offset, pc, rs_val, target = 0;
1565 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1566
1567 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1568 offset = insn.getOperand(i: 1).getImm();
1569
1570 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1571 if (!success)
1572 return false;
1573
1574 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1575 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1576 if (!success)
1577 return false;
1578
1579 if (op_name.equals_insensitive(RHS: "BLTZL") ||
1580 op_name.equals_insensitive(RHS: "BLTZ") ||
1581 op_name.equals_insensitive(RHS: "BLTZ64")) {
1582 if (rs_val < 0)
1583 target = pc + offset;
1584 else
1585 target = pc + 8;
1586 } else if (op_name.equals_insensitive(RHS: "BGEZL") ||
1587 op_name.equals_insensitive(RHS: "BGEZ") ||
1588 op_name.equals_insensitive(RHS: "BGEZ64")) {
1589 if (rs_val >= 0)
1590 target = pc + offset;
1591 else
1592 target = pc + 8;
1593 } else if (op_name.equals_insensitive(RHS: "BGTZL") ||
1594 op_name.equals_insensitive(RHS: "BGTZ") ||
1595 op_name.equals_insensitive(RHS: "BGTZ64")) {
1596 if (rs_val > 0)
1597 target = pc + offset;
1598 else
1599 target = pc + 8;
1600 } else if (op_name.equals_insensitive(RHS: "BLEZL") ||
1601 op_name.equals_insensitive(RHS: "BLEZ") ||
1602 op_name.equals_insensitive(RHS: "BLEZ64")) {
1603 if (rs_val <= 0)
1604 target = pc + offset;
1605 else
1606 target = pc + 8;
1607 }
1608
1609 Context context;
1610 context.type = eContextRelativeBranchImmediate;
1611 context.SetImmediate(offset);
1612
1613 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1614 reg_value: target);
1615}
1616
1617bool EmulateInstructionMIPS64::Emulate_BC(llvm::MCInst &insn) {
1618 bool success = false;
1619 int64_t offset, pc, target;
1620
1621 /*
1622 * BC offset
1623 * offset = sign_ext (offset << 2)
1624 * PC = PC + 4 + offset
1625 */
1626 offset = insn.getOperand(i: 0).getImm();
1627
1628 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1629 if (!success)
1630 return false;
1631
1632 target = pc + offset;
1633
1634 Context context;
1635
1636 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1637 reg_value: target);
1638}
1639
1640static int IsAdd64bitOverflow(int64_t a, int64_t b) {
1641 int64_t r = (uint64_t)a + (uint64_t)b;
1642 return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
1643}
1644
1645/*
1646 Emulate below MIPS branch instructions.
1647 BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch
1648 instructions with no delay slot
1649*/
1650bool EmulateInstructionMIPS64::Emulate_BXX_3ops_C(llvm::MCInst &insn) {
1651 bool success = false;
1652 uint32_t rs, rt;
1653 int64_t offset, pc, rs_val, rt_val, target = 0;
1654 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1655 uint32_t current_inst_size = m_insn_info->get(Opcode: insn.getOpcode()).getSize();
1656
1657 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1658 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1659 offset = insn.getOperand(i: 2).getImm();
1660
1661 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1662 if (!success)
1663 return false;
1664
1665 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1666 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1667 if (!success)
1668 return false;
1669
1670 rt_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1671 reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1672 if (!success)
1673 return false;
1674
1675 if (op_name.equals_insensitive(RHS: "BEQC") ||
1676 op_name.equals_insensitive(RHS: "BEQC64")) {
1677 if (rs_val == rt_val)
1678 target = pc + offset;
1679 else
1680 target = pc + 4;
1681 } else if (op_name.equals_insensitive(RHS: "BNEC") ||
1682 op_name.equals_insensitive(RHS: "BNEC64")) {
1683 if (rs_val != rt_val)
1684 target = pc + offset;
1685 else
1686 target = pc + 4;
1687 } else if (op_name.equals_insensitive(RHS: "BLTC") ||
1688 op_name.equals_insensitive(RHS: "BLTC64")) {
1689 if (rs_val < rt_val)
1690 target = pc + offset;
1691 else
1692 target = pc + 4;
1693 } else if (op_name.equals_insensitive(RHS: "BGEC64") ||
1694 op_name.equals_insensitive(RHS: "BGEC")) {
1695 if (rs_val >= rt_val)
1696 target = pc + offset;
1697 else
1698 target = pc + 4;
1699 } else if (op_name.equals_insensitive(RHS: "BLTUC") ||
1700 op_name.equals_insensitive(RHS: "BLTUC64")) {
1701 if (rs_val < rt_val)
1702 target = pc + offset;
1703 else
1704 target = pc + 4;
1705 } else if (op_name.equals_insensitive(RHS: "BGEUC") ||
1706 op_name.equals_insensitive(RHS: "BGEUC64")) {
1707 if ((uint32_t)rs_val >= (uint32_t)rt_val)
1708 target = pc + offset;
1709 else
1710 target = pc + 4;
1711 } else if (op_name.equals_insensitive(RHS: "BOVC")) {
1712 if (IsAdd64bitOverflow(a: rs_val, b: rt_val))
1713 target = pc + offset;
1714 else
1715 target = pc + 4;
1716 } else if (op_name.equals_insensitive(RHS: "BNVC")) {
1717 if (!IsAdd64bitOverflow(a: rs_val, b: rt_val))
1718 target = pc + offset;
1719 else
1720 target = pc + 4;
1721 }
1722
1723 Context context;
1724 context.type = eContextRelativeBranchImmediate;
1725 context.SetImmediate(current_inst_size + offset);
1726
1727 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1728 reg_value: target);
1729}
1730
1731/*
1732 Emulate below MIPS branch instructions.
1733 BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches
1734*/
1735bool EmulateInstructionMIPS64::Emulate_BXX_2ops_C(llvm::MCInst &insn) {
1736 bool success = false;
1737 uint32_t rs;
1738 int64_t offset, pc, target = 0;
1739 int64_t rs_val;
1740 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1741 uint32_t current_inst_size = m_insn_info->get(Opcode: insn.getOpcode()).getSize();
1742
1743 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1744 offset = insn.getOperand(i: 1).getImm();
1745
1746 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1747 if (!success)
1748 return false;
1749
1750 rs_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1751 reg_num: dwarf_zero_mips64 + rs, fail_value: 0, success_ptr: &success);
1752 if (!success)
1753 return false;
1754
1755 if (op_name.equals_insensitive(RHS: "BLTZC") ||
1756 op_name.equals_insensitive(RHS: "BLTZC64")) {
1757 if (rs_val < 0)
1758 target = pc + offset;
1759 else
1760 target = pc + 4;
1761 } else if (op_name.equals_insensitive(RHS: "BLEZC") ||
1762 op_name.equals_insensitive(RHS: "BLEZC64")) {
1763 if (rs_val <= 0)
1764 target = pc + offset;
1765 else
1766 target = pc + 4;
1767 } else if (op_name.equals_insensitive(RHS: "BGEZC") ||
1768 op_name.equals_insensitive(RHS: "BGEZC64")) {
1769 if (rs_val >= 0)
1770 target = pc + offset;
1771 else
1772 target = pc + 4;
1773 } else if (op_name.equals_insensitive(RHS: "BGTZC") ||
1774 op_name.equals_insensitive(RHS: "BGTZC64")) {
1775 if (rs_val > 0)
1776 target = pc + offset;
1777 else
1778 target = pc + 4;
1779 } else if (op_name.equals_insensitive(RHS: "BEQZC") ||
1780 op_name.equals_insensitive(RHS: "BEQZC64")) {
1781 if (rs_val == 0)
1782 target = pc + offset;
1783 else
1784 target = pc + 4;
1785 } else if (op_name.equals_insensitive(RHS: "BNEZC") ||
1786 op_name.equals_insensitive(RHS: "BNEZC64")) {
1787 if (rs_val != 0)
1788 target = pc + offset;
1789 else
1790 target = pc + 4;
1791 }
1792
1793 Context context;
1794 context.type = eContextRelativeBranchImmediate;
1795 context.SetImmediate(current_inst_size + offset);
1796
1797 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1798 reg_value: target);
1799}
1800
1801bool EmulateInstructionMIPS64::Emulate_J(llvm::MCInst &insn) {
1802 bool success = false;
1803 uint64_t offset, pc;
1804
1805 /*
1806 * J offset
1807 * offset = sign_ext (offset << 2)
1808 * PC = PC[63-28] | offset
1809 */
1810 offset = insn.getOperand(i: 0).getImm();
1811
1812 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1813 if (!success)
1814 return false;
1815
1816 /* This is a PC-region branch and not PC-relative */
1817 pc = (pc & 0xFFFFFFFFF0000000ULL) | offset;
1818
1819 Context context;
1820
1821 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1822 reg_value: pc);
1823}
1824
1825bool EmulateInstructionMIPS64::Emulate_JAL(llvm::MCInst &insn) {
1826 bool success = false;
1827 uint64_t offset, target, pc;
1828
1829 /*
1830 * JAL offset
1831 * offset = sign_ext (offset << 2)
1832 * PC = PC[63-28] | offset
1833 */
1834 offset = insn.getOperand(i: 0).getImm();
1835
1836 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1837 if (!success)
1838 return false;
1839
1840 /* This is a PC-region branch and not PC-relative */
1841 target = (pc & 0xFFFFFFFFF0000000ULL) | offset;
1842
1843 Context context;
1844
1845 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1846 reg_value: target))
1847 return false;
1848
1849 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1850 reg_value: pc + 8))
1851 return false;
1852
1853 return true;
1854}
1855
1856bool EmulateInstructionMIPS64::Emulate_JALR(llvm::MCInst &insn) {
1857 bool success = false;
1858 uint32_t rs, rt;
1859 uint64_t pc, rs_val;
1860
1861 /*
1862 * JALR rt, rs
1863 * GPR[rt] = PC + 8
1864 * PC = GPR[rs]
1865 */
1866 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1867 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 1).getReg());
1868
1869 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1870 if (!success)
1871 return false;
1872
1873 rs_val = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + rs, fail_value: 0,
1874 success_ptr: &success);
1875 if (!success)
1876 return false;
1877
1878 Context context;
1879
1880 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1881 reg_value: rs_val))
1882 return false;
1883
1884 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF,
1885 reg_num: dwarf_zero_mips64 + rt, reg_value: pc + 8))
1886 return false;
1887
1888 return true;
1889}
1890
1891bool EmulateInstructionMIPS64::Emulate_JIALC(llvm::MCInst &insn) {
1892 bool success = false;
1893 uint32_t rt;
1894 int64_t target, offset, pc, rt_val;
1895
1896 /*
1897 * JIALC rt, offset
1898 * offset = sign_ext (offset)
1899 * PC = GPR[rt] + offset
1900 * RA = PC + 4
1901 */
1902 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1903 offset = insn.getOperand(i: 1).getImm();
1904
1905 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1906 if (!success)
1907 return false;
1908
1909 rt_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1910 reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1911 if (!success)
1912 return false;
1913
1914 target = rt_val + offset;
1915
1916 Context context;
1917
1918 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1919 reg_value: target))
1920 return false;
1921
1922 if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_ra_mips64,
1923 reg_value: pc + 4))
1924 return false;
1925
1926 return true;
1927}
1928
1929bool EmulateInstructionMIPS64::Emulate_JIC(llvm::MCInst &insn) {
1930 bool success = false;
1931 uint32_t rt;
1932 int64_t target, offset, rt_val;
1933
1934 /*
1935 * JIC rt, offset
1936 * offset = sign_ext (offset)
1937 * PC = GPR[rt] + offset
1938 */
1939 rt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1940 offset = insn.getOperand(i: 1).getImm();
1941
1942 rt_val = (int64_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
1943 reg_num: dwarf_zero_mips64 + rt, fail_value: 0, success_ptr: &success);
1944 if (!success)
1945 return false;
1946
1947 target = rt_val + offset;
1948
1949 Context context;
1950
1951 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1952 reg_value: target);
1953}
1954
1955bool EmulateInstructionMIPS64::Emulate_JR(llvm::MCInst &insn) {
1956 bool success = false;
1957 uint32_t rs;
1958 uint64_t rs_val;
1959
1960 /*
1961 * JR rs
1962 * PC = GPR[rs]
1963 */
1964 rs = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1965
1966 rs_val = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + rs, fail_value: 0,
1967 success_ptr: &success);
1968 if (!success)
1969 return false;
1970
1971 Context context;
1972
1973 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
1974 reg_value: rs_val);
1975}
1976
1977/*
1978 Emulate Branch on FP True/False
1979 BC1F, BC1FL : Branch on FP False (L stands for branch likely)
1980 BC1T, BC1TL : Branch on FP True (L stands for branch likely)
1981*/
1982bool EmulateInstructionMIPS64::Emulate_FP_branch(llvm::MCInst &insn) {
1983 bool success = false;
1984 uint32_t cc, fcsr;
1985 int64_t pc, offset, target = 0;
1986 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
1987
1988 /*
1989 * BC1F cc, offset
1990 * condition <- (FPConditionCode(cc) == 0)
1991 * if condition then
1992 * offset = sign_ext (offset)
1993 * PC = PC + offset
1994 */
1995 cc = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
1996 offset = insn.getOperand(i: 1).getImm();
1997
1998 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
1999 if (!success)
2000 return false;
2001
2002 fcsr =
2003 ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_fcsr_mips64, fail_value: 0, success_ptr: &success);
2004 if (!success)
2005 return false;
2006
2007 /* fcsr[23], fcsr[25-31] are vaild condition bits */
2008 fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
2009
2010 if (op_name.equals_insensitive(RHS: "BC1F") ||
2011 op_name.equals_insensitive(RHS: "BC1FL")) {
2012 if ((fcsr & (1 << cc)) == 0)
2013 target = pc + offset;
2014 else
2015 target = pc + 8;
2016 } else if (op_name.equals_insensitive(RHS: "BC1T") ||
2017 op_name.equals_insensitive(RHS: "BC1TL")) {
2018 if ((fcsr & (1 << cc)) != 0)
2019 target = pc + offset;
2020 else
2021 target = pc + 8;
2022 }
2023
2024 Context context;
2025
2026 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2027 reg_value: target);
2028}
2029
2030bool EmulateInstructionMIPS64::Emulate_BC1EQZ(llvm::MCInst &insn) {
2031 bool success = false;
2032 uint32_t ft;
2033 uint64_t ft_val;
2034 int64_t target, pc, offset;
2035
2036 /*
2037 * BC1EQZ ft, offset
2038 * condition <- (FPR[ft].bit0 == 0)
2039 * if condition then
2040 * offset = sign_ext (offset)
2041 * PC = PC + 4 + offset
2042 */
2043 ft = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
2044 offset = insn.getOperand(i: 1).getImm();
2045
2046 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
2047 if (!success)
2048 return false;
2049
2050 ft_val = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + ft, fail_value: 0,
2051 success_ptr: &success);
2052 if (!success)
2053 return false;
2054
2055 if ((ft_val & 1) == 0)
2056 target = pc + 4 + offset;
2057 else
2058 target = pc + 8;
2059
2060 Context context;
2061
2062 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2063 reg_value: target);
2064}
2065
2066bool EmulateInstructionMIPS64::Emulate_BC1NEZ(llvm::MCInst &insn) {
2067 bool success = false;
2068 uint32_t ft;
2069 uint64_t ft_val;
2070 int64_t target, pc, offset;
2071
2072 /*
2073 * BC1NEZ ft, offset
2074 * condition <- (FPR[ft].bit0 != 0)
2075 * if condition then
2076 * offset = sign_ext (offset)
2077 * PC = PC + 4 + offset
2078 */
2079 ft = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
2080 offset = insn.getOperand(i: 1).getImm();
2081
2082 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
2083 if (!success)
2084 return false;
2085
2086 ft_val = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips64 + ft, fail_value: 0,
2087 success_ptr: &success);
2088 if (!success)
2089 return false;
2090
2091 if ((ft_val & 1) != 0)
2092 target = pc + 4 + offset;
2093 else
2094 target = pc + 8;
2095
2096 Context context;
2097
2098 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2099 reg_value: target);
2100}
2101
2102/*
2103 Emulate MIPS-3D Branch instructions
2104 BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes
2105 False/True
2106 BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes
2107 False/True
2108*/
2109bool EmulateInstructionMIPS64::Emulate_3D_branch(llvm::MCInst &insn) {
2110 bool success = false;
2111 uint32_t cc, fcsr;
2112 int64_t pc, offset, target = 0;
2113 llvm::StringRef op_name = m_insn_info->getName(Opcode: insn.getOpcode());
2114
2115 cc = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
2116 offset = insn.getOperand(i: 1).getImm();
2117
2118 pc = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
2119 if (!success)
2120 return false;
2121
2122 fcsr = (uint32_t)ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_fcsr_mips64,
2123 fail_value: 0, success_ptr: &success);
2124 if (!success)
2125 return false;
2126
2127 /* fcsr[23], fcsr[25-31] are vaild condition bits */
2128 fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
2129
2130 if (op_name.equals_insensitive(RHS: "BC1ANY2F")) {
2131 /* if any one bit is 0 */
2132 if (((fcsr >> cc) & 3) != 3)
2133 target = pc + offset;
2134 else
2135 target = pc + 8;
2136 } else if (op_name.equals_insensitive(RHS: "BC1ANY2T")) {
2137 /* if any one bit is 1 */
2138 if (((fcsr >> cc) & 3) != 0)
2139 target = pc + offset;
2140 else
2141 target = pc + 8;
2142 } else if (op_name.equals_insensitive(RHS: "BC1ANY4F")) {
2143 /* if any one bit is 0 */
2144 if (((fcsr >> cc) & 0xf) != 0xf)
2145 target = pc + offset;
2146 else
2147 target = pc + 8;
2148 } else if (op_name.equals_insensitive(RHS: "BC1ANY4T")) {
2149 /* if any one bit is 1 */
2150 if (((fcsr >> cc) & 0xf) != 0)
2151 target = pc + offset;
2152 else
2153 target = pc + 8;
2154 }
2155
2156 Context context;
2157
2158 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2159 reg_value: target);
2160}
2161
2162bool EmulateInstructionMIPS64::Emulate_BNZB(llvm::MCInst &insn) {
2163 return Emulate_MSA_Branch_DF(insn, element_byte_size: 1, bnz: true);
2164}
2165
2166bool EmulateInstructionMIPS64::Emulate_BNZH(llvm::MCInst &insn) {
2167 return Emulate_MSA_Branch_DF(insn, element_byte_size: 2, bnz: true);
2168}
2169
2170bool EmulateInstructionMIPS64::Emulate_BNZW(llvm::MCInst &insn) {
2171 return Emulate_MSA_Branch_DF(insn, element_byte_size: 4, bnz: true);
2172}
2173
2174bool EmulateInstructionMIPS64::Emulate_BNZD(llvm::MCInst &insn) {
2175 return Emulate_MSA_Branch_DF(insn, element_byte_size: 8, bnz: true);
2176}
2177
2178bool EmulateInstructionMIPS64::Emulate_BZB(llvm::MCInst &insn) {
2179 return Emulate_MSA_Branch_DF(insn, element_byte_size: 1, bnz: false);
2180}
2181
2182bool EmulateInstructionMIPS64::Emulate_BZH(llvm::MCInst &insn) {
2183 return Emulate_MSA_Branch_DF(insn, element_byte_size: 2, bnz: false);
2184}
2185
2186bool EmulateInstructionMIPS64::Emulate_BZW(llvm::MCInst &insn) {
2187 return Emulate_MSA_Branch_DF(insn, element_byte_size: 4, bnz: false);
2188}
2189
2190bool EmulateInstructionMIPS64::Emulate_BZD(llvm::MCInst &insn) {
2191 return Emulate_MSA_Branch_DF(insn, element_byte_size: 8, bnz: false);
2192}
2193
2194bool EmulateInstructionMIPS64::Emulate_MSA_Branch_DF(llvm::MCInst &insn,
2195 int element_byte_size,
2196 bool bnz) {
2197 bool success = false, branch_hit = true;
2198 int64_t target = 0;
2199 RegisterValue reg_value;
2200 const uint8_t *ptr = nullptr;
2201
2202 uint32_t wt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
2203 int64_t offset = insn.getOperand(i: 1).getImm();
2204
2205 int64_t pc =
2206 ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
2207 if (!success)
2208 return false;
2209
2210 if (ReadRegister(reg_kind: eRegisterKindDWARF, reg_num: dwarf_w0_mips64 + wt, reg_value))
2211 ptr = (const uint8_t *)reg_value.GetBytes();
2212 else
2213 return false;
2214
2215 for (int i = 0; i < 16 / element_byte_size; i++) {
2216 switch (element_byte_size) {
2217 case 1:
2218 if ((*ptr == 0 && bnz) || (*ptr != 0 && !bnz))
2219 branch_hit = false;
2220 break;
2221 case 2:
2222 if ((*(const uint16_t *)ptr == 0 && bnz) ||
2223 (*(const uint16_t *)ptr != 0 && !bnz))
2224 branch_hit = false;
2225 break;
2226 case 4:
2227 if ((*(const uint32_t *)ptr == 0 && bnz) ||
2228 (*(const uint32_t *)ptr != 0 && !bnz))
2229 branch_hit = false;
2230 break;
2231 case 8:
2232 if ((*(const uint64_t *)ptr == 0 && bnz) ||
2233 (*(const uint64_t *)ptr != 0 && !bnz))
2234 branch_hit = false;
2235 break;
2236 }
2237 if (!branch_hit)
2238 break;
2239 ptr = ptr + element_byte_size;
2240 }
2241
2242 if (branch_hit)
2243 target = pc + offset;
2244 else
2245 target = pc + 8;
2246
2247 Context context;
2248 context.type = eContextRelativeBranchImmediate;
2249
2250 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2251 reg_value: target);
2252}
2253
2254bool EmulateInstructionMIPS64::Emulate_BNZV(llvm::MCInst &insn) {
2255 return Emulate_MSA_Branch_V(insn, bnz: true);
2256}
2257
2258bool EmulateInstructionMIPS64::Emulate_BZV(llvm::MCInst &insn) {
2259 return Emulate_MSA_Branch_V(insn, bnz: false);
2260}
2261
2262bool EmulateInstructionMIPS64::Emulate_MSA_Branch_V(llvm::MCInst &insn,
2263 bool bnz) {
2264 bool success = false;
2265 int64_t target = 0;
2266 llvm::APInt wr_val = llvm::APInt::getZero(numBits: 128);
2267 llvm::APInt fail_value = llvm::APInt::getMaxValue(numBits: 128);
2268 llvm::APInt zero_value = llvm::APInt::getZero(numBits: 128);
2269 RegisterValue reg_value;
2270
2271 uint32_t wt = m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: 0).getReg());
2272 int64_t offset = insn.getOperand(i: 1).getImm();
2273
2274 int64_t pc =
2275 ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64, fail_value: 0, success_ptr: &success);
2276 if (!success)
2277 return false;
2278
2279 if (ReadRegister(reg_kind: eRegisterKindDWARF, reg_num: dwarf_w0_mips64 + wt, reg_value))
2280 wr_val = reg_value.GetAsUInt128(fail_value);
2281 else
2282 return false;
2283
2284 if ((llvm::APInt::isSameValue(I1: zero_value, I2: wr_val) && !bnz) ||
2285 (!llvm::APInt::isSameValue(I1: zero_value, I2: wr_val) && bnz))
2286 target = pc + offset;
2287 else
2288 target = pc + 8;
2289
2290 Context context;
2291 context.type = eContextRelativeBranchImmediate;
2292
2293 return WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc_mips64,
2294 reg_value: target);
2295}
2296
2297bool EmulateInstructionMIPS64::Emulate_LDST_Imm(llvm::MCInst &insn) {
2298 bool success = false;
2299 uint32_t base;
2300 int64_t imm, address;
2301 Context bad_vaddr_context;
2302
2303 uint32_t num_operands = insn.getNumOperands();
2304 base =
2305 m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: num_operands - 2).getReg());
2306 imm = insn.getOperand(i: num_operands - 1).getImm();
2307
2308 if (!GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips + base))
2309 return false;
2310
2311 /* read base register */
2312 address = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips + base, fail_value: 0,
2313 success_ptr: &success);
2314 if (!success)
2315 return false;
2316
2317 /* destination address */
2318 address = address + imm;
2319
2320 /* Set the bad_vaddr register with base address used in the instruction */
2321 bad_vaddr_context.type = eContextInvalid;
2322 WriteRegisterUnsigned(context: bad_vaddr_context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_bad_mips,
2323 reg_value: address);
2324
2325 return true;
2326}
2327
2328bool EmulateInstructionMIPS64::Emulate_LDST_Reg(llvm::MCInst &insn) {
2329 bool success = false;
2330 uint32_t base, index;
2331 int64_t address, index_address;
2332 Context bad_vaddr_context;
2333
2334 uint32_t num_operands = insn.getNumOperands();
2335 base =
2336 m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: num_operands - 2).getReg());
2337 index =
2338 m_reg_info->getEncodingValue(RegNo: insn.getOperand(i: num_operands - 1).getReg());
2339
2340 if (!GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips + base))
2341 return false;
2342
2343 if (!GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips + index))
2344 return false;
2345
2346 /* read base register */
2347 address = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_zero_mips + base, fail_value: 0,
2348 success_ptr: &success);
2349 if (!success)
2350 return false;
2351
2352 /* read index register */
2353 index_address = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF,
2354 reg_num: dwarf_zero_mips + index, fail_value: 0, success_ptr: &success);
2355 if (!success)
2356 return false;
2357
2358 /* destination address */
2359 address = address + index_address;
2360
2361 /* Set the bad_vaddr register with base address used in the instruction */
2362 bad_vaddr_context.type = eContextInvalid;
2363 WriteRegisterUnsigned(context: bad_vaddr_context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_bad_mips,
2364 reg_value: address);
2365
2366 return true;
2367}
2368

source code of lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp