1 //===---EmulateInstructionLoongArch.cpp------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <cstdlib>
10 #include <optional>
11 
12 #include "EmulateInstructionLoongArch.h"
13 #include "Plugins/Process/Utility/InstructionUtils.h"
14 #include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h"
15 #include "Plugins/Process/Utility/lldb-loongarch-register-enums.h"
16 #include "lldb/Core/Address.h"
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Interpreter/OptionValueArray.h"
19 #include "lldb/Interpreter/OptionValueDictionary.h"
20 #include "lldb/Symbol/UnwindPlan.h"
21 #include "lldb/Utility/ArchSpec.h"
22 #include "lldb/Utility/LLDBLog.h"
23 #include "lldb/Utility/RegisterValue.h"
24 #include "lldb/Utility/Stream.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/MathExtras.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionLoongArch, InstructionLoongArch)
32 
33 namespace lldb_private {
34 
35 EmulateInstructionLoongArch::Opcode *
36 EmulateInstructionLoongArch::GetOpcodeForInstruction(uint32_t inst) {
37   // TODO: Add the mask for other instruction.
38   static EmulateInstructionLoongArch::Opcode g_opcodes[] = {
39       {0xfc000000, 0x40000000, &EmulateInstructionLoongArch::EmulateBEQZ,
40        "beqz rj, offs21"},
41       {0xfc000000, 0x44000000, &EmulateInstructionLoongArch::EmulateBNEZ,
42        "bnez rj, offs21"},
43       {0xfc000300, 0x48000000, &EmulateInstructionLoongArch::EmulateBCEQZ,
44        "bceqz cj, offs21"},
45       {0xfc000300, 0x48000100, &EmulateInstructionLoongArch::EmulateBCNEZ,
46        "bcnez cj, offs21"},
47       {0xfc000000, 0x4c000000, &EmulateInstructionLoongArch::EmulateJIRL,
48        "jirl rd, rj, offs16"},
49       {0xfc000000, 0x50000000, &EmulateInstructionLoongArch::EmulateB,
50        " b  offs26"},
51       {0xfc000000, 0x54000000, &EmulateInstructionLoongArch::EmulateBL,
52        "bl  offs26"},
53       {0xfc000000, 0x58000000, &EmulateInstructionLoongArch::EmulateBEQ,
54        "beq  rj, rd, offs16"},
55       {0xfc000000, 0x5c000000, &EmulateInstructionLoongArch::EmulateBNE,
56        "bne  rj, rd, offs16"},
57       {0xfc000000, 0x60000000, &EmulateInstructionLoongArch::EmulateBLT,
58        "blt  rj, rd, offs16"},
59       {0xfc000000, 0x64000000, &EmulateInstructionLoongArch::EmulateBGE,
60        "bge  rj, rd, offs16"},
61       {0xfc000000, 0x68000000, &EmulateInstructionLoongArch::EmulateBLTU,
62        "bltu rj, rd, offs16"},
63       {0xfc000000, 0x6c000000, &EmulateInstructionLoongArch::EmulateBGEU,
64        "bgeu rj, rd, offs16"},
65       {0x00000000, 0x00000000, &EmulateInstructionLoongArch::EmulateNonJMP,
66        "NonJMP"}};
67   static const size_t num_loongarch_opcodes = std::size(g_opcodes);
68 
69   for (size_t i = 0; i < num_loongarch_opcodes; ++i)
70     if ((g_opcodes[i].mask & inst) == g_opcodes[i].value)
71       return &g_opcodes[i];
72   return nullptr;
73 }
74 
75 bool EmulateInstructionLoongArch::TestExecute(uint32_t inst) {
76   Opcode *opcode_data = GetOpcodeForInstruction(inst);
77   if (!opcode_data)
78     return false;
79   // Call the Emulate... function.
80   if (!(this->*opcode_data->callback)(inst))
81     return false;
82   return true;
83 }
84 
85 bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {
86   uint32_t inst_size = m_opcode.GetByteSize();
87   uint32_t inst = m_opcode.GetOpcode32();
88   bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;
89   bool success = false;
90 
91   Opcode *opcode_data = GetOpcodeForInstruction(inst);
92   if (!opcode_data)
93     return false;
94 
95   lldb::addr_t old_pc = 0;
96   if (increase_pc) {
97     old_pc = ReadPC(&success);
98     if (!success)
99       return false;
100   }
101 
102   // Call the Emulate... function.
103   if (!(this->*opcode_data->callback)(inst))
104     return false;
105 
106   if (increase_pc) {
107     lldb::addr_t new_pc = ReadPC(&success);
108     if (!success)
109       return false;
110 
111     if (new_pc == old_pc && !WritePC(old_pc + inst_size))
112       return false;
113   }
114   return true;
115 }
116 
117 bool EmulateInstructionLoongArch::ReadInstruction() {
118   bool success = false;
119   m_addr = ReadPC(&success);
120   if (!success) {
121     m_addr = LLDB_INVALID_ADDRESS;
122     return false;
123   }
124 
125   Context ctx;
126   ctx.type = eContextReadOpcode;
127   ctx.SetNoArgs();
128   uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);
129   m_opcode.SetOpcode32(inst, GetByteOrder());
130 
131   return true;
132 }
133 
134 lldb::addr_t EmulateInstructionLoongArch::ReadPC(bool *success) {
135   return ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
136                               LLDB_INVALID_ADDRESS, success);
137 }
138 
139 bool EmulateInstructionLoongArch::WritePC(lldb::addr_t pc) {
140   EmulateInstruction::Context ctx;
141   ctx.type = eContextAdvancePC;
142   ctx.SetNoArgs();
143   return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,
144                                LLDB_REGNUM_GENERIC_PC, pc);
145 }
146 
147 std::optional<RegisterInfo>
148 EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind,
149                                              uint32_t reg_index) {
150   if (reg_kind == eRegisterKindGeneric) {
151     switch (reg_index) {
152     case LLDB_REGNUM_GENERIC_PC:
153       reg_kind = eRegisterKindLLDB;
154       reg_index = gpr_pc_loongarch;
155       break;
156     case LLDB_REGNUM_GENERIC_SP:
157       reg_kind = eRegisterKindLLDB;
158       reg_index = gpr_sp_loongarch;
159       break;
160     case LLDB_REGNUM_GENERIC_FP:
161       reg_kind = eRegisterKindLLDB;
162       reg_index = gpr_fp_loongarch;
163       break;
164     case LLDB_REGNUM_GENERIC_RA:
165       reg_kind = eRegisterKindLLDB;
166       reg_index = gpr_ra_loongarch;
167       break;
168     // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are
169     // supported.
170     default:
171       llvm_unreachable("unsupported register");
172     }
173   }
174 
175   const RegisterInfo *array =
176       RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(m_arch);
177   const uint32_t length =
178       RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(m_arch);
179 
180   if (reg_index >= length || reg_kind != eRegisterKindLLDB)
181     return {};
182   return array[reg_index];
183 }
184 
185 bool EmulateInstructionLoongArch::SetTargetTriple(const ArchSpec &arch) {
186   return SupportsThisArch(arch);
187 }
188 
189 bool EmulateInstructionLoongArch::TestEmulation(
190     Stream &out_stream, ArchSpec &arch, OptionValueDictionary *test_data) {
191   return false;
192 }
193 
194 void EmulateInstructionLoongArch::Initialize() {
195   PluginManager::RegisterPlugin(GetPluginNameStatic(),
196                                 GetPluginDescriptionStatic(), CreateInstance);
197 }
198 
199 void EmulateInstructionLoongArch::Terminate() {
200   PluginManager::UnregisterPlugin(CreateInstance);
201 }
202 
203 lldb_private::EmulateInstruction *
204 EmulateInstructionLoongArch::CreateInstance(const ArchSpec &arch,
205                                             InstructionType inst_type) {
206   if (EmulateInstructionLoongArch::SupportsThisInstructionType(inst_type) &&
207       SupportsThisArch(arch))
208     return new EmulateInstructionLoongArch(arch);
209   return nullptr;
210 }
211 
212 bool EmulateInstructionLoongArch::SupportsThisArch(const ArchSpec &arch) {
213   return arch.GetTriple().isLoongArch();
214 }
215 
216 bool EmulateInstructionLoongArch::EmulateBEQZ(uint32_t inst) {
217   return IsLoongArch64() ? EmulateBEQZ64(inst) : false;
218 }
219 
220 bool EmulateInstructionLoongArch::EmulateBNEZ(uint32_t inst) {
221   return IsLoongArch64() ? EmulateBNEZ64(inst) : false;
222 }
223 
224 bool EmulateInstructionLoongArch::EmulateBCEQZ(uint32_t inst) {
225   return IsLoongArch64() ? EmulateBCEQZ64(inst) : false;
226 }
227 
228 bool EmulateInstructionLoongArch::EmulateBCNEZ(uint32_t inst) {
229   return IsLoongArch64() ? EmulateBCNEZ64(inst) : false;
230 }
231 
232 bool EmulateInstructionLoongArch::EmulateJIRL(uint32_t inst) {
233   return IsLoongArch64() ? EmulateJIRL64(inst) : false;
234 }
235 
236 bool EmulateInstructionLoongArch::EmulateB(uint32_t inst) {
237   return IsLoongArch64() ? EmulateB64(inst) : false;
238 }
239 
240 bool EmulateInstructionLoongArch::EmulateBL(uint32_t inst) {
241   return IsLoongArch64() ? EmulateBL64(inst) : false;
242 }
243 
244 bool EmulateInstructionLoongArch::EmulateBEQ(uint32_t inst) {
245   return IsLoongArch64() ? EmulateBEQ64(inst) : false;
246 }
247 
248 bool EmulateInstructionLoongArch::EmulateBNE(uint32_t inst) {
249   return IsLoongArch64() ? EmulateBNE64(inst) : false;
250 }
251 
252 bool EmulateInstructionLoongArch::EmulateBLT(uint32_t inst) {
253   return IsLoongArch64() ? EmulateBLT64(inst) : false;
254 }
255 
256 bool EmulateInstructionLoongArch::EmulateBGE(uint32_t inst) {
257   return IsLoongArch64() ? EmulateBGE64(inst) : false;
258 }
259 
260 bool EmulateInstructionLoongArch::EmulateBLTU(uint32_t inst) {
261   return IsLoongArch64() ? EmulateBLTU64(inst) : false;
262 }
263 
264 bool EmulateInstructionLoongArch::EmulateBGEU(uint32_t inst) {
265   return IsLoongArch64() ? EmulateBGEU64(inst) : false;
266 }
267 
268 bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; }
269 
270 // beqz rj, offs21
271 // if GR[rj] == 0:
272 //   PC = PC + SignExtend({offs21, 2'b0}, GRLEN)
273 bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) {
274   bool success = false;
275   uint32_t rj = Bits32(inst, 9, 5);
276   uint64_t pc = ReadPC(&success);
277   if (!success)
278     return false;
279   uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
280   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
281   if (!success)
282     return false;
283   if (rj_val == 0) {
284     uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);
285     return WritePC(next_pc);
286   } else
287     return WritePC(pc + 4);
288 }
289 
290 // bnez rj, offs21
291 // if GR[rj] != 0:
292 //   PC = PC + SignExtend({offs21, 2'b0}, GRLEN)
293 bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) {
294   bool success = false;
295   uint32_t rj = Bits32(inst, 9, 5);
296   uint64_t pc = ReadPC(&success);
297   if (!success)
298     return false;
299   uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
300   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
301   if (!success)
302     return false;
303   if (rj_val != 0) {
304     uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);
305     return WritePC(next_pc);
306   } else
307     return WritePC(pc + 4);
308 }
309 
310 // bceqz cj, offs21
311 // if CFR[cj] == 0:
312 //	PC = PC + SignExtend({offs21, 2'b0}, GRLEN)
313 bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) {
314   bool success = false;
315   uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;
316   uint64_t pc = ReadPC(&success);
317   if (!success)
318     return false;
319   uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
320   uint8_t cj_val =
321       (uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);
322   if (!success)
323     return false;
324   if (cj_val == 0) {
325     uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);
326     return WritePC(next_pc);
327   } else
328     return WritePC(pc + 4);
329   return false;
330 }
331 
332 // bcnez cj, offs21
333 // if CFR[cj] != 0:
334 //	PC = PC + SignExtend({offs21, 2'b0}, GRLEN)
335 bool EmulateInstructionLoongArch::EmulateBCNEZ64(uint32_t inst) {
336   bool success = false;
337   uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;
338   uint64_t pc = ReadPC(&success);
339   if (!success)
340     return false;
341   uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);
342   uint8_t cj_val =
343       (uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);
344   if (!success)
345     return false;
346   if (cj_val != 0) {
347     uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);
348     return WritePC(next_pc);
349   } else
350     return WritePC(pc + 4);
351   return false;
352 }
353 
354 // jirl rd, rj, offs16
355 // GR[rd] = PC + 4
356 // PC = GR[rj] + SignExtend({offs16, 2'b0}, GRLEN)
357 bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) {
358   uint32_t rj = Bits32(inst, 9, 5);
359   uint32_t rd = Bits32(inst, 4, 0);
360   bool success = false;
361   uint64_t pc = ReadPC(&success);
362   if (!success)
363     return false;
364   EmulateInstruction::Context ctx;
365   if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, rd, pc + 4))
366     return false;
367   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
368   if (!success)
369     return false;
370   uint64_t next_pc = rj_val + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
371   return WritePC(next_pc);
372 }
373 
374 // b offs26
375 // PC = PC + SignExtend({offs26, 2' b0}, GRLEN)
376 bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) {
377   bool success = false;
378   uint64_t pc = ReadPC(&success);
379   if (!success)
380     return false;
381   uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);
382   uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);
383   return WritePC(next_pc);
384 }
385 
386 // bl offs26
387 // GR[1] = PC + 4
388 // PC = PC + SignExtend({offs26, 2'b0}, GRLEN)
389 bool EmulateInstructionLoongArch::EmulateBL64(uint32_t inst) {
390   bool success = false;
391   uint64_t pc = ReadPC(&success);
392   if (!success)
393     return false;
394   EmulateInstruction::Context ctx;
395   if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_loongarch, pc + 4))
396     return false;
397   uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);
398   uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);
399   return WritePC(next_pc);
400 }
401 
402 // beq rj, rd, offs16
403 // if GR[rj] == GR[rd]:
404 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
405 bool EmulateInstructionLoongArch::EmulateBEQ64(uint32_t inst) {
406   bool success = false;
407   uint32_t rj = Bits32(inst, 9, 5);
408   uint32_t rd = Bits32(inst, 4, 0);
409   uint64_t pc = ReadPC(&success);
410   if (!success)
411     return false;
412   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
413   if (!success)
414     return false;
415   uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
416   if (!success)
417     return false;
418   if (rj_val == rd_val) {
419     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
420     return WritePC(next_pc);
421   } else
422     return WritePC(pc + 4);
423 }
424 
425 // bne rj, rd, offs16
426 // if GR[rj] != GR[rd]:
427 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
428 bool EmulateInstructionLoongArch::EmulateBNE64(uint32_t inst) {
429   bool success = false;
430   uint32_t rj = Bits32(inst, 9, 5);
431   uint32_t rd = Bits32(inst, 4, 0);
432   uint64_t pc = ReadPC(&success);
433   if (!success)
434     return false;
435   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
436   if (!success)
437     return false;
438   uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
439   if (!success)
440     return false;
441   if (rj_val != rd_val) {
442     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
443     return WritePC(next_pc);
444   } else
445     return WritePC(pc + 4);
446 }
447 
448 // blt rj, rd, offs16
449 // if signed(GR[rj]) < signed(GR[rd]):
450 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
451 bool EmulateInstructionLoongArch::EmulateBLT64(uint32_t inst) {
452   bool success = false;
453   uint32_t rj = Bits32(inst, 9, 5);
454   uint32_t rd = Bits32(inst, 4, 0);
455   uint64_t pc = ReadPC(&success);
456   if (!success)
457     return false;
458   int64_t rj_val =
459       (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
460   if (!success)
461     return false;
462   int64_t rd_val =
463       (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
464   if (!success)
465     return false;
466   if (rj_val < rd_val) {
467     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
468     return WritePC(next_pc);
469   } else
470     return WritePC(pc + 4);
471 }
472 
473 // bge rj, rd, offs16
474 // if signed(GR[rj]) >= signed(GR[rd]):
475 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
476 bool EmulateInstructionLoongArch::EmulateBGE64(uint32_t inst) {
477   bool success = false;
478   uint32_t rj = Bits32(inst, 9, 5);
479   uint32_t rd = Bits32(inst, 4, 0);
480   uint64_t pc = ReadPC(&success);
481   if (!success)
482     return false;
483   int64_t rj_val =
484       (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
485   if (!success)
486     return false;
487   int64_t rd_val =
488       (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
489   if (!success)
490     return false;
491   if (rj_val >= rd_val) {
492     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
493     return WritePC(next_pc);
494   } else
495     return WritePC(pc + 4);
496 }
497 
498 // bltu rj, rd, offs16
499 // if unsigned(GR[rj]) < unsigned(GR[rd]):
500 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
501 bool EmulateInstructionLoongArch::EmulateBLTU64(uint32_t inst) {
502   bool success = false;
503   uint32_t rj = Bits32(inst, 9, 5);
504   uint32_t rd = Bits32(inst, 4, 0);
505   uint64_t pc = ReadPC(&success);
506   if (!success)
507     return false;
508   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
509   if (!success)
510     return false;
511   uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
512   if (!success)
513     return false;
514   if (rj_val < rd_val) {
515     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
516     return WritePC(next_pc);
517   } else
518     return WritePC(pc + 4);
519 }
520 
521 // bgeu rj, rd, offs16
522 // if unsigned(GR[rj]) >= unsigned(GR[rd]):
523 //   PC = PC + SignExtend({offs16, 2'b0}, GRLEN)
524 bool EmulateInstructionLoongArch::EmulateBGEU64(uint32_t inst) {
525   bool success = false;
526   uint32_t rj = Bits32(inst, 9, 5);
527   uint32_t rd = Bits32(inst, 4, 0);
528   uint64_t pc = ReadPC(&success);
529   if (!success)
530     return false;
531   uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);
532   if (!success)
533     return false;
534   uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);
535   if (!success)
536     return false;
537   if (rj_val >= rd_val) {
538     uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);
539     return WritePC(next_pc);
540   } else
541     return WritePC(pc + 4);
542 }
543 
544 } // namespace lldb_private
545