Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
39645 views
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
546