xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- EmulateInstructionMIPS.cpp ----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "EmulateInstructionMIPS.h"
10061da546Spatrick 
11be691f3bSpatrick #include <cstdlib>
12*f6aab3d8Srobert #include <optional>
13061da546Spatrick 
14061da546Spatrick #include "lldb/Core/Address.h"
15061da546Spatrick #include "lldb/Core/Opcode.h"
16061da546Spatrick #include "lldb/Core/PluginManager.h"
17061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
18061da546Spatrick #include "lldb/Target/Target.h"
19061da546Spatrick #include "lldb/Utility/ArchSpec.h"
20061da546Spatrick #include "lldb/Utility/ConstString.h"
21061da546Spatrick #include "lldb/Utility/DataExtractor.h"
22061da546Spatrick #include "lldb/Utility/RegisterValue.h"
23061da546Spatrick #include "lldb/Utility/Stream.h"
24061da546Spatrick #include "llvm-c/Disassembler.h"
25061da546Spatrick #include "llvm/MC/MCAsmInfo.h"
26061da546Spatrick #include "llvm/MC/MCContext.h"
27061da546Spatrick #include "llvm/MC/MCDisassembler/MCDisassembler.h"
28061da546Spatrick #include "llvm/MC/MCInst.h"
29061da546Spatrick #include "llvm/MC/MCInstrInfo.h"
30061da546Spatrick #include "llvm/MC/MCRegisterInfo.h"
31061da546Spatrick #include "llvm/MC/MCSubtargetInfo.h"
32061da546Spatrick #include "llvm/MC/MCTargetOptions.h"
33*f6aab3d8Srobert #include "llvm/MC/TargetRegistry.h"
34061da546Spatrick #include "llvm/Support/TargetSelect.h"
35061da546Spatrick 
36061da546Spatrick #include "llvm/ADT/STLExtras.h"
37061da546Spatrick 
38061da546Spatrick #include "Plugins/Process/Utility/InstructionUtils.h"
39061da546Spatrick #include "Plugins/Process/Utility/RegisterContext_mips.h"
40061da546Spatrick 
41061da546Spatrick using namespace lldb;
42061da546Spatrick using namespace lldb_private;
43061da546Spatrick 
LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS,InstructionMIPS)44dda28197Spatrick LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionMIPS, InstructionMIPS)
45dda28197Spatrick 
46061da546Spatrick #define UInt(x) ((uint64_t)x)
47061da546Spatrick #define integer int64_t
48061da546Spatrick 
49061da546Spatrick //
50061da546Spatrick // EmulateInstructionMIPS implementation
51061da546Spatrick //
52061da546Spatrick 
53061da546Spatrick #ifdef __mips__
54061da546Spatrick extern "C" {
55061da546Spatrick void LLVMInitializeMipsTargetInfo();
56061da546Spatrick void LLVMInitializeMipsTarget();
57061da546Spatrick void LLVMInitializeMipsAsmPrinter();
58061da546Spatrick void LLVMInitializeMipsTargetMC();
59061da546Spatrick void LLVMInitializeMipsDisassembler();
60061da546Spatrick }
61061da546Spatrick #endif
62061da546Spatrick 
EmulateInstructionMIPS(const lldb_private::ArchSpec & arch)63061da546Spatrick EmulateInstructionMIPS::EmulateInstructionMIPS(
64061da546Spatrick     const lldb_private::ArchSpec &arch)
65061da546Spatrick     : EmulateInstruction(arch) {
66061da546Spatrick   /* Create instance of llvm::MCDisassembler */
67061da546Spatrick   std::string Status;
68061da546Spatrick   llvm::Triple triple = arch.GetTriple();
69061da546Spatrick   const llvm::Target *target =
70061da546Spatrick       llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
71061da546Spatrick 
72061da546Spatrick /*
73061da546Spatrick  * If we fail to get the target then we haven't registered it. The
74061da546Spatrick  * SystemInitializerCommon
75061da546Spatrick  * does not initialize targets, MCs and disassemblers. However we need the
76061da546Spatrick  * MCDisassembler
77061da546Spatrick  * to decode the instructions so that the decoding complexity stays with LLVM.
78061da546Spatrick  * Initialize the MIPS targets and disassemblers.
79061da546Spatrick */
80061da546Spatrick #ifdef __mips__
81061da546Spatrick   if (!target) {
82061da546Spatrick     LLVMInitializeMipsTargetInfo();
83061da546Spatrick     LLVMInitializeMipsTarget();
84061da546Spatrick     LLVMInitializeMipsAsmPrinter();
85061da546Spatrick     LLVMInitializeMipsTargetMC();
86061da546Spatrick     LLVMInitializeMipsDisassembler();
87061da546Spatrick     target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
88061da546Spatrick   }
89061da546Spatrick #endif
90061da546Spatrick 
91061da546Spatrick   assert(target);
92061da546Spatrick 
93061da546Spatrick   llvm::StringRef cpu;
94061da546Spatrick 
95061da546Spatrick   switch (arch.GetCore()) {
96061da546Spatrick   case ArchSpec::eCore_mips32:
97061da546Spatrick   case ArchSpec::eCore_mips32el:
98061da546Spatrick     cpu = "mips32";
99061da546Spatrick     break;
100061da546Spatrick   case ArchSpec::eCore_mips32r2:
101061da546Spatrick   case ArchSpec::eCore_mips32r2el:
102061da546Spatrick     cpu = "mips32r2";
103061da546Spatrick     break;
104061da546Spatrick   case ArchSpec::eCore_mips32r3:
105061da546Spatrick   case ArchSpec::eCore_mips32r3el:
106061da546Spatrick     cpu = "mips32r3";
107061da546Spatrick     break;
108061da546Spatrick   case ArchSpec::eCore_mips32r5:
109061da546Spatrick   case ArchSpec::eCore_mips32r5el:
110061da546Spatrick     cpu = "mips32r5";
111061da546Spatrick     break;
112061da546Spatrick   case ArchSpec::eCore_mips32r6:
113061da546Spatrick   case ArchSpec::eCore_mips32r6el:
114061da546Spatrick     cpu = "mips32r6";
115061da546Spatrick     break;
116061da546Spatrick   case ArchSpec::eCore_mips64:
117061da546Spatrick   case ArchSpec::eCore_mips64el:
118061da546Spatrick     cpu = "mips64";
119061da546Spatrick     break;
120061da546Spatrick   case ArchSpec::eCore_mips64r2:
121061da546Spatrick   case ArchSpec::eCore_mips64r2el:
122061da546Spatrick     cpu = "mips64r2";
123061da546Spatrick     break;
124061da546Spatrick   case ArchSpec::eCore_mips64r3:
125061da546Spatrick   case ArchSpec::eCore_mips64r3el:
126061da546Spatrick     cpu = "mips64r3";
127061da546Spatrick     break;
128061da546Spatrick   case ArchSpec::eCore_mips64r5:
129061da546Spatrick   case ArchSpec::eCore_mips64r5el:
130061da546Spatrick     cpu = "mips64r5";
131061da546Spatrick     break;
132061da546Spatrick   case ArchSpec::eCore_mips64r6:
133061da546Spatrick   case ArchSpec::eCore_mips64r6el:
134061da546Spatrick     cpu = "mips64r6";
135061da546Spatrick     break;
136061da546Spatrick   default:
137061da546Spatrick     cpu = "generic";
138061da546Spatrick     break;
139061da546Spatrick   }
140061da546Spatrick 
141*f6aab3d8Srobert   std::string features;
142061da546Spatrick   uint32_t arch_flags = arch.GetFlags();
143061da546Spatrick   if (arch_flags & ArchSpec::eMIPSAse_msa)
144061da546Spatrick     features += "+msa,";
145061da546Spatrick   if (arch_flags & ArchSpec::eMIPSAse_dsp)
146061da546Spatrick     features += "+dsp,";
147061da546Spatrick   if (arch_flags & ArchSpec::eMIPSAse_dspr2)
148061da546Spatrick     features += "+dspr2,";
149061da546Spatrick 
150061da546Spatrick   m_reg_info.reset(target->createMCRegInfo(triple.getTriple()));
151061da546Spatrick   assert(m_reg_info.get());
152061da546Spatrick 
153061da546Spatrick   m_insn_info.reset(target->createMCInstrInfo());
154061da546Spatrick   assert(m_insn_info.get());
155061da546Spatrick 
156061da546Spatrick   llvm::MCTargetOptions MCOptions;
157061da546Spatrick   m_asm_info.reset(
158061da546Spatrick       target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions));
159061da546Spatrick   m_subtype_info.reset(
160061da546Spatrick       target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
161061da546Spatrick   assert(m_asm_info.get() && m_subtype_info.get());
162061da546Spatrick 
163be691f3bSpatrick   m_context = std::make_unique<llvm::MCContext>(
164be691f3bSpatrick       triple, m_asm_info.get(), m_reg_info.get(), m_subtype_info.get());
165061da546Spatrick   assert(m_context.get());
166061da546Spatrick 
167061da546Spatrick   m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context));
168061da546Spatrick   assert(m_disasm.get());
169061da546Spatrick 
170061da546Spatrick   /* Create alternate disassembler for microMIPS */
171061da546Spatrick   if (arch_flags & ArchSpec::eMIPSAse_mips16)
172061da546Spatrick     features += "+mips16,";
173061da546Spatrick   else if (arch_flags & ArchSpec::eMIPSAse_micromips)
174061da546Spatrick     features += "+micromips,";
175061da546Spatrick 
176061da546Spatrick   m_alt_subtype_info.reset(
177061da546Spatrick       target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
178061da546Spatrick   assert(m_alt_subtype_info.get());
179061da546Spatrick 
180061da546Spatrick   m_alt_disasm.reset(
181061da546Spatrick       target->createMCDisassembler(*m_alt_subtype_info, *m_context));
182061da546Spatrick   assert(m_alt_disasm.get());
183061da546Spatrick 
184061da546Spatrick   m_next_inst_size = 0;
185061da546Spatrick   m_use_alt_disaasm = false;
186061da546Spatrick }
187061da546Spatrick 
Initialize()188061da546Spatrick void EmulateInstructionMIPS::Initialize() {
189061da546Spatrick   PluginManager::RegisterPlugin(GetPluginNameStatic(),
190061da546Spatrick                                 GetPluginDescriptionStatic(), CreateInstance);
191061da546Spatrick }
192061da546Spatrick 
Terminate()193061da546Spatrick void EmulateInstructionMIPS::Terminate() {
194061da546Spatrick   PluginManager::UnregisterPlugin(CreateInstance);
195061da546Spatrick }
196061da546Spatrick 
GetPluginDescriptionStatic()197*f6aab3d8Srobert llvm::StringRef EmulateInstructionMIPS::GetPluginDescriptionStatic() {
198061da546Spatrick   return "Emulate instructions for the MIPS32 architecture.";
199061da546Spatrick }
200061da546Spatrick 
201061da546Spatrick EmulateInstruction *
CreateInstance(const ArchSpec & arch,InstructionType inst_type)202061da546Spatrick EmulateInstructionMIPS::CreateInstance(const ArchSpec &arch,
203061da546Spatrick                                        InstructionType inst_type) {
204061da546Spatrick   if (EmulateInstructionMIPS::SupportsEmulatingInstructionsOfTypeStatic(
205061da546Spatrick           inst_type)) {
206061da546Spatrick     if (arch.GetTriple().getArch() == llvm::Triple::mips ||
207061da546Spatrick         arch.GetTriple().getArch() == llvm::Triple::mipsel) {
208061da546Spatrick       return new EmulateInstructionMIPS(arch);
209061da546Spatrick     }
210061da546Spatrick   }
211061da546Spatrick 
212061da546Spatrick   return nullptr;
213061da546Spatrick }
214061da546Spatrick 
SetTargetTriple(const ArchSpec & arch)215061da546Spatrick bool EmulateInstructionMIPS::SetTargetTriple(const ArchSpec &arch) {
216061da546Spatrick   return arch.GetTriple().getArch() == llvm::Triple::mips ||
217061da546Spatrick          arch.GetTriple().getArch() == llvm::Triple::mipsel;
218061da546Spatrick }
219061da546Spatrick 
GetRegisterName(unsigned reg_num,bool alternate_name)220061da546Spatrick const char *EmulateInstructionMIPS::GetRegisterName(unsigned reg_num,
221061da546Spatrick                                                     bool alternate_name) {
222061da546Spatrick   if (alternate_name) {
223061da546Spatrick     switch (reg_num) {
224061da546Spatrick     case dwarf_sp_mips:
225061da546Spatrick       return "r29";
226061da546Spatrick     case dwarf_r30_mips:
227061da546Spatrick       return "r30";
228061da546Spatrick     case dwarf_ra_mips:
229061da546Spatrick       return "r31";
230061da546Spatrick     case dwarf_f0_mips:
231061da546Spatrick       return "f0";
232061da546Spatrick     case dwarf_f1_mips:
233061da546Spatrick       return "f1";
234061da546Spatrick     case dwarf_f2_mips:
235061da546Spatrick       return "f2";
236061da546Spatrick     case dwarf_f3_mips:
237061da546Spatrick       return "f3";
238061da546Spatrick     case dwarf_f4_mips:
239061da546Spatrick       return "f4";
240061da546Spatrick     case dwarf_f5_mips:
241061da546Spatrick       return "f5";
242061da546Spatrick     case dwarf_f6_mips:
243061da546Spatrick       return "f6";
244061da546Spatrick     case dwarf_f7_mips:
245061da546Spatrick       return "f7";
246061da546Spatrick     case dwarf_f8_mips:
247061da546Spatrick       return "f8";
248061da546Spatrick     case dwarf_f9_mips:
249061da546Spatrick       return "f9";
250061da546Spatrick     case dwarf_f10_mips:
251061da546Spatrick       return "f10";
252061da546Spatrick     case dwarf_f11_mips:
253061da546Spatrick       return "f11";
254061da546Spatrick     case dwarf_f12_mips:
255061da546Spatrick       return "f12";
256061da546Spatrick     case dwarf_f13_mips:
257061da546Spatrick       return "f13";
258061da546Spatrick     case dwarf_f14_mips:
259061da546Spatrick       return "f14";
260061da546Spatrick     case dwarf_f15_mips:
261061da546Spatrick       return "f15";
262061da546Spatrick     case dwarf_f16_mips:
263061da546Spatrick       return "f16";
264061da546Spatrick     case dwarf_f17_mips:
265061da546Spatrick       return "f17";
266061da546Spatrick     case dwarf_f18_mips:
267061da546Spatrick       return "f18";
268061da546Spatrick     case dwarf_f19_mips:
269061da546Spatrick       return "f19";
270061da546Spatrick     case dwarf_f20_mips:
271061da546Spatrick       return "f20";
272061da546Spatrick     case dwarf_f21_mips:
273061da546Spatrick       return "f21";
274061da546Spatrick     case dwarf_f22_mips:
275061da546Spatrick       return "f22";
276061da546Spatrick     case dwarf_f23_mips:
277061da546Spatrick       return "f23";
278061da546Spatrick     case dwarf_f24_mips:
279061da546Spatrick       return "f24";
280061da546Spatrick     case dwarf_f25_mips:
281061da546Spatrick       return "f25";
282061da546Spatrick     case dwarf_f26_mips:
283061da546Spatrick       return "f26";
284061da546Spatrick     case dwarf_f27_mips:
285061da546Spatrick       return "f27";
286061da546Spatrick     case dwarf_f28_mips:
287061da546Spatrick       return "f28";
288061da546Spatrick     case dwarf_f29_mips:
289061da546Spatrick       return "f29";
290061da546Spatrick     case dwarf_f30_mips:
291061da546Spatrick       return "f30";
292061da546Spatrick     case dwarf_f31_mips:
293061da546Spatrick       return "f31";
294061da546Spatrick     case dwarf_w0_mips:
295061da546Spatrick       return "w0";
296061da546Spatrick     case dwarf_w1_mips:
297061da546Spatrick       return "w1";
298061da546Spatrick     case dwarf_w2_mips:
299061da546Spatrick       return "w2";
300061da546Spatrick     case dwarf_w3_mips:
301061da546Spatrick       return "w3";
302061da546Spatrick     case dwarf_w4_mips:
303061da546Spatrick       return "w4";
304061da546Spatrick     case dwarf_w5_mips:
305061da546Spatrick       return "w5";
306061da546Spatrick     case dwarf_w6_mips:
307061da546Spatrick       return "w6";
308061da546Spatrick     case dwarf_w7_mips:
309061da546Spatrick       return "w7";
310061da546Spatrick     case dwarf_w8_mips:
311061da546Spatrick       return "w8";
312061da546Spatrick     case dwarf_w9_mips:
313061da546Spatrick       return "w9";
314061da546Spatrick     case dwarf_w10_mips:
315061da546Spatrick       return "w10";
316061da546Spatrick     case dwarf_w11_mips:
317061da546Spatrick       return "w11";
318061da546Spatrick     case dwarf_w12_mips:
319061da546Spatrick       return "w12";
320061da546Spatrick     case dwarf_w13_mips:
321061da546Spatrick       return "w13";
322061da546Spatrick     case dwarf_w14_mips:
323061da546Spatrick       return "w14";
324061da546Spatrick     case dwarf_w15_mips:
325061da546Spatrick       return "w15";
326061da546Spatrick     case dwarf_w16_mips:
327061da546Spatrick       return "w16";
328061da546Spatrick     case dwarf_w17_mips:
329061da546Spatrick       return "w17";
330061da546Spatrick     case dwarf_w18_mips:
331061da546Spatrick       return "w18";
332061da546Spatrick     case dwarf_w19_mips:
333061da546Spatrick       return "w19";
334061da546Spatrick     case dwarf_w20_mips:
335061da546Spatrick       return "w20";
336061da546Spatrick     case dwarf_w21_mips:
337061da546Spatrick       return "w21";
338061da546Spatrick     case dwarf_w22_mips:
339061da546Spatrick       return "w22";
340061da546Spatrick     case dwarf_w23_mips:
341061da546Spatrick       return "w23";
342061da546Spatrick     case dwarf_w24_mips:
343061da546Spatrick       return "w24";
344061da546Spatrick     case dwarf_w25_mips:
345061da546Spatrick       return "w25";
346061da546Spatrick     case dwarf_w26_mips:
347061da546Spatrick       return "w26";
348061da546Spatrick     case dwarf_w27_mips:
349061da546Spatrick       return "w27";
350061da546Spatrick     case dwarf_w28_mips:
351061da546Spatrick       return "w28";
352061da546Spatrick     case dwarf_w29_mips:
353061da546Spatrick       return "w29";
354061da546Spatrick     case dwarf_w30_mips:
355061da546Spatrick       return "w30";
356061da546Spatrick     case dwarf_w31_mips:
357061da546Spatrick       return "w31";
358061da546Spatrick     case dwarf_mir_mips:
359061da546Spatrick       return "mir";
360061da546Spatrick     case dwarf_mcsr_mips:
361061da546Spatrick       return "mcsr";
362061da546Spatrick     case dwarf_config5_mips:
363061da546Spatrick       return "config5";
364061da546Spatrick     default:
365061da546Spatrick       break;
366061da546Spatrick     }
367061da546Spatrick     return nullptr;
368061da546Spatrick   }
369061da546Spatrick 
370061da546Spatrick   switch (reg_num) {
371061da546Spatrick   case dwarf_zero_mips:
372061da546Spatrick     return "r0";
373061da546Spatrick   case dwarf_r1_mips:
374061da546Spatrick     return "r1";
375061da546Spatrick   case dwarf_r2_mips:
376061da546Spatrick     return "r2";
377061da546Spatrick   case dwarf_r3_mips:
378061da546Spatrick     return "r3";
379061da546Spatrick   case dwarf_r4_mips:
380061da546Spatrick     return "r4";
381061da546Spatrick   case dwarf_r5_mips:
382061da546Spatrick     return "r5";
383061da546Spatrick   case dwarf_r6_mips:
384061da546Spatrick     return "r6";
385061da546Spatrick   case dwarf_r7_mips:
386061da546Spatrick     return "r7";
387061da546Spatrick   case dwarf_r8_mips:
388061da546Spatrick     return "r8";
389061da546Spatrick   case dwarf_r9_mips:
390061da546Spatrick     return "r9";
391061da546Spatrick   case dwarf_r10_mips:
392061da546Spatrick     return "r10";
393061da546Spatrick   case dwarf_r11_mips:
394061da546Spatrick     return "r11";
395061da546Spatrick   case dwarf_r12_mips:
396061da546Spatrick     return "r12";
397061da546Spatrick   case dwarf_r13_mips:
398061da546Spatrick     return "r13";
399061da546Spatrick   case dwarf_r14_mips:
400061da546Spatrick     return "r14";
401061da546Spatrick   case dwarf_r15_mips:
402061da546Spatrick     return "r15";
403061da546Spatrick   case dwarf_r16_mips:
404061da546Spatrick     return "r16";
405061da546Spatrick   case dwarf_r17_mips:
406061da546Spatrick     return "r17";
407061da546Spatrick   case dwarf_r18_mips:
408061da546Spatrick     return "r18";
409061da546Spatrick   case dwarf_r19_mips:
410061da546Spatrick     return "r19";
411061da546Spatrick   case dwarf_r20_mips:
412061da546Spatrick     return "r20";
413061da546Spatrick   case dwarf_r21_mips:
414061da546Spatrick     return "r21";
415061da546Spatrick   case dwarf_r22_mips:
416061da546Spatrick     return "r22";
417061da546Spatrick   case dwarf_r23_mips:
418061da546Spatrick     return "r23";
419061da546Spatrick   case dwarf_r24_mips:
420061da546Spatrick     return "r24";
421061da546Spatrick   case dwarf_r25_mips:
422061da546Spatrick     return "r25";
423061da546Spatrick   case dwarf_r26_mips:
424061da546Spatrick     return "r26";
425061da546Spatrick   case dwarf_r27_mips:
426061da546Spatrick     return "r27";
427061da546Spatrick   case dwarf_gp_mips:
428061da546Spatrick     return "gp";
429061da546Spatrick   case dwarf_sp_mips:
430061da546Spatrick     return "sp";
431061da546Spatrick   case dwarf_r30_mips:
432061da546Spatrick     return "fp";
433061da546Spatrick   case dwarf_ra_mips:
434061da546Spatrick     return "ra";
435061da546Spatrick   case dwarf_sr_mips:
436061da546Spatrick     return "sr";
437061da546Spatrick   case dwarf_lo_mips:
438061da546Spatrick     return "lo";
439061da546Spatrick   case dwarf_hi_mips:
440061da546Spatrick     return "hi";
441061da546Spatrick   case dwarf_bad_mips:
442061da546Spatrick     return "bad";
443061da546Spatrick   case dwarf_cause_mips:
444061da546Spatrick     return "cause";
445061da546Spatrick   case dwarf_pc_mips:
446061da546Spatrick     return "pc";
447061da546Spatrick   case dwarf_f0_mips:
448061da546Spatrick     return "f0";
449061da546Spatrick   case dwarf_f1_mips:
450061da546Spatrick     return "f1";
451061da546Spatrick   case dwarf_f2_mips:
452061da546Spatrick     return "f2";
453061da546Spatrick   case dwarf_f3_mips:
454061da546Spatrick     return "f3";
455061da546Spatrick   case dwarf_f4_mips:
456061da546Spatrick     return "f4";
457061da546Spatrick   case dwarf_f5_mips:
458061da546Spatrick     return "f5";
459061da546Spatrick   case dwarf_f6_mips:
460061da546Spatrick     return "f6";
461061da546Spatrick   case dwarf_f7_mips:
462061da546Spatrick     return "f7";
463061da546Spatrick   case dwarf_f8_mips:
464061da546Spatrick     return "f8";
465061da546Spatrick   case dwarf_f9_mips:
466061da546Spatrick     return "f9";
467061da546Spatrick   case dwarf_f10_mips:
468061da546Spatrick     return "f10";
469061da546Spatrick   case dwarf_f11_mips:
470061da546Spatrick     return "f11";
471061da546Spatrick   case dwarf_f12_mips:
472061da546Spatrick     return "f12";
473061da546Spatrick   case dwarf_f13_mips:
474061da546Spatrick     return "f13";
475061da546Spatrick   case dwarf_f14_mips:
476061da546Spatrick     return "f14";
477061da546Spatrick   case dwarf_f15_mips:
478061da546Spatrick     return "f15";
479061da546Spatrick   case dwarf_f16_mips:
480061da546Spatrick     return "f16";
481061da546Spatrick   case dwarf_f17_mips:
482061da546Spatrick     return "f17";
483061da546Spatrick   case dwarf_f18_mips:
484061da546Spatrick     return "f18";
485061da546Spatrick   case dwarf_f19_mips:
486061da546Spatrick     return "f19";
487061da546Spatrick   case dwarf_f20_mips:
488061da546Spatrick     return "f20";
489061da546Spatrick   case dwarf_f21_mips:
490061da546Spatrick     return "f21";
491061da546Spatrick   case dwarf_f22_mips:
492061da546Spatrick     return "f22";
493061da546Spatrick   case dwarf_f23_mips:
494061da546Spatrick     return "f23";
495061da546Spatrick   case dwarf_f24_mips:
496061da546Spatrick     return "f24";
497061da546Spatrick   case dwarf_f25_mips:
498061da546Spatrick     return "f25";
499061da546Spatrick   case dwarf_f26_mips:
500061da546Spatrick     return "f26";
501061da546Spatrick   case dwarf_f27_mips:
502061da546Spatrick     return "f27";
503061da546Spatrick   case dwarf_f28_mips:
504061da546Spatrick     return "f28";
505061da546Spatrick   case dwarf_f29_mips:
506061da546Spatrick     return "f29";
507061da546Spatrick   case dwarf_f30_mips:
508061da546Spatrick     return "f30";
509061da546Spatrick   case dwarf_f31_mips:
510061da546Spatrick     return "f31";
511061da546Spatrick   case dwarf_fcsr_mips:
512061da546Spatrick     return "fcsr";
513061da546Spatrick   case dwarf_fir_mips:
514061da546Spatrick     return "fir";
515061da546Spatrick   case dwarf_w0_mips:
516061da546Spatrick     return "w0";
517061da546Spatrick   case dwarf_w1_mips:
518061da546Spatrick     return "w1";
519061da546Spatrick   case dwarf_w2_mips:
520061da546Spatrick     return "w2";
521061da546Spatrick   case dwarf_w3_mips:
522061da546Spatrick     return "w3";
523061da546Spatrick   case dwarf_w4_mips:
524061da546Spatrick     return "w4";
525061da546Spatrick   case dwarf_w5_mips:
526061da546Spatrick     return "w5";
527061da546Spatrick   case dwarf_w6_mips:
528061da546Spatrick     return "w6";
529061da546Spatrick   case dwarf_w7_mips:
530061da546Spatrick     return "w7";
531061da546Spatrick   case dwarf_w8_mips:
532061da546Spatrick     return "w8";
533061da546Spatrick   case dwarf_w9_mips:
534061da546Spatrick     return "w9";
535061da546Spatrick   case dwarf_w10_mips:
536061da546Spatrick     return "w10";
537061da546Spatrick   case dwarf_w11_mips:
538061da546Spatrick     return "w11";
539061da546Spatrick   case dwarf_w12_mips:
540061da546Spatrick     return "w12";
541061da546Spatrick   case dwarf_w13_mips:
542061da546Spatrick     return "w13";
543061da546Spatrick   case dwarf_w14_mips:
544061da546Spatrick     return "w14";
545061da546Spatrick   case dwarf_w15_mips:
546061da546Spatrick     return "w15";
547061da546Spatrick   case dwarf_w16_mips:
548061da546Spatrick     return "w16";
549061da546Spatrick   case dwarf_w17_mips:
550061da546Spatrick     return "w17";
551061da546Spatrick   case dwarf_w18_mips:
552061da546Spatrick     return "w18";
553061da546Spatrick   case dwarf_w19_mips:
554061da546Spatrick     return "w19";
555061da546Spatrick   case dwarf_w20_mips:
556061da546Spatrick     return "w20";
557061da546Spatrick   case dwarf_w21_mips:
558061da546Spatrick     return "w21";
559061da546Spatrick   case dwarf_w22_mips:
560061da546Spatrick     return "w22";
561061da546Spatrick   case dwarf_w23_mips:
562061da546Spatrick     return "w23";
563061da546Spatrick   case dwarf_w24_mips:
564061da546Spatrick     return "w24";
565061da546Spatrick   case dwarf_w25_mips:
566061da546Spatrick     return "w25";
567061da546Spatrick   case dwarf_w26_mips:
568061da546Spatrick     return "w26";
569061da546Spatrick   case dwarf_w27_mips:
570061da546Spatrick     return "w27";
571061da546Spatrick   case dwarf_w28_mips:
572061da546Spatrick     return "w28";
573061da546Spatrick   case dwarf_w29_mips:
574061da546Spatrick     return "w29";
575061da546Spatrick   case dwarf_w30_mips:
576061da546Spatrick     return "w30";
577061da546Spatrick   case dwarf_w31_mips:
578061da546Spatrick     return "w31";
579061da546Spatrick   case dwarf_mcsr_mips:
580061da546Spatrick     return "mcsr";
581061da546Spatrick   case dwarf_mir_mips:
582061da546Spatrick     return "mir";
583061da546Spatrick   case dwarf_config5_mips:
584061da546Spatrick     return "config5";
585061da546Spatrick   }
586061da546Spatrick   return nullptr;
587061da546Spatrick }
588061da546Spatrick 
589*f6aab3d8Srobert std::optional<RegisterInfo>
GetRegisterInfo(RegisterKind reg_kind,uint32_t reg_num)590*f6aab3d8Srobert EmulateInstructionMIPS::GetRegisterInfo(RegisterKind reg_kind,
591*f6aab3d8Srobert                                         uint32_t reg_num) {
592061da546Spatrick   if (reg_kind == eRegisterKindGeneric) {
593061da546Spatrick     switch (reg_num) {
594061da546Spatrick     case LLDB_REGNUM_GENERIC_PC:
595061da546Spatrick       reg_kind = eRegisterKindDWARF;
596061da546Spatrick       reg_num = dwarf_pc_mips;
597061da546Spatrick       break;
598061da546Spatrick     case LLDB_REGNUM_GENERIC_SP:
599061da546Spatrick       reg_kind = eRegisterKindDWARF;
600061da546Spatrick       reg_num = dwarf_sp_mips;
601061da546Spatrick       break;
602061da546Spatrick     case LLDB_REGNUM_GENERIC_FP:
603061da546Spatrick       reg_kind = eRegisterKindDWARF;
604061da546Spatrick       reg_num = dwarf_r30_mips;
605061da546Spatrick       break;
606061da546Spatrick     case LLDB_REGNUM_GENERIC_RA:
607061da546Spatrick       reg_kind = eRegisterKindDWARF;
608061da546Spatrick       reg_num = dwarf_ra_mips;
609061da546Spatrick       break;
610061da546Spatrick     case LLDB_REGNUM_GENERIC_FLAGS:
611061da546Spatrick       reg_kind = eRegisterKindDWARF;
612061da546Spatrick       reg_num = dwarf_sr_mips;
613061da546Spatrick       break;
614061da546Spatrick     default:
615*f6aab3d8Srobert       return {};
616061da546Spatrick     }
617061da546Spatrick   }
618061da546Spatrick 
619061da546Spatrick   if (reg_kind == eRegisterKindDWARF) {
620*f6aab3d8Srobert     RegisterInfo reg_info;
621061da546Spatrick     ::memset(&reg_info, 0, sizeof(RegisterInfo));
622061da546Spatrick     ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
623061da546Spatrick 
624061da546Spatrick     if (reg_num == dwarf_sr_mips || reg_num == dwarf_fcsr_mips ||
625061da546Spatrick         reg_num == dwarf_fir_mips || reg_num == dwarf_mcsr_mips ||
626061da546Spatrick         reg_num == dwarf_mir_mips || reg_num == dwarf_config5_mips) {
627061da546Spatrick       reg_info.byte_size = 4;
628061da546Spatrick       reg_info.format = eFormatHex;
629061da546Spatrick       reg_info.encoding = eEncodingUint;
630061da546Spatrick     } else if ((int)reg_num >= dwarf_zero_mips &&
631061da546Spatrick                (int)reg_num <= dwarf_f31_mips) {
632061da546Spatrick       reg_info.byte_size = 4;
633061da546Spatrick       reg_info.format = eFormatHex;
634061da546Spatrick       reg_info.encoding = eEncodingUint;
635061da546Spatrick     } else if ((int)reg_num >= dwarf_w0_mips &&
636061da546Spatrick                (int)reg_num <= dwarf_w31_mips) {
637061da546Spatrick       reg_info.byte_size = 16;
638061da546Spatrick       reg_info.format = eFormatVectorOfUInt8;
639061da546Spatrick       reg_info.encoding = eEncodingVector;
640061da546Spatrick     } else {
641*f6aab3d8Srobert       return {};
642061da546Spatrick     }
643061da546Spatrick 
644061da546Spatrick     reg_info.name = GetRegisterName(reg_num, false);
645061da546Spatrick     reg_info.alt_name = GetRegisterName(reg_num, true);
646061da546Spatrick     reg_info.kinds[eRegisterKindDWARF] = reg_num;
647061da546Spatrick 
648061da546Spatrick     switch (reg_num) {
649061da546Spatrick     case dwarf_r30_mips:
650061da546Spatrick       reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
651061da546Spatrick       break;
652061da546Spatrick     case dwarf_ra_mips:
653061da546Spatrick       reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
654061da546Spatrick       break;
655061da546Spatrick     case dwarf_sp_mips:
656061da546Spatrick       reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
657061da546Spatrick       break;
658061da546Spatrick     case dwarf_pc_mips:
659061da546Spatrick       reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
660061da546Spatrick       break;
661061da546Spatrick     case dwarf_sr_mips:
662061da546Spatrick       reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
663061da546Spatrick       break;
664061da546Spatrick     default:
665061da546Spatrick       break;
666061da546Spatrick     }
667*f6aab3d8Srobert     return reg_info;
668061da546Spatrick   }
669*f6aab3d8Srobert   return {};
670061da546Spatrick }
671061da546Spatrick 
672061da546Spatrick EmulateInstructionMIPS::MipsOpcode *
GetOpcodeForInstruction(llvm::StringRef name)673*f6aab3d8Srobert EmulateInstructionMIPS::GetOpcodeForInstruction(llvm::StringRef name) {
674061da546Spatrick   static EmulateInstructionMIPS::MipsOpcode g_opcodes[] = {
675061da546Spatrick       // Prologue/Epilogue instructions
676061da546Spatrick       {"ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu,
677061da546Spatrick        "ADDIU rt, rs, immediate"},
678061da546Spatrick       {"SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt, offset(rs)"},
679061da546Spatrick       {"LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt, offset(base)"},
680061da546Spatrick       {"SUBU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "SUBU rd, rs, rt"},
681061da546Spatrick       {"ADDU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "ADDU rd, rs, rt"},
682061da546Spatrick       {"LUI", &EmulateInstructionMIPS::Emulate_LUI, "LUI rt, immediate"},
683061da546Spatrick 
684061da546Spatrick       // MicroMIPS Prologue/Epilogue instructions
685061da546Spatrick       {"ADDIUSP_MM", &EmulateInstructionMIPS::Emulate_ADDIUSP,
686061da546Spatrick        "ADDIU immediate"},
687061da546Spatrick       {"ADDIUS5_MM", &EmulateInstructionMIPS::Emulate_ADDIUS5,
688061da546Spatrick        "ADDIUS5 rd,immediate"},
689061da546Spatrick       {"SWSP_MM", &EmulateInstructionMIPS::Emulate_SWSP, "SWSP rt,offset(sp)"},
690061da546Spatrick       {"SWM16_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
691061da546Spatrick        "SWM16 reglist,offset(sp)"},
692061da546Spatrick       {"SWM32_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
693061da546Spatrick        "SWM32 reglist,offset(base)"},
694061da546Spatrick       {"SWP_MM", &EmulateInstructionMIPS::Emulate_SWM16_32,
695061da546Spatrick        "SWP rs1,offset(base)"},
696061da546Spatrick       {"LWSP_MM", &EmulateInstructionMIPS::Emulate_LWSP, "LWSP rt,offset(sp)"},
697061da546Spatrick       {"LWM16_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
698061da546Spatrick        "LWM16 reglist,offset(sp)"},
699061da546Spatrick       {"LWM32_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
700061da546Spatrick        "LWM32 reglist,offset(base)"},
701061da546Spatrick       {"LWP_MM", &EmulateInstructionMIPS::Emulate_LWM16_32,
702061da546Spatrick        "LWP rd,offset(base)"},
703061da546Spatrick       {"JRADDIUSP", &EmulateInstructionMIPS::Emulate_JRADDIUSP,
704061da546Spatrick        "JRADDIUSP immediate"},
705061da546Spatrick 
706061da546Spatrick       // Load/Store  instructions
707061da546Spatrick       /* Following list of emulated instructions are required by implementation
708061da546Spatrick          of hardware watchpoint
709061da546Spatrick          for MIPS in lldb. As we just need the address accessed by instructions,
710061da546Spatrick          we have generalised
711061da546Spatrick          all these instructions in 2 functions depending on their addressing
712061da546Spatrick          modes */
713061da546Spatrick 
714061da546Spatrick       {"LB", &EmulateInstructionMIPS::Emulate_LDST_Imm,
715061da546Spatrick        "LB    rt, offset(base)"},
716061da546Spatrick       {"LBE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
717061da546Spatrick        "LBE   rt, offset(base)"},
718061da546Spatrick       {"LBU", &EmulateInstructionMIPS::Emulate_LDST_Imm,
719061da546Spatrick        "LBU   rt, offset(base)"},
720061da546Spatrick       {"LBUE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
721061da546Spatrick        "LBUE  rt, offset(base)"},
722061da546Spatrick       {"LDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
723061da546Spatrick        "LDC1  ft, offset(base)"},
724061da546Spatrick       {"LD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
725061da546Spatrick        "LD    rt, offset(base)"},
726061da546Spatrick       {"LDL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
727061da546Spatrick        "LDL   rt, offset(base)"},
728061da546Spatrick       {"LDR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
729061da546Spatrick        "LDR   rt, offset(base)"},
730061da546Spatrick       {"LLD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
731061da546Spatrick        "LLD   rt, offset(base)"},
732061da546Spatrick       {"LDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
733061da546Spatrick        "LDC2  rt, offset(base)"},
734061da546Spatrick       {"LDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
735061da546Spatrick        "LDXC1 fd, index (base)"},
736061da546Spatrick       {"LH", &EmulateInstructionMIPS::Emulate_LDST_Imm,
737061da546Spatrick        "LH    rt, offset(base)"},
738061da546Spatrick       {"LHE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
739061da546Spatrick        "LHE   rt, offset(base)"},
740061da546Spatrick       {"LHU", &EmulateInstructionMIPS::Emulate_LDST_Imm,
741061da546Spatrick        "LHU   rt, offset(base)"},
742061da546Spatrick       {"LHUE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
743061da546Spatrick        "LHUE  rt, offset(base)"},
744061da546Spatrick       {"LL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
745061da546Spatrick        "LL    rt, offset(base)"},
746061da546Spatrick       {"LLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
747061da546Spatrick        "LLE   rt, offset(base)"},
748061da546Spatrick       {"LUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
749061da546Spatrick        "LUXC1 fd, index (base)"},
750061da546Spatrick       {"LW", &EmulateInstructionMIPS::Emulate_LDST_Imm,
751061da546Spatrick        "LW    rt, offset(base)"},
752061da546Spatrick       {"LWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
753061da546Spatrick        "LWC1  ft, offset(base)"},
754061da546Spatrick       {"LWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
755061da546Spatrick        "LWC2  rt, offset(base)"},
756061da546Spatrick       {"LWE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
757061da546Spatrick        "LWE   rt, offset(base)"},
758061da546Spatrick       {"LWL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
759061da546Spatrick        "LWL   rt, offset(base)"},
760061da546Spatrick       {"LWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
761061da546Spatrick        "LWLE  rt, offset(base)"},
762061da546Spatrick       {"LWR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
763061da546Spatrick        "LWR   rt, offset(base)"},
764061da546Spatrick       {"LWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
765061da546Spatrick        "LWRE  rt, offset(base)"},
766061da546Spatrick       {"LWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
767061da546Spatrick        "LWXC1 fd, index (base)"},
768061da546Spatrick       {"LLX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
769061da546Spatrick        "LLX   rt, offset(base)"},
770061da546Spatrick       {"LLXE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
771061da546Spatrick        "LLXE  rt, offset(base)"},
772061da546Spatrick       {"LLDX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
773061da546Spatrick        "LLDX  rt, offset(base)"},
774061da546Spatrick 
775061da546Spatrick       {"SB", &EmulateInstructionMIPS::Emulate_LDST_Imm,
776061da546Spatrick        "SB    rt, offset(base)"},
777061da546Spatrick       {"SBE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
778061da546Spatrick        "SBE   rt, offset(base)"},
779061da546Spatrick       {"SC", &EmulateInstructionMIPS::Emulate_LDST_Imm,
780061da546Spatrick        "SC    rt, offset(base)"},
781061da546Spatrick       {"SCE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
782061da546Spatrick        "SCE   rt, offset(base)"},
783061da546Spatrick       {"SCD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
784061da546Spatrick        "SCD   rt, offset(base)"},
785061da546Spatrick       {"SD", &EmulateInstructionMIPS::Emulate_LDST_Imm,
786061da546Spatrick        "SD    rt, offset(base)"},
787061da546Spatrick       {"SDL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
788061da546Spatrick        "SDL   rt, offset(base)"},
789061da546Spatrick       {"SDR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
790061da546Spatrick        "SDR   rt, offset(base)"},
791061da546Spatrick       {"SDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
792061da546Spatrick        "SDC1  ft, offset(base)"},
793061da546Spatrick       {"SDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
794061da546Spatrick        "SDC2  rt, offset(base)"},
795061da546Spatrick       {"SDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
796061da546Spatrick        "SDXC1 fs, index(base)"},
797061da546Spatrick       {"SH", &EmulateInstructionMIPS::Emulate_LDST_Imm,
798061da546Spatrick        "SH    rt, offset(base)"},
799061da546Spatrick       {"SHE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
800061da546Spatrick        "SHE   rt, offset(base)"},
801061da546Spatrick       {"SUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
802061da546Spatrick        "SUXC1 fs, index (base)"},
803061da546Spatrick       {"SWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm,
804061da546Spatrick        "SWC1  ft, offset(base)"},
805061da546Spatrick       {"SWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm,
806061da546Spatrick        "SWC2  rt, offset(base)"},
807061da546Spatrick       {"SWE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
808061da546Spatrick        "SWE   rt, offset(base)"},
809061da546Spatrick       {"SWL", &EmulateInstructionMIPS::Emulate_LDST_Imm,
810061da546Spatrick        "SWL   rt, offset(base)"},
811061da546Spatrick       {"SWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
812061da546Spatrick        "SWLE  rt, offset(base)"},
813061da546Spatrick       {"SWR", &EmulateInstructionMIPS::Emulate_LDST_Imm,
814061da546Spatrick        "SWR   rt, offset(base)"},
815061da546Spatrick       {"SWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
816061da546Spatrick        "SWRE  rt, offset(base)"},
817061da546Spatrick       {"SWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg,
818061da546Spatrick        "SWXC1 fs, index (base)"},
819061da546Spatrick       {"SCX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
820061da546Spatrick        "SCX   rt, offset(base)"},
821061da546Spatrick       {"SCXE", &EmulateInstructionMIPS::Emulate_LDST_Imm,
822061da546Spatrick        "SCXE  rt, offset(base)"},
823061da546Spatrick       {"SCDX", &EmulateInstructionMIPS::Emulate_LDST_Imm,
824061da546Spatrick        "SCDX  rt, offset(base)"},
825061da546Spatrick 
826061da546Spatrick       // MicroMIPS Load/Store instructions
827061da546Spatrick       {"LBU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
828061da546Spatrick        "LBU16 rt, decoded_offset(base)"},
829061da546Spatrick       {"LHU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
830061da546Spatrick        "LHU16 rt, left_shifted_offset(base)"},
831061da546Spatrick       {"LW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
832061da546Spatrick        "LW16  rt, left_shifted_offset(base)"},
833061da546Spatrick       {"LWGP_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
834061da546Spatrick        "LWGP  rt, left_shifted_offset(gp)"},
835061da546Spatrick       {"SH16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
836061da546Spatrick        "SH16  rt, left_shifted_offset(base)"},
837061da546Spatrick       {"SW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
838061da546Spatrick        "SW16  rt, left_shifted_offset(base)"},
839061da546Spatrick       {"SW_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
840061da546Spatrick        "SWSP  rt, left_shifted_offset(base)"},
841061da546Spatrick       {"SB16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm,
842061da546Spatrick        "SB16  rt, offset(base)"},
843061da546Spatrick 
844061da546Spatrick       // Branch instructions
845061da546Spatrick       {"BEQ", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQ rs,rt,offset"},
846061da546Spatrick       {"BNE", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNE rs,rt,offset"},
847061da546Spatrick       {"BEQL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQL rs,rt,offset"},
848061da546Spatrick       {"BNEL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNEL rs,rt,offset"},
849061da546Spatrick       {"BGEZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
850061da546Spatrick        "BGEZALL rt,offset"},
851061da546Spatrick       {"BAL", &EmulateInstructionMIPS::Emulate_BAL, "BAL offset"},
852061da546Spatrick       {"BGEZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
853061da546Spatrick        "BGEZAL rs,offset"},
854061da546Spatrick       {"BALC", &EmulateInstructionMIPS::Emulate_BALC, "BALC offset"},
855061da546Spatrick       {"BC", &EmulateInstructionMIPS::Emulate_BC, "BC offset"},
856061da546Spatrick       {"BGEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZ rs,offset"},
857061da546Spatrick       {"BLEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
858061da546Spatrick        "BLEZALC rs,offset"},
859061da546Spatrick       {"BGEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
860061da546Spatrick        "BGEZALC rs,offset"},
861061da546Spatrick       {"BLTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
862061da546Spatrick        "BLTZALC rs,offset"},
863061da546Spatrick       {"BGTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
864061da546Spatrick        "BGTZALC rs,offset"},
865061da546Spatrick       {"BEQZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
866061da546Spatrick        "BEQZALC rs,offset"},
867061da546Spatrick       {"BNEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,
868061da546Spatrick        "BNEZALC rs,offset"},
869061da546Spatrick       {"BEQC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
870061da546Spatrick        "BEQC rs,rt,offset"},
871061da546Spatrick       {"BNEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
872061da546Spatrick        "BNEC rs,rt,offset"},
873061da546Spatrick       {"BLTC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
874061da546Spatrick        "BLTC rs,rt,offset"},
875061da546Spatrick       {"BGEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
876061da546Spatrick        "BGEC rs,rt,offset"},
877061da546Spatrick       {"BLTUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
878061da546Spatrick        "BLTUC rs,rt,offset"},
879061da546Spatrick       {"BGEUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
880061da546Spatrick        "BGEUC rs,rt,offset"},
881061da546Spatrick       {"BLTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLTZC rt,offset"},
882061da546Spatrick       {"BLEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLEZC rt,offset"},
883061da546Spatrick       {"BGEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGEZC rt,offset"},
884061da546Spatrick       {"BGTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGTZC rt,offset"},
885061da546Spatrick       {"BEQZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BEQZC rt,offset"},
886061da546Spatrick       {"BNEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BNEZC rt,offset"},
887061da546Spatrick       {"BGEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZL rt,offset"},
888061da546Spatrick       {"BGTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZ rt,offset"},
889061da546Spatrick       {"BGTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZL rt,offset"},
890061da546Spatrick       {"BLEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZ rt,offset"},
891061da546Spatrick       {"BLEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZL rt,offset"},
892061da546Spatrick       {"BLTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZ rt,offset"},
893061da546Spatrick       {"BLTZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
894061da546Spatrick        "BLTZAL rt,offset"},
895061da546Spatrick       {"BLTZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link,
896061da546Spatrick        "BLTZALL rt,offset"},
897061da546Spatrick       {"BLTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZL rt,offset"},
898061da546Spatrick       {"BOVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
899061da546Spatrick        "BOVC rs,rt,offset"},
900061da546Spatrick       {"BNVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C,
901061da546Spatrick        "BNVC rs,rt,offset"},
902061da546Spatrick       {"J", &EmulateInstructionMIPS::Emulate_J, "J target"},
903061da546Spatrick       {"JAL", &EmulateInstructionMIPS::Emulate_JAL, "JAL target"},
904061da546Spatrick       {"JALX", &EmulateInstructionMIPS::Emulate_JAL, "JALX target"},
905061da546Spatrick       {"JALR", &EmulateInstructionMIPS::Emulate_JALR, "JALR target"},
906061da546Spatrick       {"JALR_HB", &EmulateInstructionMIPS::Emulate_JALR, "JALR.HB target"},
907061da546Spatrick       {"JIALC", &EmulateInstructionMIPS::Emulate_JIALC, "JIALC rt,offset"},
908061da546Spatrick       {"JIC", &EmulateInstructionMIPS::Emulate_JIC, "JIC rt,offset"},
909061da546Spatrick       {"JR", &EmulateInstructionMIPS::Emulate_JR, "JR target"},
910061da546Spatrick       {"JR_HB", &EmulateInstructionMIPS::Emulate_JR, "JR.HB target"},
911061da546Spatrick       {"BC1F", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1F cc, offset"},
912061da546Spatrick       {"BC1T", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1T cc, offset"},
913061da546Spatrick       {"BC1FL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1FL cc, offset"},
914061da546Spatrick       {"BC1TL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1TL cc, offset"},
915061da546Spatrick       {"BC1EQZ", &EmulateInstructionMIPS::Emulate_BC1EQZ, "BC1EQZ ft, offset"},
916061da546Spatrick       {"BC1NEZ", &EmulateInstructionMIPS::Emulate_BC1NEZ, "BC1NEZ ft, offset"},
917061da546Spatrick       {"BC1ANY2F", &EmulateInstructionMIPS::Emulate_3D_branch,
918061da546Spatrick        "BC1ANY2F cc, offset"},
919061da546Spatrick       {"BC1ANY2T", &EmulateInstructionMIPS::Emulate_3D_branch,
920061da546Spatrick        "BC1ANY2T cc, offset"},
921061da546Spatrick       {"BC1ANY4F", &EmulateInstructionMIPS::Emulate_3D_branch,
922061da546Spatrick        "BC1ANY4F cc, offset"},
923061da546Spatrick       {"BC1ANY4T", &EmulateInstructionMIPS::Emulate_3D_branch,
924061da546Spatrick        "BC1ANY4T cc, offset"},
925061da546Spatrick       {"BNZ_B", &EmulateInstructionMIPS::Emulate_BNZB, "BNZ.b wt,s16"},
926061da546Spatrick       {"BNZ_H", &EmulateInstructionMIPS::Emulate_BNZH, "BNZ.h wt,s16"},
927061da546Spatrick       {"BNZ_W", &EmulateInstructionMIPS::Emulate_BNZW, "BNZ.w wt,s16"},
928061da546Spatrick       {"BNZ_D", &EmulateInstructionMIPS::Emulate_BNZD, "BNZ.d wt,s16"},
929061da546Spatrick       {"BZ_B", &EmulateInstructionMIPS::Emulate_BZB, "BZ.b wt,s16"},
930061da546Spatrick       {"BZ_H", &EmulateInstructionMIPS::Emulate_BZH, "BZ.h wt,s16"},
931061da546Spatrick       {"BZ_W", &EmulateInstructionMIPS::Emulate_BZW, "BZ.w wt,s16"},
932061da546Spatrick       {"BZ_D", &EmulateInstructionMIPS::Emulate_BZD, "BZ.d wt,s16"},
933061da546Spatrick       {"BNZ_V", &EmulateInstructionMIPS::Emulate_BNZV, "BNZ.V wt,s16"},
934061da546Spatrick       {"BZ_V", &EmulateInstructionMIPS::Emulate_BZV, "BZ.V wt,s16"},
935061da546Spatrick 
936061da546Spatrick       // MicroMIPS Branch instructions
937061da546Spatrick       {"B16_MM", &EmulateInstructionMIPS::Emulate_B16_MM, "B16 offset"},
938061da546Spatrick       {"BEQZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
939061da546Spatrick        "BEQZ16 rs, offset"},
940061da546Spatrick       {"BNEZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
941061da546Spatrick        "BNEZ16 rs, offset"},
942061da546Spatrick       {"BEQZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
943061da546Spatrick        "BEQZC rs, offset"},
944061da546Spatrick       {"BNEZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
945061da546Spatrick        "BNEZC rs, offset"},
946061da546Spatrick       {"BGEZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
947061da546Spatrick        "BGEZALS rs, offset"},
948061da546Spatrick       {"BLTZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM,
949061da546Spatrick        "BLTZALS rs, offset"},
950061da546Spatrick       {"JALR16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALR16 rs"},
951061da546Spatrick       {"JALRS16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALRS16 rs"},
952061da546Spatrick       {"JR16_MM", &EmulateInstructionMIPS::Emulate_JR, "JR16 rs rs"},
953061da546Spatrick       {"JRC16_MM", &EmulateInstructionMIPS::Emulate_JR, "JRC16 rs rs"},
954061da546Spatrick       {"JALS_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALS target"},
955061da546Spatrick       {"JALX_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALX target"},
956061da546Spatrick       {"JALRS_MM", &EmulateInstructionMIPS::Emulate_JALRS, "JALRS rt, rs"},
957061da546Spatrick   };
958061da546Spatrick 
959*f6aab3d8Srobert   for (MipsOpcode &opcode : g_opcodes) {
960*f6aab3d8Srobert     if (name.equals_insensitive(opcode.op_name))
961*f6aab3d8Srobert       return &opcode;
962061da546Spatrick   }
963061da546Spatrick   return nullptr;
964061da546Spatrick }
965061da546Spatrick 
966061da546Spatrick uint32_t
GetSizeOfInstruction(lldb_private::DataExtractor & data,uint64_t inst_addr)967061da546Spatrick EmulateInstructionMIPS::GetSizeOfInstruction(lldb_private::DataExtractor &data,
968061da546Spatrick                                              uint64_t inst_addr) {
969061da546Spatrick   uint64_t next_inst_size = 0;
970061da546Spatrick   llvm::MCInst mc_insn;
971061da546Spatrick   llvm::MCDisassembler::DecodeStatus decode_status;
972061da546Spatrick   llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize());
973061da546Spatrick 
974061da546Spatrick   if (m_use_alt_disaasm)
975061da546Spatrick     decode_status = m_alt_disasm->getInstruction(
976061da546Spatrick         mc_insn, next_inst_size, raw_insn, inst_addr, llvm::nulls());
977061da546Spatrick   else
978061da546Spatrick     decode_status = m_disasm->getInstruction(mc_insn, next_inst_size, raw_insn,
979061da546Spatrick                                              inst_addr, llvm::nulls());
980061da546Spatrick 
981061da546Spatrick   if (decode_status != llvm::MCDisassembler::Success)
982061da546Spatrick     return false;
983061da546Spatrick 
984061da546Spatrick   return m_insn_info->get(mc_insn.getOpcode()).getSize();
985061da546Spatrick }
986061da546Spatrick 
SetInstruction(const Opcode & insn_opcode,const Address & inst_addr,Target * target)987061da546Spatrick bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode,
988061da546Spatrick                                             const Address &inst_addr,
989061da546Spatrick                                             Target *target) {
990061da546Spatrick   m_use_alt_disaasm = false;
991061da546Spatrick 
992061da546Spatrick   if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) {
993061da546Spatrick     if (inst_addr.GetAddressClass() == AddressClass::eCodeAlternateISA) {
994061da546Spatrick       Status error;
995061da546Spatrick       lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
996061da546Spatrick 
997061da546Spatrick       /*
998061da546Spatrick        * The address belongs to microMIPS function. To find the size of
999061da546Spatrick        * next instruction use microMIPS disassembler.
1000061da546Spatrick       */
1001061da546Spatrick       m_use_alt_disaasm = true;
1002061da546Spatrick 
1003061da546Spatrick       uint32_t current_inst_size = insn_opcode.GetByteSize();
1004061da546Spatrick       uint8_t buf[sizeof(uint32_t)];
1005061da546Spatrick       uint64_t next_inst_addr = (m_addr & (~1ull)) + current_inst_size;
1006061da546Spatrick       Address next_addr(next_inst_addr);
1007061da546Spatrick 
1008061da546Spatrick       const size_t bytes_read =
1009061da546Spatrick           target->ReadMemory(next_addr, /* Address of next instruction */
1010be691f3bSpatrick                              buf, sizeof(uint32_t), error,
1011be691f3bSpatrick                              false,  /* force_live_memory */
1012be691f3bSpatrick                              &load_addr);
1013061da546Spatrick 
1014061da546Spatrick       if (bytes_read == 0)
1015061da546Spatrick         return true;
1016061da546Spatrick 
1017061da546Spatrick       DataExtractor data(buf, sizeof(uint32_t), GetByteOrder(),
1018061da546Spatrick                          GetAddressByteSize());
1019061da546Spatrick       m_next_inst_size = GetSizeOfInstruction(data, next_inst_addr);
1020061da546Spatrick       return true;
1021061da546Spatrick     } else {
1022061da546Spatrick       /*
1023061da546Spatrick        * If the address class is not AddressClass::eCodeAlternateISA then
1024061da546Spatrick        * the function is not microMIPS. In this case instruction size is
1025061da546Spatrick        * always 4 bytes.
1026061da546Spatrick       */
1027061da546Spatrick       m_next_inst_size = 4;
1028061da546Spatrick       return true;
1029061da546Spatrick     }
1030061da546Spatrick   }
1031061da546Spatrick   return false;
1032061da546Spatrick }
1033061da546Spatrick 
ReadInstruction()1034061da546Spatrick bool EmulateInstructionMIPS::ReadInstruction() {
1035061da546Spatrick   bool success = false;
1036061da546Spatrick   m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
1037061da546Spatrick                                 LLDB_INVALID_ADDRESS, &success);
1038061da546Spatrick   if (success) {
1039061da546Spatrick     Context read_inst_context;
1040061da546Spatrick     read_inst_context.type = eContextReadOpcode;
1041061da546Spatrick     read_inst_context.SetNoArgs();
1042061da546Spatrick     m_opcode.SetOpcode32(
1043061da546Spatrick         ReadMemoryUnsigned(read_inst_context, m_addr, 4, 0, &success),
1044061da546Spatrick         GetByteOrder());
1045061da546Spatrick   }
1046061da546Spatrick   if (!success)
1047061da546Spatrick     m_addr = LLDB_INVALID_ADDRESS;
1048061da546Spatrick   return success;
1049061da546Spatrick }
1050061da546Spatrick 
EvaluateInstruction(uint32_t evaluate_options)1051061da546Spatrick bool EmulateInstructionMIPS::EvaluateInstruction(uint32_t evaluate_options) {
1052061da546Spatrick   bool success = false;
1053061da546Spatrick   llvm::MCInst mc_insn;
1054061da546Spatrick   uint64_t insn_size;
1055061da546Spatrick   DataExtractor data;
1056061da546Spatrick 
1057061da546Spatrick   /* Keep the complexity of the decode logic with the llvm::MCDisassembler
1058061da546Spatrick    * class. */
1059061da546Spatrick   if (m_opcode.GetData(data)) {
1060061da546Spatrick     llvm::MCDisassembler::DecodeStatus decode_status;
1061061da546Spatrick     llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize());
1062061da546Spatrick     if (m_use_alt_disaasm)
1063061da546Spatrick       decode_status = m_alt_disasm->getInstruction(mc_insn, insn_size, raw_insn,
1064061da546Spatrick                                                    m_addr, llvm::nulls());
1065061da546Spatrick     else
1066061da546Spatrick       decode_status = m_disasm->getInstruction(mc_insn, insn_size, raw_insn,
1067061da546Spatrick                                                m_addr, llvm::nulls());
1068061da546Spatrick 
1069061da546Spatrick     if (decode_status != llvm::MCDisassembler::Success)
1070061da546Spatrick       return false;
1071061da546Spatrick   }
1072061da546Spatrick 
1073061da546Spatrick   /*
1074061da546Spatrick    * mc_insn.getOpcode() returns decoded opcode. However to make use
1075061da546Spatrick    * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc".
1076061da546Spatrick   */
1077061da546Spatrick   const char *op_name = m_insn_info->getName(mc_insn.getOpcode()).data();
1078061da546Spatrick 
1079061da546Spatrick   if (op_name == nullptr)
1080061da546Spatrick     return false;
1081061da546Spatrick 
1082061da546Spatrick   /*
1083061da546Spatrick    * Decoding has been done already. Just get the call-back function
1084061da546Spatrick    * and emulate the instruction.
1085061da546Spatrick   */
1086061da546Spatrick   MipsOpcode *opcode_data = GetOpcodeForInstruction(op_name);
1087061da546Spatrick 
1088061da546Spatrick   if (opcode_data == nullptr)
1089061da546Spatrick     return false;
1090061da546Spatrick 
1091061da546Spatrick   uint64_t old_pc = 0, new_pc = 0;
1092061da546Spatrick   const bool auto_advance_pc =
1093061da546Spatrick       evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
1094061da546Spatrick 
1095061da546Spatrick   if (auto_advance_pc) {
1096061da546Spatrick     old_pc =
1097061da546Spatrick         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1098061da546Spatrick     if (!success)
1099061da546Spatrick       return false;
1100061da546Spatrick   }
1101061da546Spatrick 
1102061da546Spatrick   /* emulate instruction */
1103061da546Spatrick   success = (this->*opcode_data->callback)(mc_insn);
1104061da546Spatrick   if (!success)
1105061da546Spatrick     return false;
1106061da546Spatrick 
1107061da546Spatrick   if (auto_advance_pc) {
1108061da546Spatrick     new_pc =
1109061da546Spatrick         ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1110061da546Spatrick     if (!success)
1111061da546Spatrick       return false;
1112061da546Spatrick 
1113061da546Spatrick     /* If we haven't changed the PC, change it here */
1114061da546Spatrick     if (old_pc == new_pc) {
1115061da546Spatrick       new_pc += 4;
1116061da546Spatrick       Context context;
1117061da546Spatrick       if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
1118061da546Spatrick                                  new_pc))
1119061da546Spatrick         return false;
1120061da546Spatrick     }
1121061da546Spatrick   }
1122061da546Spatrick 
1123061da546Spatrick   return true;
1124061da546Spatrick }
1125061da546Spatrick 
CreateFunctionEntryUnwind(UnwindPlan & unwind_plan)1126061da546Spatrick bool EmulateInstructionMIPS::CreateFunctionEntryUnwind(
1127061da546Spatrick     UnwindPlan &unwind_plan) {
1128061da546Spatrick   unwind_plan.Clear();
1129061da546Spatrick   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
1130061da546Spatrick 
1131061da546Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row);
1132061da546Spatrick   const bool can_replace = false;
1133061da546Spatrick 
1134061da546Spatrick   // Our previous Call Frame Address is the stack pointer
1135061da546Spatrick   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp_mips, 0);
1136061da546Spatrick 
1137061da546Spatrick   // Our previous PC is in the RA
1138061da546Spatrick   row->SetRegisterLocationToRegister(dwarf_pc_mips, dwarf_ra_mips, can_replace);
1139061da546Spatrick 
1140061da546Spatrick   unwind_plan.AppendRow(row);
1141061da546Spatrick 
1142061da546Spatrick   // All other registers are the same.
1143061da546Spatrick   unwind_plan.SetSourceName("EmulateInstructionMIPS");
1144061da546Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1145061da546Spatrick   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
1146061da546Spatrick   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1147061da546Spatrick   unwind_plan.SetReturnAddressRegister(dwarf_ra_mips);
1148061da546Spatrick 
1149061da546Spatrick   return true;
1150061da546Spatrick }
1151061da546Spatrick 
nonvolatile_reg_p(uint32_t regnum)1152061da546Spatrick bool EmulateInstructionMIPS::nonvolatile_reg_p(uint32_t regnum) {
1153061da546Spatrick   switch (regnum) {
1154061da546Spatrick   case dwarf_r16_mips:
1155061da546Spatrick   case dwarf_r17_mips:
1156061da546Spatrick   case dwarf_r18_mips:
1157061da546Spatrick   case dwarf_r19_mips:
1158061da546Spatrick   case dwarf_r20_mips:
1159061da546Spatrick   case dwarf_r21_mips:
1160061da546Spatrick   case dwarf_r22_mips:
1161061da546Spatrick   case dwarf_r23_mips:
1162061da546Spatrick   case dwarf_gp_mips:
1163061da546Spatrick   case dwarf_sp_mips:
1164061da546Spatrick   case dwarf_r30_mips:
1165061da546Spatrick   case dwarf_ra_mips:
1166061da546Spatrick     return true;
1167061da546Spatrick   default:
1168061da546Spatrick     return false;
1169061da546Spatrick   }
1170061da546Spatrick   return false;
1171061da546Spatrick }
1172061da546Spatrick 
Emulate_ADDiu(llvm::MCInst & insn)1173061da546Spatrick bool EmulateInstructionMIPS::Emulate_ADDiu(llvm::MCInst &insn) {
1174061da546Spatrick   // ADDIU rt, rs, immediate
1175061da546Spatrick   // GPR[rt] <- GPR[rs] + sign_extend(immediate)
1176061da546Spatrick 
1177061da546Spatrick   uint8_t dst, src;
1178061da546Spatrick   bool success = false;
1179061da546Spatrick   const uint32_t imm16 = insn.getOperand(2).getImm();
1180061da546Spatrick   int64_t imm = SignedBits(imm16, 15, 0);
1181061da546Spatrick 
1182061da546Spatrick   dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1183061da546Spatrick   src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1184061da546Spatrick 
1185061da546Spatrick   // If immediate value is greater then 2^16 - 1 then clang generate LUI,
1186061da546Spatrick   // ADDIU, SUBU instructions in prolog. Example lui    $1, 0x2 addiu $1, $1,
1187061da546Spatrick   // -0x5920 subu  $sp, $sp, $1 In this case, ADDIU dst and src will be same
1188061da546Spatrick   // and not equal to sp
1189061da546Spatrick   if (dst == src) {
1190061da546Spatrick     Context context;
1191061da546Spatrick 
1192061da546Spatrick     /* read <src> register */
1193061da546Spatrick     const int64_t src_opd_val = ReadRegisterUnsigned(
1194061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
1195061da546Spatrick     if (!success)
1196061da546Spatrick       return false;
1197061da546Spatrick 
1198061da546Spatrick     /* Check if this is daddiu sp, sp, imm16 */
1199061da546Spatrick     if (dst == dwarf_sp_mips) {
1200061da546Spatrick       uint64_t result = src_opd_val + imm;
1201*f6aab3d8Srobert       std::optional<RegisterInfo> reg_info_sp =
1202*f6aab3d8Srobert           GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1203*f6aab3d8Srobert       if (reg_info_sp)
1204*f6aab3d8Srobert         context.SetRegisterPlusOffset(*reg_info_sp, imm);
1205061da546Spatrick 
1206061da546Spatrick       /* We are allocating bytes on stack */
1207061da546Spatrick       context.type = eContextAdjustStackPointer;
1208061da546Spatrick 
1209061da546Spatrick       WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
1210061da546Spatrick       return true;
1211061da546Spatrick     }
1212061da546Spatrick 
1213061da546Spatrick     imm += src_opd_val;
1214061da546Spatrick     context.SetImmediateSigned(imm);
1215061da546Spatrick     context.type = eContextImmediate;
1216061da546Spatrick 
1217061da546Spatrick     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
1218061da546Spatrick                                dwarf_zero_mips + dst, imm))
1219061da546Spatrick       return false;
1220061da546Spatrick   }
1221061da546Spatrick 
1222061da546Spatrick   return true;
1223061da546Spatrick }
1224061da546Spatrick 
Emulate_SW(llvm::MCInst & insn)1225061da546Spatrick bool EmulateInstructionMIPS::Emulate_SW(llvm::MCInst &insn) {
1226061da546Spatrick   bool success = false;
1227061da546Spatrick   uint32_t imm16 = insn.getOperand(2).getImm();
1228061da546Spatrick   uint32_t imm = SignedBits(imm16, 15, 0);
1229061da546Spatrick   uint32_t src, base;
1230061da546Spatrick   int32_t address;
1231061da546Spatrick   Context bad_vaddr_context;
1232061da546Spatrick 
1233061da546Spatrick   src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1234061da546Spatrick   base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1235061da546Spatrick 
1236*f6aab3d8Srobert   std::optional<RegisterInfo> reg_info_base =
1237*f6aab3d8Srobert       GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1238*f6aab3d8Srobert   if (!reg_info_base)
1239061da546Spatrick     return false;
1240061da546Spatrick 
1241061da546Spatrick   /* read base register */
1242061da546Spatrick   address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1243061da546Spatrick                                           dwarf_zero_mips + base, 0, &success);
1244061da546Spatrick   if (!success)
1245061da546Spatrick     return false;
1246061da546Spatrick 
1247061da546Spatrick   /* destination address */
1248061da546Spatrick   address = address + imm;
1249061da546Spatrick 
1250061da546Spatrick   /* Set the bad_vaddr register with base address used in the instruction */
1251061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
1252061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
1253061da546Spatrick                         address);
1254061da546Spatrick 
1255061da546Spatrick   /* We look for sp based non-volatile register stores */
1256061da546Spatrick   if (nonvolatile_reg_p(src)) {
1257*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_src =
1258*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1259*f6aab3d8Srobert     if (!reg_info_src)
1260061da546Spatrick       return false;
1261061da546Spatrick 
1262061da546Spatrick     Context context;
1263061da546Spatrick     context.type = eContextPushRegisterOnStack;
1264*f6aab3d8Srobert     context.SetRegisterToRegisterPlusOffset(*reg_info_src, *reg_info_base, 0);
1265061da546Spatrick 
1266061da546Spatrick     uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
1267061da546Spatrick     Status error;
1268061da546Spatrick 
1269*f6aab3d8Srobert     std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1270*f6aab3d8Srobert     if (!data_src)
1271061da546Spatrick       return false;
1272061da546Spatrick 
1273*f6aab3d8Srobert     if (data_src->GetAsMemoryData(*reg_info_src, buffer,
1274*f6aab3d8Srobert                                   reg_info_src->byte_size, eByteOrderLittle,
1275*f6aab3d8Srobert                                   error) == 0)
1276061da546Spatrick       return false;
1277061da546Spatrick 
1278*f6aab3d8Srobert     if (!WriteMemory(context, address, buffer, reg_info_src->byte_size))
1279061da546Spatrick       return false;
1280061da546Spatrick 
1281061da546Spatrick     return true;
1282061da546Spatrick   }
1283061da546Spatrick 
1284061da546Spatrick   return false;
1285061da546Spatrick }
1286061da546Spatrick 
Emulate_LW(llvm::MCInst & insn)1287061da546Spatrick bool EmulateInstructionMIPS::Emulate_LW(llvm::MCInst &insn) {
1288061da546Spatrick   bool success = false;
1289061da546Spatrick   uint32_t src, base;
1290061da546Spatrick   int32_t imm, address;
1291061da546Spatrick   Context bad_vaddr_context;
1292061da546Spatrick 
1293061da546Spatrick   src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1294061da546Spatrick   base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1295061da546Spatrick   imm = insn.getOperand(2).getImm();
1296061da546Spatrick 
1297*f6aab3d8Srobert   if (GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
1298061da546Spatrick     return false;
1299061da546Spatrick 
1300061da546Spatrick   /* read base register */
1301061da546Spatrick   address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1302061da546Spatrick                                           dwarf_zero_mips + base, 0, &success);
1303061da546Spatrick   if (!success)
1304061da546Spatrick     return false;
1305061da546Spatrick 
1306061da546Spatrick   /* destination address */
1307061da546Spatrick   address = address + imm;
1308061da546Spatrick 
1309061da546Spatrick   /* Set the bad_vaddr register with base address used in the instruction */
1310061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
1311061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
1312061da546Spatrick                         address);
1313061da546Spatrick 
1314061da546Spatrick   if (nonvolatile_reg_p(src)) {
1315061da546Spatrick     RegisterValue data_src;
1316*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_src =
1317*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1318*f6aab3d8Srobert     if (!reg_info_src)
1319061da546Spatrick       return false;
1320061da546Spatrick 
1321061da546Spatrick     Context context;
1322061da546Spatrick     context.type = eContextPopRegisterOffStack;
1323061da546Spatrick     context.SetAddress(address);
1324061da546Spatrick 
1325*f6aab3d8Srobert     return WriteRegister(context, *reg_info_src, data_src);
1326061da546Spatrick   }
1327061da546Spatrick 
1328061da546Spatrick   return false;
1329061da546Spatrick }
1330061da546Spatrick 
Emulate_SUBU_ADDU(llvm::MCInst & insn)1331061da546Spatrick bool EmulateInstructionMIPS::Emulate_SUBU_ADDU(llvm::MCInst &insn) {
1332061da546Spatrick   // SUBU sp, <src>, <rt>
1333061da546Spatrick   // ADDU sp, <src>, <rt>
1334061da546Spatrick   // ADDU dst, sp, <rt>
1335061da546Spatrick 
1336061da546Spatrick   bool success = false;
1337061da546Spatrick   uint64_t result;
1338061da546Spatrick   uint8_t src, dst, rt;
1339*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
1340061da546Spatrick 
1341061da546Spatrick   dst = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1342061da546Spatrick   src = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1343061da546Spatrick 
1344061da546Spatrick   /* Check if sp is destination register */
1345061da546Spatrick   if (dst == dwarf_sp_mips) {
1346061da546Spatrick     rt = m_reg_info->getEncodingValue(insn.getOperand(2).getReg());
1347061da546Spatrick 
1348061da546Spatrick     /* read <src> register */
1349061da546Spatrick     uint64_t src_opd_val = ReadRegisterUnsigned(
1350061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
1351061da546Spatrick     if (!success)
1352061da546Spatrick       return false;
1353061da546Spatrick 
1354061da546Spatrick     /* read <rt > register */
1355061da546Spatrick     uint64_t rt_opd_val = ReadRegisterUnsigned(
1356061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
1357061da546Spatrick     if (!success)
1358061da546Spatrick       return false;
1359061da546Spatrick 
1360*f6aab3d8Srobert     if (op_name.equals_insensitive("SUBU"))
1361061da546Spatrick       result = src_opd_val - rt_opd_val;
1362061da546Spatrick     else
1363061da546Spatrick       result = src_opd_val + rt_opd_val;
1364061da546Spatrick 
1365061da546Spatrick     Context context;
1366*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_sp =
1367*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1368*f6aab3d8Srobert     if (reg_info_sp)
1369*f6aab3d8Srobert       context.SetRegisterPlusOffset(*reg_info_sp, rt_opd_val);
1370061da546Spatrick 
1371061da546Spatrick     /* We are allocating bytes on stack */
1372061da546Spatrick     context.type = eContextAdjustStackPointer;
1373061da546Spatrick 
1374061da546Spatrick     WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
1375061da546Spatrick 
1376061da546Spatrick     return true;
1377061da546Spatrick   } else if (src == dwarf_sp_mips) {
1378061da546Spatrick     rt = m_reg_info->getEncodingValue(insn.getOperand(2).getReg());
1379061da546Spatrick 
1380061da546Spatrick     /* read <src> register */
1381061da546Spatrick     uint64_t src_opd_val = ReadRegisterUnsigned(
1382061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success);
1383061da546Spatrick     if (!success)
1384061da546Spatrick       return false;
1385061da546Spatrick 
1386061da546Spatrick     /* read <rt> register */
1387061da546Spatrick     uint64_t rt_opd_val = ReadRegisterUnsigned(
1388061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success);
1389061da546Spatrick     if (!success)
1390061da546Spatrick       return false;
1391061da546Spatrick 
1392061da546Spatrick     Context context;
1393061da546Spatrick 
1394*f6aab3d8Srobert     if (op_name.equals_insensitive("SUBU"))
1395061da546Spatrick       result = src_opd_val - rt_opd_val;
1396061da546Spatrick     else
1397061da546Spatrick       result = src_opd_val + rt_opd_val;
1398061da546Spatrick 
1399061da546Spatrick     context.SetImmediateSigned(result);
1400061da546Spatrick     context.type = eContextImmediate;
1401061da546Spatrick 
1402061da546Spatrick     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF,
1403061da546Spatrick                                dwarf_zero_mips + dst, result))
1404061da546Spatrick       return false;
1405061da546Spatrick   }
1406061da546Spatrick 
1407061da546Spatrick   return true;
1408061da546Spatrick }
1409061da546Spatrick 
Emulate_LUI(llvm::MCInst & insn)1410061da546Spatrick bool EmulateInstructionMIPS::Emulate_LUI(llvm::MCInst &insn) {
1411061da546Spatrick   // LUI rt, immediate
1412061da546Spatrick   // GPR[rt] <- sign_extend(immediate << 16)
1413061da546Spatrick 
1414061da546Spatrick   const uint32_t imm32 = insn.getOperand(1).getImm() << 16;
1415061da546Spatrick   int64_t imm = SignedBits(imm32, 31, 0);
1416061da546Spatrick   uint8_t rt;
1417061da546Spatrick   Context context;
1418061da546Spatrick 
1419061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1420061da546Spatrick   context.SetImmediateSigned(imm);
1421061da546Spatrick   context.type = eContextImmediate;
1422061da546Spatrick 
1423061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF,
1424061da546Spatrick                                dwarf_zero_mips + rt, imm);
1425061da546Spatrick }
1426061da546Spatrick 
Emulate_ADDIUSP(llvm::MCInst & insn)1427061da546Spatrick bool EmulateInstructionMIPS::Emulate_ADDIUSP(llvm::MCInst &insn) {
1428061da546Spatrick   bool success = false;
1429061da546Spatrick   const uint32_t imm9 = insn.getOperand(0).getImm();
1430061da546Spatrick   uint64_t result;
1431061da546Spatrick 
1432061da546Spatrick   // This instruction operates implicitly on stack pointer, so read <sp>
1433061da546Spatrick   // register.
1434061da546Spatrick   uint64_t src_opd_val =
1435061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_sp_mips, 0, &success);
1436061da546Spatrick   if (!success)
1437061da546Spatrick     return false;
1438061da546Spatrick 
1439061da546Spatrick   result = src_opd_val + imm9;
1440061da546Spatrick 
1441061da546Spatrick   Context context;
1442*f6aab3d8Srobert   std::optional<RegisterInfo> reg_info_sp =
1443*f6aab3d8Srobert       GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1444*f6aab3d8Srobert   if (reg_info_sp)
1445*f6aab3d8Srobert     context.SetRegisterPlusOffset(*reg_info_sp, imm9);
1446061da546Spatrick 
1447061da546Spatrick   // We are adjusting the stack.
1448061da546Spatrick   context.type = eContextAdjustStackPointer;
1449061da546Spatrick 
1450061da546Spatrick   WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
1451061da546Spatrick   return true;
1452061da546Spatrick }
1453061da546Spatrick 
Emulate_ADDIUS5(llvm::MCInst & insn)1454061da546Spatrick bool EmulateInstructionMIPS::Emulate_ADDIUS5(llvm::MCInst &insn) {
1455061da546Spatrick   bool success = false;
1456061da546Spatrick   uint32_t base;
1457061da546Spatrick   const uint32_t imm4 = insn.getOperand(2).getImm();
1458061da546Spatrick   uint64_t result;
1459061da546Spatrick 
1460061da546Spatrick   // The source and destination register is same for this instruction.
1461061da546Spatrick   base = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1462061da546Spatrick 
1463061da546Spatrick   // We are looking for stack adjustment only
1464061da546Spatrick   if (base == dwarf_sp_mips) {
1465061da546Spatrick     // Read stack pointer register
1466061da546Spatrick     uint64_t src_opd_val = ReadRegisterUnsigned(
1467061da546Spatrick         eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
1468061da546Spatrick     if (!success)
1469061da546Spatrick       return false;
1470061da546Spatrick 
1471061da546Spatrick     result = src_opd_val + imm4;
1472061da546Spatrick 
1473061da546Spatrick     Context context;
1474*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_sp =
1475*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1476*f6aab3d8Srobert     if (reg_info_sp)
1477*f6aab3d8Srobert       context.SetRegisterPlusOffset(*reg_info_sp, imm4);
1478061da546Spatrick 
1479061da546Spatrick     // We are adjusting the stack.
1480061da546Spatrick     context.type = eContextAdjustStackPointer;
1481061da546Spatrick 
1482061da546Spatrick     WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips, result);
1483061da546Spatrick   }
1484061da546Spatrick 
1485061da546Spatrick   return true;
1486061da546Spatrick }
1487061da546Spatrick 
Emulate_SWSP(llvm::MCInst & insn)1488061da546Spatrick bool EmulateInstructionMIPS::Emulate_SWSP(llvm::MCInst &insn) {
1489061da546Spatrick   bool success = false;
1490061da546Spatrick   uint32_t imm5 = insn.getOperand(2).getImm();
1491061da546Spatrick   uint32_t src, base;
1492061da546Spatrick   Context bad_vaddr_context;
1493061da546Spatrick   uint32_t address;
1494061da546Spatrick 
1495061da546Spatrick   src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1496061da546Spatrick   base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1497061da546Spatrick 
1498*f6aab3d8Srobert   std::optional<RegisterInfo> reg_info_base =
1499*f6aab3d8Srobert       GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1500*f6aab3d8Srobert   if (!reg_info_base)
1501061da546Spatrick     return false;
1502061da546Spatrick 
1503061da546Spatrick   // read base register
1504061da546Spatrick   address = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + base, 0,
1505061da546Spatrick                                  &success);
1506061da546Spatrick   if (!success)
1507061da546Spatrick     return false;
1508061da546Spatrick 
1509061da546Spatrick   // destination address
1510061da546Spatrick   address = address + imm5;
1511061da546Spatrick 
1512061da546Spatrick   // We use bad_vaddr_context to store base address which is used by H/W
1513061da546Spatrick   // watchpoint Set the bad_vaddr register with base address used in the
1514061da546Spatrick   // instruction
1515061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
1516061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
1517061da546Spatrick                         address);
1518061da546Spatrick 
1519061da546Spatrick   // We look for sp based non-volatile register stores.
1520061da546Spatrick   if (base == dwarf_sp_mips && nonvolatile_reg_p(src)) {
1521061da546Spatrick     RegisterInfo reg_info_src = {};
1522061da546Spatrick     Context context;
1523061da546Spatrick     context.type = eContextPushRegisterOnStack;
1524*f6aab3d8Srobert     context.SetRegisterToRegisterPlusOffset(reg_info_src, *reg_info_base, 0);
1525061da546Spatrick 
1526061da546Spatrick     uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
1527061da546Spatrick     Status error;
1528061da546Spatrick 
1529*f6aab3d8Srobert     std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1530*f6aab3d8Srobert     if (!data_src)
1531061da546Spatrick       return false;
1532061da546Spatrick 
1533*f6aab3d8Srobert     if (data_src->GetAsMemoryData(reg_info_src, buffer, reg_info_src.byte_size,
1534061da546Spatrick                                   eByteOrderLittle, error) == 0)
1535061da546Spatrick       return false;
1536061da546Spatrick 
1537061da546Spatrick     if (!WriteMemory(context, address, buffer, reg_info_src.byte_size))
1538061da546Spatrick       return false;
1539061da546Spatrick 
1540061da546Spatrick     return true;
1541061da546Spatrick   }
1542061da546Spatrick 
1543061da546Spatrick   return false;
1544061da546Spatrick }
1545061da546Spatrick 
1546061da546Spatrick /* Emulate SWM16,SWM32 and SWP instruction.
1547061da546Spatrick 
1548061da546Spatrick    SWM16 always has stack pointer as a base register (but it is still available
1549061da546Spatrick    in MCInst as an operand).
1550061da546Spatrick    SWM32 and SWP can have base register other than stack pointer.
1551061da546Spatrick */
Emulate_SWM16_32(llvm::MCInst & insn)1552061da546Spatrick bool EmulateInstructionMIPS::Emulate_SWM16_32(llvm::MCInst &insn) {
1553061da546Spatrick   bool success = false;
1554061da546Spatrick   uint32_t src, base;
1555061da546Spatrick   uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on
1556061da546Spatrick                                                  // no of regs to store.
1557061da546Spatrick 
1558061da546Spatrick   // Base register is second last operand of the instruction.
1559061da546Spatrick   base =
1560061da546Spatrick       m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
1561061da546Spatrick 
1562061da546Spatrick   // We are looking for sp based stores so if base is not a stack pointer then
1563061da546Spatrick   // don't proceed.
1564061da546Spatrick   if (base != dwarf_sp_mips)
1565061da546Spatrick     return false;
1566061da546Spatrick 
1567061da546Spatrick   // offset is always the last operand.
1568061da546Spatrick   uint32_t offset = insn.getOperand(num_operands - 1).getImm();
1569061da546Spatrick 
1570*f6aab3d8Srobert   std::optional<RegisterInfo> reg_info_base =
1571*f6aab3d8Srobert       GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base);
1572*f6aab3d8Srobert   if (!reg_info_base)
1573061da546Spatrick     return false;
1574061da546Spatrick 
1575061da546Spatrick   // read SP
1576061da546Spatrick   uint32_t base_address = ReadRegisterUnsigned(
1577061da546Spatrick       eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
1578061da546Spatrick   if (!success)
1579061da546Spatrick     return false;
1580061da546Spatrick 
1581061da546Spatrick   // Resulting base addrss
1582061da546Spatrick   base_address = base_address + offset;
1583061da546Spatrick 
1584061da546Spatrick   // Total no of registers to be stored are num_operands-2.
1585061da546Spatrick   for (uint32_t i = 0; i < num_operands - 2; i++) {
1586061da546Spatrick     // Get the register number to be stored.
1587061da546Spatrick     src = m_reg_info->getEncodingValue(insn.getOperand(i).getReg());
1588061da546Spatrick 
1589061da546Spatrick     /*
1590061da546Spatrick         Record only non-volatile stores.
1591061da546Spatrick         This check is required for SWP instruction because source operand could
1592061da546Spatrick        be any register.
1593061da546Spatrick         SWM16 and SWM32 instruction always has saved registers as source
1594061da546Spatrick        operands.
1595061da546Spatrick     */
1596061da546Spatrick     if (!nonvolatile_reg_p(src))
1597061da546Spatrick       return false;
1598061da546Spatrick 
1599*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_src =
1600*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1601*f6aab3d8Srobert     if (!reg_info_src)
1602061da546Spatrick       return false;
1603061da546Spatrick 
1604061da546Spatrick     Context context;
1605061da546Spatrick     context.type = eContextPushRegisterOnStack;
1606*f6aab3d8Srobert     context.SetRegisterToRegisterPlusOffset(*reg_info_src, *reg_info_base, 0);
1607061da546Spatrick 
1608061da546Spatrick     uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
1609061da546Spatrick     Status error;
1610061da546Spatrick 
1611*f6aab3d8Srobert     std::optional<RegisterValue> data_src = ReadRegister(*reg_info_base);
1612*f6aab3d8Srobert     if (!data_src)
1613061da546Spatrick       return false;
1614061da546Spatrick 
1615*f6aab3d8Srobert     if (data_src->GetAsMemoryData(*reg_info_src, buffer,
1616*f6aab3d8Srobert                                   reg_info_src->byte_size, eByteOrderLittle,
1617*f6aab3d8Srobert                                   error) == 0)
1618061da546Spatrick       return false;
1619061da546Spatrick 
1620*f6aab3d8Srobert     if (!WriteMemory(context, base_address, buffer, reg_info_src->byte_size))
1621061da546Spatrick       return false;
1622061da546Spatrick 
1623061da546Spatrick     // Stack address for next register
1624*f6aab3d8Srobert     base_address = base_address + reg_info_src->byte_size;
1625061da546Spatrick   }
1626061da546Spatrick   return true;
1627061da546Spatrick }
1628061da546Spatrick 
Emulate_LWSP(llvm::MCInst & insn)1629061da546Spatrick bool EmulateInstructionMIPS::Emulate_LWSP(llvm::MCInst &insn) {
1630061da546Spatrick   bool success = false;
1631061da546Spatrick   uint32_t src = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1632061da546Spatrick   uint32_t base = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1633061da546Spatrick   uint32_t imm5 = insn.getOperand(2).getImm();
1634061da546Spatrick   Context bad_vaddr_context;
1635061da546Spatrick 
1636*f6aab3d8Srobert   if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
1637061da546Spatrick     return false;
1638061da546Spatrick 
1639061da546Spatrick   // read base register
1640061da546Spatrick   uint32_t base_address = ReadRegisterUnsigned(
1641061da546Spatrick       eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
1642061da546Spatrick   if (!success)
1643061da546Spatrick     return false;
1644061da546Spatrick 
1645061da546Spatrick   base_address = base_address + imm5;
1646061da546Spatrick 
1647061da546Spatrick   // We use bad_vaddr_context to store base address which is used by H/W
1648061da546Spatrick   // watchpoint Set the bad_vaddr register with base address used in the
1649061da546Spatrick   // instruction
1650061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
1651061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
1652061da546Spatrick                         base_address);
1653061da546Spatrick 
1654061da546Spatrick   if (base == dwarf_sp_mips && nonvolatile_reg_p(src)) {
1655061da546Spatrick     RegisterValue data_src;
1656*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_src =
1657*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + src);
1658*f6aab3d8Srobert     if (!reg_info_src)
1659061da546Spatrick       return false;
1660061da546Spatrick 
1661061da546Spatrick     Context context;
1662061da546Spatrick     context.type = eContextPopRegisterOffStack;
1663061da546Spatrick     context.SetAddress(base_address);
1664061da546Spatrick 
1665*f6aab3d8Srobert     return WriteRegister(context, *reg_info_src, data_src);
1666061da546Spatrick   }
1667061da546Spatrick 
1668061da546Spatrick   return false;
1669061da546Spatrick }
1670061da546Spatrick 
1671061da546Spatrick /* Emulate LWM16, LWM32 and LWP instructions.
1672061da546Spatrick 
1673061da546Spatrick    LWM16 always has stack pointer as a base register (but it is still available
1674061da546Spatrick    in MCInst as an operand).
1675061da546Spatrick    LWM32 and LWP can have base register other than stack pointer.
1676061da546Spatrick */
Emulate_LWM16_32(llvm::MCInst & insn)1677061da546Spatrick bool EmulateInstructionMIPS::Emulate_LWM16_32(llvm::MCInst &insn) {
1678061da546Spatrick   bool success = false;
1679061da546Spatrick   uint32_t dst, base;
1680061da546Spatrick   uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on
1681061da546Spatrick                                                  // no of regs to store.
1682061da546Spatrick   uint32_t imm = insn.getOperand(num_operands - 1)
1683061da546Spatrick                      .getImm(); // imm is the last operand in the instruction.
1684061da546Spatrick 
1685061da546Spatrick   // Base register is second last operand of the instruction.
1686061da546Spatrick   base =
1687061da546Spatrick       m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
1688061da546Spatrick 
1689061da546Spatrick   // We are looking for sp based loads so if base is not a stack pointer then
1690061da546Spatrick   // don't proceed.
1691061da546Spatrick   if (base != dwarf_sp_mips)
1692061da546Spatrick     return false;
1693061da546Spatrick 
1694061da546Spatrick   uint32_t base_address = ReadRegisterUnsigned(
1695061da546Spatrick       eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success);
1696061da546Spatrick   if (!success)
1697061da546Spatrick     return false;
1698061da546Spatrick 
1699061da546Spatrick   base_address = base_address + imm;
1700061da546Spatrick 
1701061da546Spatrick   RegisterValue data_dst;
1702061da546Spatrick 
1703061da546Spatrick   // Total no of registers to be re-stored are num_operands-2.
1704061da546Spatrick   for (uint32_t i = 0; i < num_operands - 2; i++) {
1705061da546Spatrick     // Get the register number to be re-stored.
1706061da546Spatrick     dst = m_reg_info->getEncodingValue(insn.getOperand(i).getReg());
1707061da546Spatrick 
1708061da546Spatrick     /*
1709061da546Spatrick         Record only non-volatile loads.
1710061da546Spatrick         This check is required for LWP instruction because destination operand
1711061da546Spatrick        could be any register.
1712061da546Spatrick         LWM16 and LWM32 instruction always has saved registers as destination
1713061da546Spatrick        operands.
1714061da546Spatrick     */
1715061da546Spatrick     if (!nonvolatile_reg_p(dst))
1716061da546Spatrick       return false;
1717061da546Spatrick 
1718*f6aab3d8Srobert     std::optional<RegisterInfo> reg_info_dst =
1719*f6aab3d8Srobert         GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + dst);
1720*f6aab3d8Srobert     if (!reg_info_dst)
1721061da546Spatrick       return false;
1722061da546Spatrick 
1723061da546Spatrick     Context context;
1724061da546Spatrick     context.type = eContextPopRegisterOffStack;
1725061da546Spatrick     context.SetAddress(base_address + (i * 4));
1726061da546Spatrick 
1727*f6aab3d8Srobert     if (!WriteRegister(context, *reg_info_dst, data_dst))
1728061da546Spatrick       return false;
1729061da546Spatrick   }
1730061da546Spatrick 
1731061da546Spatrick   return true;
1732061da546Spatrick }
1733061da546Spatrick 
Emulate_JRADDIUSP(llvm::MCInst & insn)1734061da546Spatrick bool EmulateInstructionMIPS::Emulate_JRADDIUSP(llvm::MCInst &insn) {
1735061da546Spatrick   bool success = false;
1736061da546Spatrick   int32_t imm5 = insn.getOperand(0).getImm();
1737061da546Spatrick 
1738061da546Spatrick   /* JRADDIUSP immediate
1739061da546Spatrick   *       PC <- RA
1740061da546Spatrick   *       SP <- SP + zero_extend(Immediate << 2)
1741061da546Spatrick   */
1742061da546Spatrick 
1743061da546Spatrick   // This instruction operates implicitly on stack pointer, so read <sp>
1744061da546Spatrick   // register.
1745061da546Spatrick   int32_t src_opd_val =
1746061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_sp_mips, 0, &success);
1747061da546Spatrick   if (!success)
1748061da546Spatrick     return false;
1749061da546Spatrick 
1750061da546Spatrick   int32_t ra_val =
1751061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_ra_mips, 0, &success);
1752061da546Spatrick   if (!success)
1753061da546Spatrick     return false;
1754061da546Spatrick 
1755061da546Spatrick   int32_t result = src_opd_val + imm5;
1756061da546Spatrick 
1757061da546Spatrick   Context context;
1758061da546Spatrick 
1759061da546Spatrick   // Update the PC
1760061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
1761061da546Spatrick                              ra_val))
1762061da546Spatrick     return false;
1763061da546Spatrick 
1764*f6aab3d8Srobert   std::optional<RegisterInfo> reg_info_sp =
1765*f6aab3d8Srobert       GetRegisterInfo(eRegisterKindDWARF, dwarf_sp_mips);
1766*f6aab3d8Srobert   if (reg_info_sp)
1767*f6aab3d8Srobert     context.SetRegisterPlusOffset(*reg_info_sp, imm5);
1768061da546Spatrick 
1769061da546Spatrick   // We are adjusting stack
1770061da546Spatrick   context.type = eContextAdjustStackPointer;
1771061da546Spatrick 
1772061da546Spatrick   // update SP
1773061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_sp_mips,
1774061da546Spatrick                                result);
1775061da546Spatrick }
1776061da546Spatrick 
IsAdd64bitOverflow(int32_t a,int32_t b)1777061da546Spatrick static int IsAdd64bitOverflow(int32_t a, int32_t b) {
1778061da546Spatrick   int32_t r = (uint32_t)a + (uint32_t)b;
1779061da546Spatrick   return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
1780061da546Spatrick }
1781061da546Spatrick 
1782061da546Spatrick /*
1783061da546Spatrick     Emulate below MIPS branch instructions.
1784061da546Spatrick     BEQ, BNE : Branch on condition
1785061da546Spatrick     BEQL, BNEL : Branch likely
1786061da546Spatrick */
Emulate_BXX_3ops(llvm::MCInst & insn)1787061da546Spatrick bool EmulateInstructionMIPS::Emulate_BXX_3ops(llvm::MCInst &insn) {
1788061da546Spatrick   bool success = false;
1789061da546Spatrick   uint32_t rs, rt;
1790061da546Spatrick   int32_t offset, pc, target = 0, rs_val, rt_val;
1791*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
1792061da546Spatrick 
1793061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1794061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1795061da546Spatrick   offset = insn.getOperand(2).getImm();
1796061da546Spatrick 
1797061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1798061da546Spatrick   if (!success)
1799061da546Spatrick     return false;
1800061da546Spatrick 
1801061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1802061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
1803061da546Spatrick   if (!success)
1804061da546Spatrick     return false;
1805061da546Spatrick 
1806061da546Spatrick   rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1807061da546Spatrick                                          dwarf_zero_mips + rt, 0, &success);
1808061da546Spatrick   if (!success)
1809061da546Spatrick     return false;
1810061da546Spatrick 
1811*f6aab3d8Srobert   if (op_name.equals_insensitive("BEQ") || op_name.equals_insensitive("BEQL")) {
1812061da546Spatrick     if (rs_val == rt_val)
1813061da546Spatrick       target = pc + offset;
1814061da546Spatrick     else
1815061da546Spatrick       target = pc + 8;
1816*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNE") ||
1817*f6aab3d8Srobert              op_name.equals_insensitive("BNEL")) {
1818061da546Spatrick     if (rs_val != rt_val)
1819061da546Spatrick       target = pc + offset;
1820061da546Spatrick     else
1821061da546Spatrick       target = pc + 8;
1822061da546Spatrick   }
1823061da546Spatrick 
1824061da546Spatrick   Context context;
1825061da546Spatrick   context.type = eContextRelativeBranchImmediate;
1826061da546Spatrick   context.SetImmediate(offset);
1827061da546Spatrick 
1828061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
1829061da546Spatrick                                target);
1830061da546Spatrick }
1831061da546Spatrick 
1832061da546Spatrick /*
1833061da546Spatrick     Emulate below MIPS branch instructions.
1834061da546Spatrick     BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch
1835061da546Spatrick    instructions with no delay slot
1836061da546Spatrick */
Emulate_BXX_3ops_C(llvm::MCInst & insn)1837061da546Spatrick bool EmulateInstructionMIPS::Emulate_BXX_3ops_C(llvm::MCInst &insn) {
1838061da546Spatrick   bool success = false;
1839061da546Spatrick   uint32_t rs, rt;
1840061da546Spatrick   int32_t offset, pc, target = 0, rs_val, rt_val;
1841*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
1842061da546Spatrick   uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
1843061da546Spatrick 
1844061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1845061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
1846061da546Spatrick   offset = insn.getOperand(2).getImm();
1847061da546Spatrick 
1848061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1849061da546Spatrick   if (!success)
1850061da546Spatrick     return false;
1851061da546Spatrick 
1852061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1853061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
1854061da546Spatrick   if (!success)
1855061da546Spatrick     return false;
1856061da546Spatrick 
1857061da546Spatrick   rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1858061da546Spatrick                                          dwarf_zero_mips + rt, 0, &success);
1859061da546Spatrick   if (!success)
1860061da546Spatrick     return false;
1861061da546Spatrick 
1862*f6aab3d8Srobert   if (op_name.equals_insensitive("BEQC")) {
1863061da546Spatrick     if (rs_val == rt_val)
1864061da546Spatrick       target = pc + offset;
1865061da546Spatrick     else
1866061da546Spatrick       target = pc + 4;
1867*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNEC")) {
1868061da546Spatrick     if (rs_val != rt_val)
1869061da546Spatrick       target = pc + offset;
1870061da546Spatrick     else
1871061da546Spatrick       target = pc + 4;
1872*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLTC")) {
1873061da546Spatrick     if (rs_val < rt_val)
1874061da546Spatrick       target = pc + offset;
1875061da546Spatrick     else
1876061da546Spatrick       target = pc + 4;
1877*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEC")) {
1878061da546Spatrick     if (rs_val >= rt_val)
1879061da546Spatrick       target = pc + offset;
1880061da546Spatrick     else
1881061da546Spatrick       target = pc + 4;
1882*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLTUC")) {
1883061da546Spatrick     if (rs_val < rt_val)
1884061da546Spatrick       target = pc + offset;
1885061da546Spatrick     else
1886061da546Spatrick       target = pc + 4;
1887*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEUC")) {
1888061da546Spatrick     if ((uint32_t)rs_val >= (uint32_t)rt_val)
1889061da546Spatrick       target = pc + offset;
1890061da546Spatrick     else
1891061da546Spatrick       target = pc + 4;
1892*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BOVC")) {
1893061da546Spatrick     if (IsAdd64bitOverflow(rs_val, rt_val))
1894061da546Spatrick       target = pc + offset;
1895061da546Spatrick     else
1896061da546Spatrick       target = pc + 4;
1897*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNVC")) {
1898061da546Spatrick     if (!IsAdd64bitOverflow(rs_val, rt_val))
1899061da546Spatrick       target = pc + offset;
1900061da546Spatrick     else
1901061da546Spatrick       target = pc + 4;
1902061da546Spatrick   }
1903061da546Spatrick 
1904061da546Spatrick   Context context;
1905061da546Spatrick   context.type = eContextRelativeBranchImmediate;
1906061da546Spatrick   context.SetImmediate(current_inst_size + offset);
1907061da546Spatrick 
1908061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
1909061da546Spatrick                                target);
1910061da546Spatrick }
1911061da546Spatrick 
1912061da546Spatrick /*
1913061da546Spatrick     Emulate below MIPS conditional branch and link instructions.
1914061da546Spatrick     BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches
1915061da546Spatrick */
Emulate_Bcond_Link_C(llvm::MCInst & insn)1916061da546Spatrick bool EmulateInstructionMIPS::Emulate_Bcond_Link_C(llvm::MCInst &insn) {
1917061da546Spatrick   bool success = false;
1918061da546Spatrick   uint32_t rs;
1919061da546Spatrick   int32_t offset, pc, target = 0;
1920061da546Spatrick   int32_t rs_val;
1921*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
1922061da546Spatrick 
1923061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1924061da546Spatrick   offset = insn.getOperand(1).getImm();
1925061da546Spatrick 
1926061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1927061da546Spatrick   if (!success)
1928061da546Spatrick     return false;
1929061da546Spatrick 
1930061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
1931061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
1932061da546Spatrick   if (!success)
1933061da546Spatrick     return false;
1934061da546Spatrick 
1935*f6aab3d8Srobert   if (op_name.equals_insensitive("BLEZALC")) {
1936061da546Spatrick     if (rs_val <= 0)
1937061da546Spatrick       target = pc + offset;
1938061da546Spatrick     else
1939061da546Spatrick       target = pc + 4;
1940*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEZALC")) {
1941061da546Spatrick     if (rs_val >= 0)
1942061da546Spatrick       target = pc + offset;
1943061da546Spatrick     else
1944061da546Spatrick       target = pc + 4;
1945*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLTZALC")) {
1946061da546Spatrick     if (rs_val < 0)
1947061da546Spatrick       target = pc + offset;
1948061da546Spatrick     else
1949061da546Spatrick       target = pc + 4;
1950*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGTZALC")) {
1951061da546Spatrick     if (rs_val > 0)
1952061da546Spatrick       target = pc + offset;
1953061da546Spatrick     else
1954061da546Spatrick       target = pc + 4;
1955*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BEQZALC")) {
1956061da546Spatrick     if (rs_val == 0)
1957061da546Spatrick       target = pc + offset;
1958061da546Spatrick     else
1959061da546Spatrick       target = pc + 4;
1960*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNEZALC")) {
1961061da546Spatrick     if (rs_val != 0)
1962061da546Spatrick       target = pc + offset;
1963061da546Spatrick     else
1964061da546Spatrick       target = pc + 4;
1965061da546Spatrick   }
1966061da546Spatrick 
1967061da546Spatrick   Context context;
1968061da546Spatrick 
1969061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
1970061da546Spatrick                              target))
1971061da546Spatrick     return false;
1972061da546Spatrick 
1973061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
1974061da546Spatrick                              pc + 4))
1975061da546Spatrick     return false;
1976061da546Spatrick 
1977061da546Spatrick   return true;
1978061da546Spatrick }
1979061da546Spatrick 
1980061da546Spatrick /*
1981061da546Spatrick     Emulate below MIPS Non-Compact conditional branch and link instructions.
1982061da546Spatrick     BLTZAL, BGEZAL      :
1983061da546Spatrick     BLTZALL, BGEZALL    : Branch likely
1984061da546Spatrick */
Emulate_Bcond_Link(llvm::MCInst & insn)1985061da546Spatrick bool EmulateInstructionMIPS::Emulate_Bcond_Link(llvm::MCInst &insn) {
1986061da546Spatrick   bool success = false;
1987061da546Spatrick   uint32_t rs;
1988061da546Spatrick   int32_t offset, pc, target = 0;
1989061da546Spatrick   int32_t rs_val;
1990*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
1991061da546Spatrick 
1992061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
1993061da546Spatrick   offset = insn.getOperand(1).getImm();
1994061da546Spatrick 
1995061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
1996061da546Spatrick   if (!success)
1997061da546Spatrick     return false;
1998061da546Spatrick 
1999061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2000061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
2001061da546Spatrick   if (!success)
2002061da546Spatrick     return false;
2003061da546Spatrick 
2004*f6aab3d8Srobert   if (op_name.equals_insensitive("BLTZAL") ||
2005*f6aab3d8Srobert       op_name.equals_insensitive("BLTZALL")) {
2006061da546Spatrick     if ((int32_t)rs_val < 0)
2007061da546Spatrick       target = pc + offset;
2008061da546Spatrick     else
2009061da546Spatrick       target = pc + 8;
2010*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEZAL") ||
2011*f6aab3d8Srobert              op_name.equals_insensitive("BGEZALL")) {
2012061da546Spatrick     if ((int32_t)rs_val >= 0)
2013061da546Spatrick       target = pc + offset;
2014061da546Spatrick     else
2015061da546Spatrick       target = pc + 8;
2016061da546Spatrick   }
2017061da546Spatrick 
2018061da546Spatrick   Context context;
2019061da546Spatrick 
2020061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2021061da546Spatrick                              target))
2022061da546Spatrick     return false;
2023061da546Spatrick 
2024061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2025061da546Spatrick                              pc + 8))
2026061da546Spatrick     return false;
2027061da546Spatrick 
2028061da546Spatrick   return true;
2029061da546Spatrick }
2030061da546Spatrick 
2031061da546Spatrick /*
2032061da546Spatrick     Emulate below MIPS branch instructions.
2033061da546Spatrick     BLTZL, BGEZL, BGTZL, BLEZL : Branch likely
2034061da546Spatrick     BLTZ, BGEZ, BGTZ, BLEZ     : Non-compact branches
2035061da546Spatrick */
Emulate_BXX_2ops(llvm::MCInst & insn)2036061da546Spatrick bool EmulateInstructionMIPS::Emulate_BXX_2ops(llvm::MCInst &insn) {
2037061da546Spatrick   bool success = false;
2038061da546Spatrick   uint32_t rs;
2039061da546Spatrick   int32_t offset, pc, target = 0;
2040061da546Spatrick   int32_t rs_val;
2041*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2042061da546Spatrick 
2043061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2044061da546Spatrick   offset = insn.getOperand(1).getImm();
2045061da546Spatrick 
2046061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2047061da546Spatrick   if (!success)
2048061da546Spatrick     return false;
2049061da546Spatrick 
2050061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2051061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
2052061da546Spatrick   if (!success)
2053061da546Spatrick     return false;
2054061da546Spatrick 
2055*f6aab3d8Srobert   if (op_name.equals_insensitive("BLTZL") ||
2056*f6aab3d8Srobert       op_name.equals_insensitive("BLTZ")) {
2057061da546Spatrick     if (rs_val < 0)
2058061da546Spatrick       target = pc + offset;
2059061da546Spatrick     else
2060061da546Spatrick       target = pc + 8;
2061*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEZL") ||
2062*f6aab3d8Srobert              op_name.equals_insensitive("BGEZ")) {
2063061da546Spatrick     if (rs_val >= 0)
2064061da546Spatrick       target = pc + offset;
2065061da546Spatrick     else
2066061da546Spatrick       target = pc + 8;
2067*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGTZL") ||
2068*f6aab3d8Srobert              op_name.equals_insensitive("BGTZ")) {
2069061da546Spatrick     if (rs_val > 0)
2070061da546Spatrick       target = pc + offset;
2071061da546Spatrick     else
2072061da546Spatrick       target = pc + 8;
2073*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLEZL") ||
2074*f6aab3d8Srobert              op_name.equals_insensitive("BLEZ")) {
2075061da546Spatrick     if (rs_val <= 0)
2076061da546Spatrick       target = pc + offset;
2077061da546Spatrick     else
2078061da546Spatrick       target = pc + 8;
2079061da546Spatrick   }
2080061da546Spatrick 
2081061da546Spatrick   Context context;
2082061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2083061da546Spatrick   context.SetImmediate(offset);
2084061da546Spatrick 
2085061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2086061da546Spatrick                                target);
2087061da546Spatrick }
2088061da546Spatrick 
2089061da546Spatrick /*
2090061da546Spatrick     Emulate below MIPS branch instructions.
2091061da546Spatrick     BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches
2092061da546Spatrick */
Emulate_BXX_2ops_C(llvm::MCInst & insn)2093061da546Spatrick bool EmulateInstructionMIPS::Emulate_BXX_2ops_C(llvm::MCInst &insn) {
2094061da546Spatrick   bool success = false;
2095061da546Spatrick   uint32_t rs;
2096061da546Spatrick   int32_t offset, pc, target = 0;
2097061da546Spatrick   int32_t rs_val;
2098*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2099061da546Spatrick   uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
2100061da546Spatrick 
2101061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2102061da546Spatrick   offset = insn.getOperand(1).getImm();
2103061da546Spatrick 
2104061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2105061da546Spatrick   if (!success)
2106061da546Spatrick     return false;
2107061da546Spatrick 
2108061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2109061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
2110061da546Spatrick   if (!success)
2111061da546Spatrick     return false;
2112061da546Spatrick 
2113*f6aab3d8Srobert   if (op_name.equals_insensitive("BLTZC")) {
2114061da546Spatrick     if (rs_val < 0)
2115061da546Spatrick       target = pc + offset;
2116061da546Spatrick     else
2117061da546Spatrick       target = pc + 4;
2118*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLEZC")) {
2119061da546Spatrick     if (rs_val <= 0)
2120061da546Spatrick       target = pc + offset;
2121061da546Spatrick     else
2122061da546Spatrick       target = pc + 4;
2123*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEZC")) {
2124061da546Spatrick     if (rs_val >= 0)
2125061da546Spatrick       target = pc + offset;
2126061da546Spatrick     else
2127061da546Spatrick       target = pc + 4;
2128*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGTZC")) {
2129061da546Spatrick     if (rs_val > 0)
2130061da546Spatrick       target = pc + offset;
2131061da546Spatrick     else
2132061da546Spatrick       target = pc + 4;
2133*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BEQZC")) {
2134061da546Spatrick     if (rs_val == 0)
2135061da546Spatrick       target = pc + offset;
2136061da546Spatrick     else
2137061da546Spatrick       target = pc + 4;
2138*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNEZC")) {
2139061da546Spatrick     if (rs_val != 0)
2140061da546Spatrick       target = pc + offset;
2141061da546Spatrick     else
2142061da546Spatrick       target = pc + 4;
2143061da546Spatrick   }
2144061da546Spatrick 
2145061da546Spatrick   Context context;
2146061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2147061da546Spatrick   context.SetImmediate(current_inst_size + offset);
2148061da546Spatrick 
2149061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2150061da546Spatrick                                target);
2151061da546Spatrick }
2152061da546Spatrick 
Emulate_B16_MM(llvm::MCInst & insn)2153061da546Spatrick bool EmulateInstructionMIPS::Emulate_B16_MM(llvm::MCInst &insn) {
2154061da546Spatrick   bool success = false;
2155061da546Spatrick   int32_t offset, pc, target;
2156061da546Spatrick   uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
2157061da546Spatrick 
2158061da546Spatrick   offset = insn.getOperand(0).getImm();
2159061da546Spatrick 
2160061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2161061da546Spatrick   if (!success)
2162061da546Spatrick     return false;
2163061da546Spatrick 
2164061da546Spatrick   // unconditional branch
2165061da546Spatrick   target = pc + offset;
2166061da546Spatrick 
2167061da546Spatrick   Context context;
2168061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2169061da546Spatrick   context.SetImmediate(current_inst_size + offset);
2170061da546Spatrick 
2171061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2172061da546Spatrick                                target);
2173061da546Spatrick }
2174061da546Spatrick 
2175061da546Spatrick /*
2176061da546Spatrick    BEQZC, BNEZC are 32 bit compact instructions without a delay slot.
2177061da546Spatrick    BEQZ16, BNEZ16 are 16 bit instructions with delay slot.
2178061da546Spatrick    BGEZALS, BLTZALS are 16 bit instructions with short (2-byte) delay slot.
2179061da546Spatrick */
Emulate_Branch_MM(llvm::MCInst & insn)2180061da546Spatrick bool EmulateInstructionMIPS::Emulate_Branch_MM(llvm::MCInst &insn) {
2181061da546Spatrick   bool success = false;
2182061da546Spatrick   int32_t target = 0;
2183061da546Spatrick   uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize();
2184*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2185061da546Spatrick   bool update_ra = false;
2186061da546Spatrick   uint32_t ra_offset = 0;
2187061da546Spatrick 
2188061da546Spatrick   /*
2189061da546Spatrick    * BEQZ16 rs, offset
2190061da546Spatrick    *      condition <- (GPR[rs] = 0)
2191061da546Spatrick    *      if condition then
2192061da546Spatrick    *          PC = PC + sign_ext (offset || 0)
2193061da546Spatrick    *
2194061da546Spatrick    * BNEZ16 rs, offset
2195061da546Spatrick    *      condition <- (GPR[rs] != 0)
2196061da546Spatrick    *      if condition then
2197061da546Spatrick    *          PC = PC + sign_ext (offset || 0)
2198061da546Spatrick    *
2199061da546Spatrick    * BEQZC rs, offset     (compact instruction: No delay slot)
2200061da546Spatrick    *      condition <- (GPR[rs] == 0)
2201061da546Spatrick    *      if condition then
2202061da546Spatrick    *         PC = PC + 4 + sign_ext (offset || 0)
2203061da546Spatrick   */
2204061da546Spatrick 
2205061da546Spatrick   uint32_t rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2206061da546Spatrick   int32_t offset = insn.getOperand(1).getImm();
2207061da546Spatrick 
2208061da546Spatrick   int32_t pc =
2209061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2210061da546Spatrick   if (!success)
2211061da546Spatrick     return false;
2212061da546Spatrick 
2213061da546Spatrick   int32_t rs_val = (int32_t)ReadRegisterUnsigned(
2214061da546Spatrick       eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success);
2215061da546Spatrick   if (!success)
2216061da546Spatrick     return false;
2217061da546Spatrick 
2218*f6aab3d8Srobert   if (op_name.equals_insensitive("BEQZ16_MM")) {
2219061da546Spatrick     if (rs_val == 0)
2220061da546Spatrick       target = pc + offset;
2221061da546Spatrick     else
2222061da546Spatrick       target = pc + current_inst_size +
2223061da546Spatrick                m_next_inst_size; // Skip delay slot instruction.
2224*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNEZ16_MM")) {
2225061da546Spatrick     if (rs_val != 0)
2226061da546Spatrick       target = pc + offset;
2227061da546Spatrick     else
2228061da546Spatrick       target = pc + current_inst_size +
2229061da546Spatrick                m_next_inst_size; // Skip delay slot instruction.
2230*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BEQZC_MM")) {
2231061da546Spatrick     if (rs_val == 0)
2232061da546Spatrick       target = pc + 4 + offset;
2233061da546Spatrick     else
2234061da546Spatrick       target =
2235061da546Spatrick           pc +
2236061da546Spatrick           4; // 32 bit instruction and does not have delay slot instruction.
2237*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BNEZC_MM")) {
2238061da546Spatrick     if (rs_val != 0)
2239061da546Spatrick       target = pc + 4 + offset;
2240061da546Spatrick     else
2241061da546Spatrick       target =
2242061da546Spatrick           pc +
2243061da546Spatrick           4; // 32 bit instruction and does not have delay slot instruction.
2244*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BGEZALS_MM")) {
2245061da546Spatrick     if (rs_val >= 0)
2246061da546Spatrick       target = pc + offset;
2247061da546Spatrick     else
2248061da546Spatrick       target = pc + 6; // 32 bit instruction with short (2-byte) delay slot
2249061da546Spatrick 
2250061da546Spatrick     update_ra = true;
2251061da546Spatrick     ra_offset = 6;
2252*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BLTZALS_MM")) {
2253061da546Spatrick     if (rs_val >= 0)
2254061da546Spatrick       target = pc + offset;
2255061da546Spatrick     else
2256061da546Spatrick       target = pc + 6; // 32 bit instruction with short (2-byte) delay slot
2257061da546Spatrick 
2258061da546Spatrick     update_ra = true;
2259061da546Spatrick     ra_offset = 6;
2260061da546Spatrick   }
2261061da546Spatrick 
2262061da546Spatrick   Context context;
2263061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2264061da546Spatrick   context.SetImmediate(current_inst_size + offset);
2265061da546Spatrick 
2266061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2267061da546Spatrick                              target))
2268061da546Spatrick     return false;
2269061da546Spatrick 
2270061da546Spatrick   if (update_ra) {
2271061da546Spatrick     if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2272061da546Spatrick                                pc + ra_offset))
2273061da546Spatrick       return false;
2274061da546Spatrick   }
2275061da546Spatrick   return true;
2276061da546Spatrick }
2277061da546Spatrick 
2278061da546Spatrick /* Emulate micromips jump instructions.
2279061da546Spatrick    JALR16,JALRS16
2280061da546Spatrick */
Emulate_JALRx16_MM(llvm::MCInst & insn)2281061da546Spatrick bool EmulateInstructionMIPS::Emulate_JALRx16_MM(llvm::MCInst &insn) {
2282061da546Spatrick   bool success = false;
2283061da546Spatrick   uint32_t ra_offset = 0;
2284*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2285061da546Spatrick 
2286061da546Spatrick   uint32_t rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2287061da546Spatrick 
2288061da546Spatrick   uint32_t pc =
2289061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2290061da546Spatrick   if (!success)
2291061da546Spatrick     return false;
2292061da546Spatrick 
2293061da546Spatrick   uint32_t rs_val = ReadRegisterUnsigned(eRegisterKindDWARF,
2294061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
2295061da546Spatrick   if (!success)
2296061da546Spatrick     return false;
2297061da546Spatrick 
2298*f6aab3d8Srobert   if (op_name.equals_insensitive("JALR16_MM"))
2299061da546Spatrick     ra_offset = 6; // 2-byte instruction with 4-byte delay slot.
2300*f6aab3d8Srobert   else if (op_name.equals_insensitive("JALRS16_MM"))
2301061da546Spatrick     ra_offset = 4; // 2-byte instruction with 2-byte delay slot.
2302061da546Spatrick 
2303061da546Spatrick   Context context;
2304061da546Spatrick 
2305061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2306061da546Spatrick                              rs_val))
2307061da546Spatrick     return false;
2308061da546Spatrick 
2309061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2310061da546Spatrick                              pc + ra_offset))
2311061da546Spatrick     return false;
2312061da546Spatrick 
2313061da546Spatrick   return true;
2314061da546Spatrick }
2315061da546Spatrick 
2316061da546Spatrick /* Emulate JALS and JALX instructions.
2317061da546Spatrick     JALS 32 bit instruction with short (2-byte) delay slot.
2318061da546Spatrick     JALX 32 bit instruction with 4-byte delay slot.
2319061da546Spatrick */
Emulate_JALx(llvm::MCInst & insn)2320061da546Spatrick bool EmulateInstructionMIPS::Emulate_JALx(llvm::MCInst &insn) {
2321061da546Spatrick   bool success = false;
2322061da546Spatrick   uint32_t offset = 0, target = 0, pc = 0, ra_offset = 0;
2323*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2324061da546Spatrick 
2325061da546Spatrick   /*
2326061da546Spatrick    * JALS target
2327061da546Spatrick    *      RA = PC + 6
2328061da546Spatrick    *      offset = sign_ext (offset << 1)
2329061da546Spatrick    *      PC = PC[31-27] | offset
2330061da546Spatrick    * JALX target
2331061da546Spatrick    *      RA = PC + 8
2332061da546Spatrick    *      offset = sign_ext (offset << 2)
2333061da546Spatrick    *      PC = PC[31-28] | offset
2334061da546Spatrick   */
2335061da546Spatrick   offset = insn.getOperand(0).getImm();
2336061da546Spatrick 
2337061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2338061da546Spatrick   if (!success)
2339061da546Spatrick     return false;
2340061da546Spatrick 
2341061da546Spatrick   // These are PC-region branches and not PC-relative.
2342*f6aab3d8Srobert   if (op_name.equals_insensitive("JALS_MM")) {
2343061da546Spatrick     // target address is in the “current” 128 MB-aligned region
2344061da546Spatrick     target = (pc & 0xF8000000UL) | offset;
2345061da546Spatrick     ra_offset = 6;
2346*f6aab3d8Srobert   } else if (op_name.equals_insensitive("JALX_MM")) {
2347061da546Spatrick     // target address is in the “current” 256 MB-aligned region
2348061da546Spatrick     target = (pc & 0xF0000000UL) | offset;
2349061da546Spatrick     ra_offset = 8;
2350061da546Spatrick   }
2351061da546Spatrick 
2352061da546Spatrick   Context context;
2353061da546Spatrick 
2354061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2355061da546Spatrick                              target))
2356061da546Spatrick     return false;
2357061da546Spatrick 
2358061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2359061da546Spatrick                              pc + ra_offset))
2360061da546Spatrick     return false;
2361061da546Spatrick 
2362061da546Spatrick   return true;
2363061da546Spatrick }
2364061da546Spatrick 
Emulate_JALRS(llvm::MCInst & insn)2365061da546Spatrick bool EmulateInstructionMIPS::Emulate_JALRS(llvm::MCInst &insn) {
2366061da546Spatrick   bool success = false;
2367061da546Spatrick   uint32_t rs = 0, rt = 0;
2368061da546Spatrick   int32_t pc = 0, rs_val = 0;
2369061da546Spatrick 
2370061da546Spatrick   /*
2371061da546Spatrick       JALRS rt, rs
2372061da546Spatrick           GPR[rt] <- PC + 6
2373061da546Spatrick           PC <- GPR[rs]
2374061da546Spatrick   */
2375061da546Spatrick 
2376061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2377061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
2378061da546Spatrick 
2379061da546Spatrick   rs_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2380061da546Spatrick                                          dwarf_zero_mips + rs, 0, &success);
2381061da546Spatrick   if (!success)
2382061da546Spatrick     return false;
2383061da546Spatrick 
2384061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2385061da546Spatrick   if (!success)
2386061da546Spatrick     return false;
2387061da546Spatrick 
2388061da546Spatrick   Context context;
2389061da546Spatrick 
2390061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2391061da546Spatrick                              rs_val))
2392061da546Spatrick     return false;
2393061da546Spatrick 
2394061da546Spatrick   // This is 4-byte instruction with 2-byte delay slot.
2395061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips + rt,
2396061da546Spatrick                              pc + 6))
2397061da546Spatrick     return false;
2398061da546Spatrick 
2399061da546Spatrick   return true;
2400061da546Spatrick }
2401061da546Spatrick 
Emulate_BAL(llvm::MCInst & insn)2402061da546Spatrick bool EmulateInstructionMIPS::Emulate_BAL(llvm::MCInst &insn) {
2403061da546Spatrick   bool success = false;
2404061da546Spatrick   int32_t offset, pc, target;
2405061da546Spatrick 
2406061da546Spatrick   /*
2407061da546Spatrick    * BAL offset
2408061da546Spatrick    *      offset = sign_ext (offset << 2)
2409061da546Spatrick    *      RA = PC + 8
2410061da546Spatrick    *      PC = PC + offset
2411061da546Spatrick   */
2412061da546Spatrick   offset = insn.getOperand(0).getImm();
2413061da546Spatrick 
2414061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2415061da546Spatrick   if (!success)
2416061da546Spatrick     return false;
2417061da546Spatrick 
2418061da546Spatrick   target = pc + offset;
2419061da546Spatrick 
2420061da546Spatrick   Context context;
2421061da546Spatrick 
2422061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2423061da546Spatrick                              target))
2424061da546Spatrick     return false;
2425061da546Spatrick 
2426061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2427061da546Spatrick                              pc + 8))
2428061da546Spatrick     return false;
2429061da546Spatrick 
2430061da546Spatrick   return true;
2431061da546Spatrick }
2432061da546Spatrick 
Emulate_BALC(llvm::MCInst & insn)2433061da546Spatrick bool EmulateInstructionMIPS::Emulate_BALC(llvm::MCInst &insn) {
2434061da546Spatrick   bool success = false;
2435061da546Spatrick   int32_t offset, pc, target;
2436061da546Spatrick 
2437061da546Spatrick   /*
2438061da546Spatrick    * BALC offset
2439061da546Spatrick    *      offset = sign_ext (offset << 2)
2440061da546Spatrick    *      RA = PC + 4
2441061da546Spatrick    *      PC = PC + 4 + offset
2442061da546Spatrick   */
2443061da546Spatrick   offset = insn.getOperand(0).getImm();
2444061da546Spatrick 
2445061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2446061da546Spatrick   if (!success)
2447061da546Spatrick     return false;
2448061da546Spatrick 
2449061da546Spatrick   target = pc + offset;
2450061da546Spatrick 
2451061da546Spatrick   Context context;
2452061da546Spatrick 
2453061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2454061da546Spatrick                              target))
2455061da546Spatrick     return false;
2456061da546Spatrick 
2457061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2458061da546Spatrick                              pc + 4))
2459061da546Spatrick     return false;
2460061da546Spatrick 
2461061da546Spatrick   return true;
2462061da546Spatrick }
2463061da546Spatrick 
Emulate_BC(llvm::MCInst & insn)2464061da546Spatrick bool EmulateInstructionMIPS::Emulate_BC(llvm::MCInst &insn) {
2465061da546Spatrick   bool success = false;
2466061da546Spatrick   int32_t offset, pc, target;
2467061da546Spatrick 
2468061da546Spatrick   /*
2469061da546Spatrick    * BC offset
2470061da546Spatrick    *      offset = sign_ext (offset << 2)
2471061da546Spatrick    *      PC = PC + 4 + offset
2472061da546Spatrick   */
2473061da546Spatrick   offset = insn.getOperand(0).getImm();
2474061da546Spatrick 
2475061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2476061da546Spatrick   if (!success)
2477061da546Spatrick     return false;
2478061da546Spatrick 
2479061da546Spatrick   target = pc + offset;
2480061da546Spatrick 
2481061da546Spatrick   Context context;
2482061da546Spatrick 
2483061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2484061da546Spatrick                                target);
2485061da546Spatrick }
2486061da546Spatrick 
Emulate_J(llvm::MCInst & insn)2487061da546Spatrick bool EmulateInstructionMIPS::Emulate_J(llvm::MCInst &insn) {
2488061da546Spatrick   bool success = false;
2489061da546Spatrick   uint32_t offset, pc;
2490061da546Spatrick 
2491061da546Spatrick   /*
2492061da546Spatrick    * J offset
2493061da546Spatrick    *      offset = sign_ext (offset << 2)
2494061da546Spatrick    *      PC = PC[63-28] | offset
2495061da546Spatrick   */
2496061da546Spatrick   offset = insn.getOperand(0).getImm();
2497061da546Spatrick 
2498061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2499061da546Spatrick   if (!success)
2500061da546Spatrick     return false;
2501061da546Spatrick 
2502061da546Spatrick   /* This is a PC-region branch and not PC-relative */
2503061da546Spatrick   pc = (pc & 0xF0000000UL) | offset;
2504061da546Spatrick 
2505061da546Spatrick   Context context;
2506061da546Spatrick 
2507061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips, pc);
2508061da546Spatrick }
2509061da546Spatrick 
Emulate_JAL(llvm::MCInst & insn)2510061da546Spatrick bool EmulateInstructionMIPS::Emulate_JAL(llvm::MCInst &insn) {
2511061da546Spatrick   bool success = false;
2512061da546Spatrick   uint32_t offset, target, pc;
2513061da546Spatrick 
2514061da546Spatrick   /*
2515061da546Spatrick    * JAL offset
2516061da546Spatrick    *      offset = sign_ext (offset << 2)
2517061da546Spatrick    *      PC = PC[63-28] | offset
2518061da546Spatrick   */
2519061da546Spatrick   offset = insn.getOperand(0).getImm();
2520061da546Spatrick 
2521061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2522061da546Spatrick   if (!success)
2523061da546Spatrick     return false;
2524061da546Spatrick 
2525061da546Spatrick   /* This is a PC-region branch and not PC-relative */
2526061da546Spatrick   target = (pc & 0xF0000000UL) | offset;
2527061da546Spatrick 
2528061da546Spatrick   Context context;
2529061da546Spatrick 
2530061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2531061da546Spatrick                              target))
2532061da546Spatrick     return false;
2533061da546Spatrick 
2534061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2535061da546Spatrick                              pc + 8))
2536061da546Spatrick     return false;
2537061da546Spatrick 
2538061da546Spatrick   return true;
2539061da546Spatrick }
2540061da546Spatrick 
Emulate_JALR(llvm::MCInst & insn)2541061da546Spatrick bool EmulateInstructionMIPS::Emulate_JALR(llvm::MCInst &insn) {
2542061da546Spatrick   bool success = false;
2543061da546Spatrick   uint32_t rs, rt;
2544061da546Spatrick   uint32_t pc, rs_val;
2545061da546Spatrick 
2546061da546Spatrick   /*
2547061da546Spatrick    * JALR rt, rs
2548061da546Spatrick    *      GPR[rt] = PC + 8
2549061da546Spatrick    *      PC = GPR[rs]
2550061da546Spatrick   */
2551061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2552061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(1).getReg());
2553061da546Spatrick 
2554061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2555061da546Spatrick   if (!success)
2556061da546Spatrick     return false;
2557061da546Spatrick 
2558061da546Spatrick   rs_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + rs, 0,
2559061da546Spatrick                                 &success);
2560061da546Spatrick   if (!success)
2561061da546Spatrick     return false;
2562061da546Spatrick 
2563061da546Spatrick   Context context;
2564061da546Spatrick 
2565061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2566061da546Spatrick                              rs_val))
2567061da546Spatrick     return false;
2568061da546Spatrick 
2569061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_zero_mips + rt,
2570061da546Spatrick                              pc + 8))
2571061da546Spatrick     return false;
2572061da546Spatrick 
2573061da546Spatrick   return true;
2574061da546Spatrick }
2575061da546Spatrick 
Emulate_JIALC(llvm::MCInst & insn)2576061da546Spatrick bool EmulateInstructionMIPS::Emulate_JIALC(llvm::MCInst &insn) {
2577061da546Spatrick   bool success = false;
2578061da546Spatrick   uint32_t rt;
2579061da546Spatrick   int32_t target, offset, pc, rt_val;
2580061da546Spatrick 
2581061da546Spatrick   /*
2582061da546Spatrick    * JIALC rt, offset
2583061da546Spatrick    *      offset = sign_ext (offset)
2584061da546Spatrick    *      PC = GPR[rt] + offset
2585061da546Spatrick    *      RA = PC + 4
2586061da546Spatrick   */
2587061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2588061da546Spatrick   offset = insn.getOperand(1).getImm();
2589061da546Spatrick 
2590061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2591061da546Spatrick   if (!success)
2592061da546Spatrick     return false;
2593061da546Spatrick 
2594061da546Spatrick   rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2595061da546Spatrick                                          dwarf_zero_mips + rt, 0, &success);
2596061da546Spatrick   if (!success)
2597061da546Spatrick     return false;
2598061da546Spatrick 
2599061da546Spatrick   target = rt_val + offset;
2600061da546Spatrick 
2601061da546Spatrick   Context context;
2602061da546Spatrick 
2603061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2604061da546Spatrick                              target))
2605061da546Spatrick     return false;
2606061da546Spatrick 
2607061da546Spatrick   if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_ra_mips,
2608061da546Spatrick                              pc + 4))
2609061da546Spatrick     return false;
2610061da546Spatrick 
2611061da546Spatrick   return true;
2612061da546Spatrick }
2613061da546Spatrick 
Emulate_JIC(llvm::MCInst & insn)2614061da546Spatrick bool EmulateInstructionMIPS::Emulate_JIC(llvm::MCInst &insn) {
2615061da546Spatrick   bool success = false;
2616061da546Spatrick   uint32_t rt;
2617061da546Spatrick   int32_t target, offset, rt_val;
2618061da546Spatrick 
2619061da546Spatrick   /*
2620061da546Spatrick    * JIC rt, offset
2621061da546Spatrick    *      offset = sign_ext (offset)
2622061da546Spatrick    *      PC = GPR[rt] + offset
2623061da546Spatrick   */
2624061da546Spatrick   rt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2625061da546Spatrick   offset = insn.getOperand(1).getImm();
2626061da546Spatrick 
2627061da546Spatrick   rt_val = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2628061da546Spatrick                                          dwarf_zero_mips + rt, 0, &success);
2629061da546Spatrick   if (!success)
2630061da546Spatrick     return false;
2631061da546Spatrick 
2632061da546Spatrick   target = rt_val + offset;
2633061da546Spatrick 
2634061da546Spatrick   Context context;
2635061da546Spatrick 
2636061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2637061da546Spatrick                                target);
2638061da546Spatrick }
2639061da546Spatrick 
Emulate_JR(llvm::MCInst & insn)2640061da546Spatrick bool EmulateInstructionMIPS::Emulate_JR(llvm::MCInst &insn) {
2641061da546Spatrick   bool success = false;
2642061da546Spatrick   uint32_t rs;
2643061da546Spatrick   uint32_t rs_val;
2644061da546Spatrick 
2645061da546Spatrick   /*
2646061da546Spatrick    * JR rs
2647061da546Spatrick    *      PC = GPR[rs]
2648061da546Spatrick   */
2649061da546Spatrick   rs = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2650061da546Spatrick 
2651061da546Spatrick   rs_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + rs, 0,
2652061da546Spatrick                                 &success);
2653061da546Spatrick   if (!success)
2654061da546Spatrick     return false;
2655061da546Spatrick 
2656061da546Spatrick   Context context;
2657061da546Spatrick 
2658061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2659061da546Spatrick                                rs_val);
2660061da546Spatrick }
2661061da546Spatrick 
2662061da546Spatrick /*
2663061da546Spatrick     Emulate Branch on FP True/False
2664061da546Spatrick     BC1F, BC1FL :   Branch on FP False (L stands for branch likely)
2665061da546Spatrick     BC1T, BC1TL :   Branch on FP True  (L stands for branch likely)
2666061da546Spatrick */
Emulate_FP_branch(llvm::MCInst & insn)2667061da546Spatrick bool EmulateInstructionMIPS::Emulate_FP_branch(llvm::MCInst &insn) {
2668061da546Spatrick   bool success = false;
2669061da546Spatrick   uint32_t cc, fcsr;
2670061da546Spatrick   int32_t pc, offset, target = 0;
2671*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2672061da546Spatrick 
2673061da546Spatrick   cc = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2674061da546Spatrick   offset = insn.getOperand(1).getImm();
2675061da546Spatrick 
2676061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2677061da546Spatrick   if (!success)
2678061da546Spatrick     return false;
2679061da546Spatrick 
2680061da546Spatrick   fcsr = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success);
2681061da546Spatrick   if (!success)
2682061da546Spatrick     return false;
2683061da546Spatrick 
2684061da546Spatrick   /* fcsr[23], fcsr[25-31] are vaild condition bits */
2685061da546Spatrick   fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
2686061da546Spatrick 
2687*f6aab3d8Srobert   if (op_name.equals_insensitive("BC1F") ||
2688*f6aab3d8Srobert       op_name.equals_insensitive("BC1FL")) {
2689061da546Spatrick     if ((fcsr & (1 << cc)) == 0)
2690061da546Spatrick       target = pc + offset;
2691061da546Spatrick     else
2692061da546Spatrick       target = pc + 8;
2693*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BC1T") ||
2694*f6aab3d8Srobert              op_name.equals_insensitive("BC1TL")) {
2695061da546Spatrick     if ((fcsr & (1 << cc)) != 0)
2696061da546Spatrick       target = pc + offset;
2697061da546Spatrick     else
2698061da546Spatrick       target = pc + 8;
2699061da546Spatrick   }
2700061da546Spatrick   Context context;
2701061da546Spatrick 
2702061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2703061da546Spatrick                                target);
2704061da546Spatrick }
2705061da546Spatrick 
Emulate_BC1EQZ(llvm::MCInst & insn)2706061da546Spatrick bool EmulateInstructionMIPS::Emulate_BC1EQZ(llvm::MCInst &insn) {
2707061da546Spatrick   bool success = false;
2708061da546Spatrick   uint32_t ft;
2709061da546Spatrick   uint32_t ft_val;
2710061da546Spatrick   int32_t target, pc, offset;
2711061da546Spatrick 
2712061da546Spatrick   /*
2713061da546Spatrick    * BC1EQZ ft, offset
2714061da546Spatrick    *  condition <- (FPR[ft].bit0 == 0)
2715061da546Spatrick    *      if condition then
2716061da546Spatrick    *          offset = sign_ext (offset)
2717061da546Spatrick    *          PC = PC + 4 + offset
2718061da546Spatrick   */
2719061da546Spatrick   ft = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2720061da546Spatrick   offset = insn.getOperand(1).getImm();
2721061da546Spatrick 
2722061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2723061da546Spatrick   if (!success)
2724061da546Spatrick     return false;
2725061da546Spatrick 
2726061da546Spatrick   ft_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + ft, 0,
2727061da546Spatrick                                 &success);
2728061da546Spatrick   if (!success)
2729061da546Spatrick     return false;
2730061da546Spatrick 
2731061da546Spatrick   if ((ft_val & 1) == 0)
2732061da546Spatrick     target = pc + 4 + offset;
2733061da546Spatrick   else
2734061da546Spatrick     target = pc + 8;
2735061da546Spatrick 
2736061da546Spatrick   Context context;
2737061da546Spatrick 
2738061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2739061da546Spatrick                                target);
2740061da546Spatrick }
2741061da546Spatrick 
Emulate_BC1NEZ(llvm::MCInst & insn)2742061da546Spatrick bool EmulateInstructionMIPS::Emulate_BC1NEZ(llvm::MCInst &insn) {
2743061da546Spatrick   bool success = false;
2744061da546Spatrick   uint32_t ft;
2745061da546Spatrick   uint32_t ft_val;
2746061da546Spatrick   int32_t target, pc, offset;
2747061da546Spatrick 
2748061da546Spatrick   /*
2749061da546Spatrick    * BC1NEZ ft, offset
2750061da546Spatrick    *  condition <- (FPR[ft].bit0 != 0)
2751061da546Spatrick    *      if condition then
2752061da546Spatrick    *          offset = sign_ext (offset)
2753061da546Spatrick    *          PC = PC + 4 + offset
2754061da546Spatrick   */
2755061da546Spatrick   ft = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2756061da546Spatrick   offset = insn.getOperand(1).getImm();
2757061da546Spatrick 
2758061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2759061da546Spatrick   if (!success)
2760061da546Spatrick     return false;
2761061da546Spatrick 
2762061da546Spatrick   ft_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_zero_mips + ft, 0,
2763061da546Spatrick                                 &success);
2764061da546Spatrick   if (!success)
2765061da546Spatrick     return false;
2766061da546Spatrick 
2767061da546Spatrick   if ((ft_val & 1) != 0)
2768061da546Spatrick     target = pc + 4 + offset;
2769061da546Spatrick   else
2770061da546Spatrick     target = pc + 8;
2771061da546Spatrick 
2772061da546Spatrick   Context context;
2773061da546Spatrick 
2774061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2775061da546Spatrick                                target);
2776061da546Spatrick }
2777061da546Spatrick 
2778061da546Spatrick /*
2779061da546Spatrick     Emulate MIPS-3D Branch instructions
2780061da546Spatrick     BC1ANY2F, BC1ANY2T  : Branch on Any of Two Floating Point Condition Codes
2781061da546Spatrick    False/True
2782061da546Spatrick     BC1ANY4F, BC1ANY4T  : Branch on Any of Four Floating Point Condition Codes
2783061da546Spatrick    False/True
2784061da546Spatrick */
Emulate_3D_branch(llvm::MCInst & insn)2785061da546Spatrick bool EmulateInstructionMIPS::Emulate_3D_branch(llvm::MCInst &insn) {
2786061da546Spatrick   bool success = false;
2787061da546Spatrick   uint32_t cc, fcsr;
2788061da546Spatrick   int32_t pc, offset, target = 0;
2789*f6aab3d8Srobert   llvm::StringRef op_name = m_insn_info->getName(insn.getOpcode());
2790061da546Spatrick 
2791061da546Spatrick   cc = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2792061da546Spatrick   offset = insn.getOperand(1).getImm();
2793061da546Spatrick 
2794061da546Spatrick   pc = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2795061da546Spatrick   if (!success)
2796061da546Spatrick     return false;
2797061da546Spatrick 
2798061da546Spatrick   fcsr = (uint32_t)ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_fcsr_mips, 0,
2799061da546Spatrick                                         &success);
2800061da546Spatrick   if (!success)
2801061da546Spatrick     return false;
2802061da546Spatrick 
2803061da546Spatrick   /* fcsr[23], fcsr[25-31] are vaild condition bits */
2804061da546Spatrick   fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01);
2805061da546Spatrick 
2806*f6aab3d8Srobert   if (op_name.equals_insensitive("BC1ANY2F")) {
2807061da546Spatrick     /* if any one bit is 0 */
2808061da546Spatrick     if (((fcsr >> cc) & 3) != 3)
2809061da546Spatrick       target = pc + offset;
2810061da546Spatrick     else
2811061da546Spatrick       target = pc + 8;
2812*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BC1ANY2T")) {
2813061da546Spatrick     /* if any one bit is 1 */
2814061da546Spatrick     if (((fcsr >> cc) & 3) != 0)
2815061da546Spatrick       target = pc + offset;
2816061da546Spatrick     else
2817061da546Spatrick       target = pc + 8;
2818*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BC1ANY4F")) {
2819061da546Spatrick     /* if any one bit is 0 */
2820061da546Spatrick     if (((fcsr >> cc) & 0xf) != 0xf)
2821061da546Spatrick       target = pc + offset;
2822061da546Spatrick     else
2823061da546Spatrick       target = pc + 8;
2824*f6aab3d8Srobert   } else if (op_name.equals_insensitive("BC1ANY4T")) {
2825061da546Spatrick     /* if any one bit is 1 */
2826061da546Spatrick     if (((fcsr >> cc) & 0xf) != 0)
2827061da546Spatrick       target = pc + offset;
2828061da546Spatrick     else
2829061da546Spatrick       target = pc + 8;
2830061da546Spatrick   }
2831061da546Spatrick   Context context;
2832061da546Spatrick 
2833061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2834061da546Spatrick                                target);
2835061da546Spatrick }
2836061da546Spatrick 
Emulate_BNZB(llvm::MCInst & insn)2837061da546Spatrick bool EmulateInstructionMIPS::Emulate_BNZB(llvm::MCInst &insn) {
2838061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 1, true);
2839061da546Spatrick }
2840061da546Spatrick 
Emulate_BNZH(llvm::MCInst & insn)2841061da546Spatrick bool EmulateInstructionMIPS::Emulate_BNZH(llvm::MCInst &insn) {
2842061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 2, true);
2843061da546Spatrick }
2844061da546Spatrick 
Emulate_BNZW(llvm::MCInst & insn)2845061da546Spatrick bool EmulateInstructionMIPS::Emulate_BNZW(llvm::MCInst &insn) {
2846061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 4, true);
2847061da546Spatrick }
2848061da546Spatrick 
Emulate_BNZD(llvm::MCInst & insn)2849061da546Spatrick bool EmulateInstructionMIPS::Emulate_BNZD(llvm::MCInst &insn) {
2850061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 8, true);
2851061da546Spatrick }
2852061da546Spatrick 
Emulate_BZB(llvm::MCInst & insn)2853061da546Spatrick bool EmulateInstructionMIPS::Emulate_BZB(llvm::MCInst &insn) {
2854061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 1, false);
2855061da546Spatrick }
2856061da546Spatrick 
Emulate_BZH(llvm::MCInst & insn)2857061da546Spatrick bool EmulateInstructionMIPS::Emulate_BZH(llvm::MCInst &insn) {
2858061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 2, false);
2859061da546Spatrick }
2860061da546Spatrick 
Emulate_BZW(llvm::MCInst & insn)2861061da546Spatrick bool EmulateInstructionMIPS::Emulate_BZW(llvm::MCInst &insn) {
2862061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 4, false);
2863061da546Spatrick }
2864061da546Spatrick 
Emulate_BZD(llvm::MCInst & insn)2865061da546Spatrick bool EmulateInstructionMIPS::Emulate_BZD(llvm::MCInst &insn) {
2866061da546Spatrick   return Emulate_MSA_Branch_DF(insn, 8, false);
2867061da546Spatrick }
2868061da546Spatrick 
Emulate_MSA_Branch_DF(llvm::MCInst & insn,int element_byte_size,bool bnz)2869061da546Spatrick bool EmulateInstructionMIPS::Emulate_MSA_Branch_DF(llvm::MCInst &insn,
2870061da546Spatrick                                                    int element_byte_size,
2871061da546Spatrick                                                    bool bnz) {
2872061da546Spatrick   bool success = false, branch_hit = true;
2873061da546Spatrick   int32_t target = 0;
2874061da546Spatrick   RegisterValue reg_value;
2875061da546Spatrick   const uint8_t *ptr = nullptr;
2876061da546Spatrick 
2877061da546Spatrick   uint32_t wt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2878061da546Spatrick   int32_t offset = insn.getOperand(1).getImm();
2879061da546Spatrick 
2880061da546Spatrick   int32_t pc =
2881061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2882061da546Spatrick   if (!success)
2883061da546Spatrick     return false;
2884061da546Spatrick 
2885061da546Spatrick   if (ReadRegister(eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value))
2886061da546Spatrick     ptr = (const uint8_t *)reg_value.GetBytes();
2887061da546Spatrick   else
2888061da546Spatrick     return false;
2889061da546Spatrick 
2890061da546Spatrick   for (int i = 0; i < 16 / element_byte_size; i++) {
2891061da546Spatrick     switch (element_byte_size) {
2892061da546Spatrick     case 1:
2893061da546Spatrick       if ((*ptr == 0 && bnz) || (*ptr != 0 && !bnz))
2894061da546Spatrick         branch_hit = false;
2895061da546Spatrick       break;
2896061da546Spatrick     case 2:
2897061da546Spatrick       if ((*(const uint16_t *)ptr == 0 && bnz) ||
2898061da546Spatrick           (*(const uint16_t *)ptr != 0 && !bnz))
2899061da546Spatrick         branch_hit = false;
2900061da546Spatrick       break;
2901061da546Spatrick     case 4:
2902061da546Spatrick       if ((*(const uint32_t *)ptr == 0 && bnz) ||
2903061da546Spatrick           (*(const uint32_t *)ptr != 0 && !bnz))
2904061da546Spatrick         branch_hit = false;
2905061da546Spatrick       break;
2906061da546Spatrick     case 8:
2907061da546Spatrick       if ((*(const uint64_t *)ptr == 0 && bnz) ||
2908061da546Spatrick           (*(const uint64_t *)ptr != 0 && !bnz))
2909061da546Spatrick         branch_hit = false;
2910061da546Spatrick       break;
2911061da546Spatrick     }
2912061da546Spatrick     if (!branch_hit)
2913061da546Spatrick       break;
2914061da546Spatrick     ptr = ptr + element_byte_size;
2915061da546Spatrick   }
2916061da546Spatrick 
2917061da546Spatrick   if (branch_hit)
2918061da546Spatrick     target = pc + offset;
2919061da546Spatrick   else
2920061da546Spatrick     target = pc + 8;
2921061da546Spatrick 
2922061da546Spatrick   Context context;
2923061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2924061da546Spatrick 
2925061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2926061da546Spatrick                                target);
2927061da546Spatrick }
2928061da546Spatrick 
Emulate_BNZV(llvm::MCInst & insn)2929061da546Spatrick bool EmulateInstructionMIPS::Emulate_BNZV(llvm::MCInst &insn) {
2930061da546Spatrick   return Emulate_MSA_Branch_V(insn, true);
2931061da546Spatrick }
2932061da546Spatrick 
Emulate_BZV(llvm::MCInst & insn)2933061da546Spatrick bool EmulateInstructionMIPS::Emulate_BZV(llvm::MCInst &insn) {
2934061da546Spatrick   return Emulate_MSA_Branch_V(insn, false);
2935061da546Spatrick }
2936061da546Spatrick 
Emulate_MSA_Branch_V(llvm::MCInst & insn,bool bnz)2937061da546Spatrick bool EmulateInstructionMIPS::Emulate_MSA_Branch_V(llvm::MCInst &insn,
2938061da546Spatrick                                                   bool bnz) {
2939061da546Spatrick   bool success = false;
2940061da546Spatrick   int32_t target = 0;
2941*f6aab3d8Srobert   llvm::APInt wr_val = llvm::APInt::getZero(128);
2942061da546Spatrick   llvm::APInt fail_value = llvm::APInt::getMaxValue(128);
2943*f6aab3d8Srobert   llvm::APInt zero_value = llvm::APInt::getZero(128);
2944061da546Spatrick   RegisterValue reg_value;
2945061da546Spatrick 
2946061da546Spatrick   uint32_t wt = m_reg_info->getEncodingValue(insn.getOperand(0).getReg());
2947061da546Spatrick   int32_t offset = insn.getOperand(1).getImm();
2948061da546Spatrick 
2949061da546Spatrick   int32_t pc =
2950061da546Spatrick       ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_pc_mips, 0, &success);
2951061da546Spatrick   if (!success)
2952061da546Spatrick     return false;
2953061da546Spatrick 
2954061da546Spatrick   if (ReadRegister(eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value))
2955061da546Spatrick     wr_val = reg_value.GetAsUInt128(fail_value);
2956061da546Spatrick   else
2957061da546Spatrick     return false;
2958061da546Spatrick 
2959061da546Spatrick   if ((llvm::APInt::isSameValue(zero_value, wr_val) && !bnz) ||
2960061da546Spatrick       (!llvm::APInt::isSameValue(zero_value, wr_val) && bnz))
2961061da546Spatrick     target = pc + offset;
2962061da546Spatrick   else
2963061da546Spatrick     target = pc + 8;
2964061da546Spatrick 
2965061da546Spatrick   Context context;
2966061da546Spatrick   context.type = eContextRelativeBranchImmediate;
2967061da546Spatrick 
2968061da546Spatrick   return WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_pc_mips,
2969061da546Spatrick                                target);
2970061da546Spatrick }
2971061da546Spatrick 
Emulate_LDST_Imm(llvm::MCInst & insn)2972061da546Spatrick bool EmulateInstructionMIPS::Emulate_LDST_Imm(llvm::MCInst &insn) {
2973061da546Spatrick   bool success = false;
2974061da546Spatrick   uint32_t base;
2975061da546Spatrick   int32_t imm, address;
2976061da546Spatrick   Context bad_vaddr_context;
2977061da546Spatrick 
2978061da546Spatrick   uint32_t num_operands = insn.getNumOperands();
2979061da546Spatrick   base =
2980061da546Spatrick       m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
2981061da546Spatrick   imm = insn.getOperand(num_operands - 1).getImm();
2982061da546Spatrick 
2983*f6aab3d8Srobert   if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
2984061da546Spatrick     return false;
2985061da546Spatrick 
2986061da546Spatrick   /* read base register */
2987061da546Spatrick   address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
2988061da546Spatrick                                           dwarf_zero_mips + base, 0, &success);
2989061da546Spatrick   if (!success)
2990061da546Spatrick     return false;
2991061da546Spatrick 
2992061da546Spatrick   /* destination address */
2993061da546Spatrick   address = address + imm;
2994061da546Spatrick 
2995061da546Spatrick   /* Set the bad_vaddr register with base address used in the instruction */
2996061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
2997061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
2998061da546Spatrick                         address);
2999061da546Spatrick 
3000061da546Spatrick   return true;
3001061da546Spatrick }
3002061da546Spatrick 
Emulate_LDST_Reg(llvm::MCInst & insn)3003061da546Spatrick bool EmulateInstructionMIPS::Emulate_LDST_Reg(llvm::MCInst &insn) {
3004061da546Spatrick   bool success = false;
3005061da546Spatrick   uint32_t base, index;
3006061da546Spatrick   int32_t address, index_address;
3007061da546Spatrick   Context bad_vaddr_context;
3008061da546Spatrick 
3009061da546Spatrick   uint32_t num_operands = insn.getNumOperands();
3010061da546Spatrick   base =
3011061da546Spatrick       m_reg_info->getEncodingValue(insn.getOperand(num_operands - 2).getReg());
3012061da546Spatrick   index =
3013061da546Spatrick       m_reg_info->getEncodingValue(insn.getOperand(num_operands - 1).getReg());
3014061da546Spatrick 
3015*f6aab3d8Srobert   if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + base))
3016061da546Spatrick     return false;
3017061da546Spatrick 
3018*f6aab3d8Srobert   if (!GetRegisterInfo(eRegisterKindDWARF, dwarf_zero_mips + index))
3019061da546Spatrick     return false;
3020061da546Spatrick 
3021061da546Spatrick   /* read base register */
3022061da546Spatrick   address = (int32_t)ReadRegisterUnsigned(eRegisterKindDWARF,
3023061da546Spatrick                                           dwarf_zero_mips + base, 0, &success);
3024061da546Spatrick   if (!success)
3025061da546Spatrick     return false;
3026061da546Spatrick 
3027061da546Spatrick   /* read index register */
3028061da546Spatrick   index_address = (int32_t)ReadRegisterUnsigned(
3029061da546Spatrick       eRegisterKindDWARF, dwarf_zero_mips + index, 0, &success);
3030061da546Spatrick   if (!success)
3031061da546Spatrick     return false;
3032061da546Spatrick 
3033061da546Spatrick   /* destination address */
3034061da546Spatrick   address = address + index_address;
3035061da546Spatrick 
3036061da546Spatrick   /* Set the bad_vaddr register with base address used in the instruction */
3037061da546Spatrick   bad_vaddr_context.type = eContextInvalid;
3038061da546Spatrick   WriteRegisterUnsigned(bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips,
3039061da546Spatrick                         address);
3040061da546Spatrick 
3041061da546Spatrick   return true;
3042061da546Spatrick }
3043