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(®_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