569 lines · cpp
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-exception6//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 28using namespace lldb;29using namespace lldb_private;30 31LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionLoongArch, InstructionLoongArch)32 33namespace lldb_private {34 35EmulateInstructionLoongArch::Opcode *36EmulateInstructionLoongArch::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 75bool 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 85bool 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 90 Opcode *opcode_data = GetOpcodeForInstruction(inst);91 if (!opcode_data)92 return false;93 94 lldb::addr_t old_pc = 0;95 if (increase_pc) {96 auto addr = ReadPC();97 if (!addr)98 return false;99 old_pc = *addr;100 }101 102 // Call the Emulate... function.103 if (!(this->*opcode_data->callback)(inst))104 return false;105 106 if (increase_pc) {107 auto addr = ReadPC();108 if (!addr)109 return false;110 lldb::addr_t new_pc = *addr;111 112 if (new_pc == old_pc && !WritePC(old_pc + inst_size))113 return false;114 }115 return true;116}117 118bool EmulateInstructionLoongArch::ReadInstruction() {119 auto addr = ReadPC();120 if (!addr) {121 m_addr = LLDB_INVALID_ADDRESS;122 return false;123 }124 m_addr = *addr;125 126 bool success = false;127 Context ctx;128 ctx.type = eContextReadOpcode;129 ctx.SetNoArgs();130 uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);131 m_opcode.SetOpcode32(inst, GetByteOrder());132 133 return true;134}135 136std::optional<RegisterInfo>137EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind,138 uint32_t reg_index) {139 if (reg_kind == eRegisterKindGeneric) {140 switch (reg_index) {141 case LLDB_REGNUM_GENERIC_PC:142 reg_kind = eRegisterKindLLDB;143 reg_index = gpr_pc_loongarch;144 break;145 case LLDB_REGNUM_GENERIC_SP:146 reg_kind = eRegisterKindLLDB;147 reg_index = gpr_sp_loongarch;148 break;149 case LLDB_REGNUM_GENERIC_FP:150 reg_kind = eRegisterKindLLDB;151 reg_index = gpr_fp_loongarch;152 break;153 case LLDB_REGNUM_GENERIC_RA:154 reg_kind = eRegisterKindLLDB;155 reg_index = gpr_ra_loongarch;156 break;157 // We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are158 // supported.159 default:160 llvm_unreachable("unsupported register");161 }162 }163 164 const RegisterInfo *array =165 RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(m_arch);166 const uint32_t length =167 RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(m_arch);168 169 if (reg_index >= length || reg_kind != eRegisterKindLLDB)170 return {};171 return array[reg_index];172}173 174bool EmulateInstructionLoongArch::SetTargetTriple(const ArchSpec &arch) {175 return SupportsThisArch(arch);176}177 178bool EmulateInstructionLoongArch::TestEmulation(179 Stream &out_stream, ArchSpec &arch, OptionValueDictionary *test_data) {180 return false;181}182 183void EmulateInstructionLoongArch::Initialize() {184 PluginManager::RegisterPlugin(GetPluginNameStatic(),185 GetPluginDescriptionStatic(), CreateInstance);186}187 188void EmulateInstructionLoongArch::Terminate() {189 PluginManager::UnregisterPlugin(CreateInstance);190}191 192lldb_private::EmulateInstruction *193EmulateInstructionLoongArch::CreateInstance(const ArchSpec &arch,194 InstructionType inst_type) {195 if (EmulateInstructionLoongArch::SupportsThisInstructionType(inst_type) &&196 SupportsThisArch(arch))197 return new EmulateInstructionLoongArch(arch);198 return nullptr;199}200 201bool EmulateInstructionLoongArch::SupportsThisArch(const ArchSpec &arch) {202 return arch.GetTriple().isLoongArch();203}204 205bool EmulateInstructionLoongArch::EmulateBEQZ(uint32_t inst) {206 return IsLoongArch64() ? EmulateBEQZ64(inst) : false;207}208 209bool EmulateInstructionLoongArch::EmulateBNEZ(uint32_t inst) {210 return IsLoongArch64() ? EmulateBNEZ64(inst) : false;211}212 213bool EmulateInstructionLoongArch::EmulateBCEQZ(uint32_t inst) {214 return IsLoongArch64() ? EmulateBCEQZ64(inst) : false;215}216 217bool EmulateInstructionLoongArch::EmulateBCNEZ(uint32_t inst) {218 return IsLoongArch64() ? EmulateBCNEZ64(inst) : false;219}220 221bool EmulateInstructionLoongArch::EmulateJIRL(uint32_t inst) {222 return IsLoongArch64() ? EmulateJIRL64(inst) : false;223}224 225bool EmulateInstructionLoongArch::EmulateB(uint32_t inst) {226 return IsLoongArch64() ? EmulateB64(inst) : false;227}228 229bool EmulateInstructionLoongArch::EmulateBL(uint32_t inst) {230 return IsLoongArch64() ? EmulateBL64(inst) : false;231}232 233bool EmulateInstructionLoongArch::EmulateBEQ(uint32_t inst) {234 return IsLoongArch64() ? EmulateBEQ64(inst) : false;235}236 237bool EmulateInstructionLoongArch::EmulateBNE(uint32_t inst) {238 return IsLoongArch64() ? EmulateBNE64(inst) : false;239}240 241bool EmulateInstructionLoongArch::EmulateBLT(uint32_t inst) {242 return IsLoongArch64() ? EmulateBLT64(inst) : false;243}244 245bool EmulateInstructionLoongArch::EmulateBGE(uint32_t inst) {246 return IsLoongArch64() ? EmulateBGE64(inst) : false;247}248 249bool EmulateInstructionLoongArch::EmulateBLTU(uint32_t inst) {250 return IsLoongArch64() ? EmulateBLTU64(inst) : false;251}252 253bool EmulateInstructionLoongArch::EmulateBGEU(uint32_t inst) {254 return IsLoongArch64() ? EmulateBGEU64(inst) : false;255}256 257bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; }258 259// beqz rj, offs21260// if GR[rj] == 0:261// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)262bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) {263 bool success = false;264 uint32_t rj = Bits32(inst, 9, 5);265 266 auto addr = ReadPC();267 if (!addr)268 return false;269 uint64_t pc = *addr;270 271 uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);272 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);273 if (!success)274 return false;275 if (rj_val == 0) {276 uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);277 return WritePC(next_pc);278 } else279 return WritePC(pc + 4);280}281 282// bnez rj, offs21283// if GR[rj] != 0:284// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)285bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) {286 bool success = false;287 uint32_t rj = Bits32(inst, 9, 5);288 289 auto addr = ReadPC();290 if (!addr)291 return false;292 uint64_t pc = *addr;293 294 uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);295 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);296 if (!success)297 return false;298 if (rj_val != 0) {299 uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);300 return WritePC(next_pc);301 } else302 return WritePC(pc + 4);303}304 305// bceqz cj, offs21306// if CFR[cj] == 0:307// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)308bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) {309 bool success = false;310 uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;311 312 auto addr = ReadPC();313 if (!addr)314 return false;315 uint64_t pc = *addr;316 317 uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);318 uint8_t cj_val =319 (uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);320 if (!success)321 return false;322 if (cj_val == 0) {323 uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);324 return WritePC(next_pc);325 } else326 return WritePC(pc + 4);327 return false;328}329 330// bcnez cj, offs21331// if CFR[cj] != 0:332// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)333bool EmulateInstructionLoongArch::EmulateBCNEZ64(uint32_t inst) {334 bool success = false;335 uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;336 337 auto addr = ReadPC();338 if (!addr)339 return false;340 uint64_t pc = *addr;341 342 uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);343 uint8_t cj_val =344 (uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);345 if (!success)346 return false;347 if (cj_val != 0) {348 uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);349 return WritePC(next_pc);350 } else351 return WritePC(pc + 4);352 return false;353}354 355// jirl rd, rj, offs16356// GR[rd] = PC + 4357// PC = GR[rj] + SignExtend({offs16, 2'b0}, GRLEN)358bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) {359 uint32_t rj = Bits32(inst, 9, 5);360 uint32_t rd = Bits32(inst, 4, 0);361 bool success = false;362 363 auto addr = ReadPC();364 if (!addr)365 return false;366 uint64_t pc = *addr;367 368 EmulateInstruction::Context ctx;369 if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, rd, pc + 4))370 return false;371 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);372 if (!success)373 return false;374 uint64_t next_pc = rj_val + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);375 return WritePC(next_pc);376}377 378// b offs26379// PC = PC + SignExtend({offs26, 2' b0}, GRLEN)380bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) {381 auto addr = ReadPC();382 if (!addr)383 return false;384 uint64_t pc = *addr;385 386 uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);387 uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);388 return WritePC(next_pc);389}390 391// bl offs26392// GR[1] = PC + 4393// PC = PC + SignExtend({offs26, 2'b0}, GRLEN)394bool EmulateInstructionLoongArch::EmulateBL64(uint32_t inst) {395 auto addr = ReadPC();396 if (!addr)397 return false;398 uint64_t pc = *addr;399 400 EmulateInstruction::Context ctx;401 if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_loongarch, pc + 4))402 return false;403 uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);404 uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);405 return WritePC(next_pc);406}407 408// beq rj, rd, offs16409// if GR[rj] == GR[rd]:410// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)411bool EmulateInstructionLoongArch::EmulateBEQ64(uint32_t inst) {412 bool success = false;413 uint32_t rj = Bits32(inst, 9, 5);414 uint32_t rd = Bits32(inst, 4, 0);415 416 auto addr = ReadPC();417 if (!addr)418 return false;419 uint64_t pc = *addr;420 421 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);422 if (!success)423 return false;424 uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);425 if (!success)426 return false;427 if (rj_val == rd_val) {428 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);429 return WritePC(next_pc);430 } else431 return WritePC(pc + 4);432}433 434// bne rj, rd, offs16435// if GR[rj] != GR[rd]:436// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)437bool EmulateInstructionLoongArch::EmulateBNE64(uint32_t inst) {438 bool success = false;439 uint32_t rj = Bits32(inst, 9, 5);440 uint32_t rd = Bits32(inst, 4, 0);441 442 auto addr = ReadPC();443 if (!addr)444 return false;445 uint64_t pc = *addr;446 447 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);448 if (!success)449 return false;450 uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);451 if (!success)452 return false;453 if (rj_val != rd_val) {454 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);455 return WritePC(next_pc);456 } else457 return WritePC(pc + 4);458}459 460// blt rj, rd, offs16461// if signed(GR[rj]) < signed(GR[rd]):462// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)463bool EmulateInstructionLoongArch::EmulateBLT64(uint32_t inst) {464 bool success = false;465 uint32_t rj = Bits32(inst, 9, 5);466 uint32_t rd = Bits32(inst, 4, 0);467 468 auto addr = ReadPC();469 if (!addr)470 return false;471 uint64_t pc = *addr;472 473 int64_t rj_val =474 (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);475 if (!success)476 return false;477 int64_t rd_val =478 (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);479 if (!success)480 return false;481 if (rj_val < rd_val) {482 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);483 return WritePC(next_pc);484 } else485 return WritePC(pc + 4);486}487 488// bge rj, rd, offs16489// if signed(GR[rj]) >= signed(GR[rd]):490// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)491bool EmulateInstructionLoongArch::EmulateBGE64(uint32_t inst) {492 bool success = false;493 uint32_t rj = Bits32(inst, 9, 5);494 uint32_t rd = Bits32(inst, 4, 0);495 496 auto addr = ReadPC();497 if (!addr)498 return false;499 uint64_t pc = *addr;500 501 int64_t rj_val =502 (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);503 if (!success)504 return false;505 int64_t rd_val =506 (int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);507 if (!success)508 return false;509 if (rj_val >= rd_val) {510 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);511 return WritePC(next_pc);512 } else513 return WritePC(pc + 4);514}515 516// bltu rj, rd, offs16517// if unsigned(GR[rj]) < unsigned(GR[rd]):518// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)519bool EmulateInstructionLoongArch::EmulateBLTU64(uint32_t inst) {520 bool success = false;521 uint32_t rj = Bits32(inst, 9, 5);522 uint32_t rd = Bits32(inst, 4, 0);523 524 auto addr = ReadPC();525 if (!addr)526 return false;527 uint64_t pc = *addr;528 529 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);530 if (!success)531 return false;532 uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);533 if (!success)534 return false;535 if (rj_val < rd_val) {536 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);537 return WritePC(next_pc);538 } else539 return WritePC(pc + 4);540}541 542// bgeu rj, rd, offs16543// if unsigned(GR[rj]) >= unsigned(GR[rd]):544// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)545bool EmulateInstructionLoongArch::EmulateBGEU64(uint32_t inst) {546 bool success = false;547 uint32_t rj = Bits32(inst, 9, 5);548 uint32_t rd = Bits32(inst, 4, 0);549 550 auto addr = ReadPC();551 if (!addr)552 return false;553 uint64_t pc = *addr;554 555 uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);556 if (!success)557 return false;558 uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);559 if (!success)560 return false;561 if (rj_val >= rd_val) {562 uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);563 return WritePC(next_pc);564 } else565 return WritePC(pc + 4);566}567 568} // namespace lldb_private569