Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/LoongArch/EmulateInstructionLoongArch.cpp
39645 views
//===---EmulateInstructionLoongArch.cpp------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <cstdlib>9#include <optional>1011#include "EmulateInstructionLoongArch.h"12#include "Plugins/Process/Utility/InstructionUtils.h"13#include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h"14#include "Plugins/Process/Utility/lldb-loongarch-register-enums.h"15#include "lldb/Core/Address.h"16#include "lldb/Core/PluginManager.h"17#include "lldb/Interpreter/OptionValueArray.h"18#include "lldb/Interpreter/OptionValueDictionary.h"19#include "lldb/Symbol/UnwindPlan.h"20#include "lldb/Utility/ArchSpec.h"21#include "lldb/Utility/LLDBLog.h"22#include "lldb/Utility/RegisterValue.h"23#include "lldb/Utility/Stream.h"24#include "llvm/ADT/STLExtras.h"25#include "llvm/Support/MathExtras.h"2627using namespace lldb;28using namespace lldb_private;2930LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionLoongArch, InstructionLoongArch)3132namespace lldb_private {3334EmulateInstructionLoongArch::Opcode *35EmulateInstructionLoongArch::GetOpcodeForInstruction(uint32_t inst) {36// TODO: Add the mask for other instruction.37static EmulateInstructionLoongArch::Opcode g_opcodes[] = {38{0xfc000000, 0x40000000, &EmulateInstructionLoongArch::EmulateBEQZ,39"beqz rj, offs21"},40{0xfc000000, 0x44000000, &EmulateInstructionLoongArch::EmulateBNEZ,41"bnez rj, offs21"},42{0xfc000300, 0x48000000, &EmulateInstructionLoongArch::EmulateBCEQZ,43"bceqz cj, offs21"},44{0xfc000300, 0x48000100, &EmulateInstructionLoongArch::EmulateBCNEZ,45"bcnez cj, offs21"},46{0xfc000000, 0x4c000000, &EmulateInstructionLoongArch::EmulateJIRL,47"jirl rd, rj, offs16"},48{0xfc000000, 0x50000000, &EmulateInstructionLoongArch::EmulateB,49" b offs26"},50{0xfc000000, 0x54000000, &EmulateInstructionLoongArch::EmulateBL,51"bl offs26"},52{0xfc000000, 0x58000000, &EmulateInstructionLoongArch::EmulateBEQ,53"beq rj, rd, offs16"},54{0xfc000000, 0x5c000000, &EmulateInstructionLoongArch::EmulateBNE,55"bne rj, rd, offs16"},56{0xfc000000, 0x60000000, &EmulateInstructionLoongArch::EmulateBLT,57"blt rj, rd, offs16"},58{0xfc000000, 0x64000000, &EmulateInstructionLoongArch::EmulateBGE,59"bge rj, rd, offs16"},60{0xfc000000, 0x68000000, &EmulateInstructionLoongArch::EmulateBLTU,61"bltu rj, rd, offs16"},62{0xfc000000, 0x6c000000, &EmulateInstructionLoongArch::EmulateBGEU,63"bgeu rj, rd, offs16"},64{0x00000000, 0x00000000, &EmulateInstructionLoongArch::EmulateNonJMP,65"NonJMP"}};66static const size_t num_loongarch_opcodes = std::size(g_opcodes);6768for (size_t i = 0; i < num_loongarch_opcodes; ++i)69if ((g_opcodes[i].mask & inst) == g_opcodes[i].value)70return &g_opcodes[i];71return nullptr;72}7374bool EmulateInstructionLoongArch::TestExecute(uint32_t inst) {75Opcode *opcode_data = GetOpcodeForInstruction(inst);76if (!opcode_data)77return false;78// Call the Emulate... function.79if (!(this->*opcode_data->callback)(inst))80return false;81return true;82}8384bool EmulateInstructionLoongArch::EvaluateInstruction(uint32_t options) {85uint32_t inst_size = m_opcode.GetByteSize();86uint32_t inst = m_opcode.GetOpcode32();87bool increase_pc = options & eEmulateInstructionOptionAutoAdvancePC;88bool success = false;8990Opcode *opcode_data = GetOpcodeForInstruction(inst);91if (!opcode_data)92return false;9394lldb::addr_t old_pc = 0;95if (increase_pc) {96old_pc = ReadPC(&success);97if (!success)98return false;99}100101// Call the Emulate... function.102if (!(this->*opcode_data->callback)(inst))103return false;104105if (increase_pc) {106lldb::addr_t new_pc = ReadPC(&success);107if (!success)108return false;109110if (new_pc == old_pc && !WritePC(old_pc + inst_size))111return false;112}113return true;114}115116bool EmulateInstructionLoongArch::ReadInstruction() {117bool success = false;118m_addr = ReadPC(&success);119if (!success) {120m_addr = LLDB_INVALID_ADDRESS;121return false;122}123124Context ctx;125ctx.type = eContextReadOpcode;126ctx.SetNoArgs();127uint32_t inst = (uint32_t)ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success);128m_opcode.SetOpcode32(inst, GetByteOrder());129130return true;131}132133lldb::addr_t EmulateInstructionLoongArch::ReadPC(bool *success) {134return ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,135LLDB_INVALID_ADDRESS, success);136}137138bool EmulateInstructionLoongArch::WritePC(lldb::addr_t pc) {139EmulateInstruction::Context ctx;140ctx.type = eContextAdvancePC;141ctx.SetNoArgs();142return WriteRegisterUnsigned(ctx, eRegisterKindGeneric,143LLDB_REGNUM_GENERIC_PC, pc);144}145146std::optional<RegisterInfo>147EmulateInstructionLoongArch::GetRegisterInfo(lldb::RegisterKind reg_kind,148uint32_t reg_index) {149if (reg_kind == eRegisterKindGeneric) {150switch (reg_index) {151case LLDB_REGNUM_GENERIC_PC:152reg_kind = eRegisterKindLLDB;153reg_index = gpr_pc_loongarch;154break;155case LLDB_REGNUM_GENERIC_SP:156reg_kind = eRegisterKindLLDB;157reg_index = gpr_sp_loongarch;158break;159case LLDB_REGNUM_GENERIC_FP:160reg_kind = eRegisterKindLLDB;161reg_index = gpr_fp_loongarch;162break;163case LLDB_REGNUM_GENERIC_RA:164reg_kind = eRegisterKindLLDB;165reg_index = gpr_ra_loongarch;166break;167// We may handle LLDB_REGNUM_GENERIC_ARGx when more instructions are168// supported.169default:170llvm_unreachable("unsupported register");171}172}173174const RegisterInfo *array =175RegisterInfoPOSIX_loongarch64::GetRegisterInfoPtr(m_arch);176const uint32_t length =177RegisterInfoPOSIX_loongarch64::GetRegisterInfoCount(m_arch);178179if (reg_index >= length || reg_kind != eRegisterKindLLDB)180return {};181return array[reg_index];182}183184bool EmulateInstructionLoongArch::SetTargetTriple(const ArchSpec &arch) {185return SupportsThisArch(arch);186}187188bool EmulateInstructionLoongArch::TestEmulation(189Stream &out_stream, ArchSpec &arch, OptionValueDictionary *test_data) {190return false;191}192193void EmulateInstructionLoongArch::Initialize() {194PluginManager::RegisterPlugin(GetPluginNameStatic(),195GetPluginDescriptionStatic(), CreateInstance);196}197198void EmulateInstructionLoongArch::Terminate() {199PluginManager::UnregisterPlugin(CreateInstance);200}201202lldb_private::EmulateInstruction *203EmulateInstructionLoongArch::CreateInstance(const ArchSpec &arch,204InstructionType inst_type) {205if (EmulateInstructionLoongArch::SupportsThisInstructionType(inst_type) &&206SupportsThisArch(arch))207return new EmulateInstructionLoongArch(arch);208return nullptr;209}210211bool EmulateInstructionLoongArch::SupportsThisArch(const ArchSpec &arch) {212return arch.GetTriple().isLoongArch();213}214215bool EmulateInstructionLoongArch::EmulateBEQZ(uint32_t inst) {216return IsLoongArch64() ? EmulateBEQZ64(inst) : false;217}218219bool EmulateInstructionLoongArch::EmulateBNEZ(uint32_t inst) {220return IsLoongArch64() ? EmulateBNEZ64(inst) : false;221}222223bool EmulateInstructionLoongArch::EmulateBCEQZ(uint32_t inst) {224return IsLoongArch64() ? EmulateBCEQZ64(inst) : false;225}226227bool EmulateInstructionLoongArch::EmulateBCNEZ(uint32_t inst) {228return IsLoongArch64() ? EmulateBCNEZ64(inst) : false;229}230231bool EmulateInstructionLoongArch::EmulateJIRL(uint32_t inst) {232return IsLoongArch64() ? EmulateJIRL64(inst) : false;233}234235bool EmulateInstructionLoongArch::EmulateB(uint32_t inst) {236return IsLoongArch64() ? EmulateB64(inst) : false;237}238239bool EmulateInstructionLoongArch::EmulateBL(uint32_t inst) {240return IsLoongArch64() ? EmulateBL64(inst) : false;241}242243bool EmulateInstructionLoongArch::EmulateBEQ(uint32_t inst) {244return IsLoongArch64() ? EmulateBEQ64(inst) : false;245}246247bool EmulateInstructionLoongArch::EmulateBNE(uint32_t inst) {248return IsLoongArch64() ? EmulateBNE64(inst) : false;249}250251bool EmulateInstructionLoongArch::EmulateBLT(uint32_t inst) {252return IsLoongArch64() ? EmulateBLT64(inst) : false;253}254255bool EmulateInstructionLoongArch::EmulateBGE(uint32_t inst) {256return IsLoongArch64() ? EmulateBGE64(inst) : false;257}258259bool EmulateInstructionLoongArch::EmulateBLTU(uint32_t inst) {260return IsLoongArch64() ? EmulateBLTU64(inst) : false;261}262263bool EmulateInstructionLoongArch::EmulateBGEU(uint32_t inst) {264return IsLoongArch64() ? EmulateBGEU64(inst) : false;265}266267bool EmulateInstructionLoongArch::EmulateNonJMP(uint32_t inst) { return false; }268269// beqz rj, offs21270// if GR[rj] == 0:271// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)272bool EmulateInstructionLoongArch::EmulateBEQZ64(uint32_t inst) {273bool success = false;274uint32_t rj = Bits32(inst, 9, 5);275uint64_t pc = ReadPC(&success);276if (!success)277return false;278uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);279uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);280if (!success)281return false;282if (rj_val == 0) {283uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);284return WritePC(next_pc);285} else286return WritePC(pc + 4);287}288289// bnez rj, offs21290// if GR[rj] != 0:291// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)292bool EmulateInstructionLoongArch::EmulateBNEZ64(uint32_t inst) {293bool success = false;294uint32_t rj = Bits32(inst, 9, 5);295uint64_t pc = ReadPC(&success);296if (!success)297return false;298uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);299uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);300if (!success)301return false;302if (rj_val != 0) {303uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);304return WritePC(next_pc);305} else306return WritePC(pc + 4);307}308309// bceqz cj, offs21310// if CFR[cj] == 0:311// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)312bool EmulateInstructionLoongArch::EmulateBCEQZ64(uint32_t inst) {313bool success = false;314uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;315uint64_t pc = ReadPC(&success);316if (!success)317return false;318uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);319uint8_t cj_val =320(uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);321if (!success)322return false;323if (cj_val == 0) {324uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);325return WritePC(next_pc);326} else327return WritePC(pc + 4);328return false;329}330331// bcnez cj, offs21332// if CFR[cj] != 0:333// PC = PC + SignExtend({offs21, 2'b0}, GRLEN)334bool EmulateInstructionLoongArch::EmulateBCNEZ64(uint32_t inst) {335bool success = false;336uint32_t cj = Bits32(inst, 7, 5) + fpr_fcc0_loongarch;337uint64_t pc = ReadPC(&success);338if (!success)339return false;340uint32_t offs21 = Bits32(inst, 25, 10) + (Bits32(inst, 4, 0) << 16);341uint8_t cj_val =342(uint8_t)ReadRegisterUnsigned(eRegisterKindLLDB, cj, 0, &success);343if (!success)344return false;345if (cj_val != 0) {346uint64_t next_pc = pc + llvm::SignExtend64<23>(offs21 << 2);347return WritePC(next_pc);348} else349return WritePC(pc + 4);350return false;351}352353// jirl rd, rj, offs16354// GR[rd] = PC + 4355// PC = GR[rj] + SignExtend({offs16, 2'b0}, GRLEN)356bool EmulateInstructionLoongArch::EmulateJIRL64(uint32_t inst) {357uint32_t rj = Bits32(inst, 9, 5);358uint32_t rd = Bits32(inst, 4, 0);359bool success = false;360uint64_t pc = ReadPC(&success);361if (!success)362return false;363EmulateInstruction::Context ctx;364if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, rd, pc + 4))365return false;366uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);367if (!success)368return false;369uint64_t next_pc = rj_val + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);370return WritePC(next_pc);371}372373// b offs26374// PC = PC + SignExtend({offs26, 2' b0}, GRLEN)375bool EmulateInstructionLoongArch::EmulateB64(uint32_t inst) {376bool success = false;377uint64_t pc = ReadPC(&success);378if (!success)379return false;380uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);381uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);382return WritePC(next_pc);383}384385// bl offs26386// GR[1] = PC + 4387// PC = PC + SignExtend({offs26, 2'b0}, GRLEN)388bool EmulateInstructionLoongArch::EmulateBL64(uint32_t inst) {389bool success = false;390uint64_t pc = ReadPC(&success);391if (!success)392return false;393EmulateInstruction::Context ctx;394if (!WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_loongarch, pc + 4))395return false;396uint32_t offs26 = Bits32(inst, 25, 10) + (Bits32(inst, 9, 0) << 16);397uint64_t next_pc = pc + llvm::SignExtend64<28>(offs26 << 2);398return WritePC(next_pc);399}400401// beq rj, rd, offs16402// if GR[rj] == GR[rd]:403// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)404bool EmulateInstructionLoongArch::EmulateBEQ64(uint32_t inst) {405bool success = false;406uint32_t rj = Bits32(inst, 9, 5);407uint32_t rd = Bits32(inst, 4, 0);408uint64_t pc = ReadPC(&success);409if (!success)410return false;411uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);412if (!success)413return false;414uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);415if (!success)416return false;417if (rj_val == rd_val) {418uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);419return WritePC(next_pc);420} else421return WritePC(pc + 4);422}423424// bne rj, rd, offs16425// if GR[rj] != GR[rd]:426// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)427bool EmulateInstructionLoongArch::EmulateBNE64(uint32_t inst) {428bool success = false;429uint32_t rj = Bits32(inst, 9, 5);430uint32_t rd = Bits32(inst, 4, 0);431uint64_t pc = ReadPC(&success);432if (!success)433return false;434uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);435if (!success)436return false;437uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);438if (!success)439return false;440if (rj_val != rd_val) {441uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);442return WritePC(next_pc);443} else444return WritePC(pc + 4);445}446447// blt rj, rd, offs16448// if signed(GR[rj]) < signed(GR[rd]):449// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)450bool EmulateInstructionLoongArch::EmulateBLT64(uint32_t inst) {451bool success = false;452uint32_t rj = Bits32(inst, 9, 5);453uint32_t rd = Bits32(inst, 4, 0);454uint64_t pc = ReadPC(&success);455if (!success)456return false;457int64_t rj_val =458(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);459if (!success)460return false;461int64_t rd_val =462(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);463if (!success)464return false;465if (rj_val < rd_val) {466uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);467return WritePC(next_pc);468} else469return WritePC(pc + 4);470}471472// bge rj, rd, offs16473// if signed(GR[rj]) >= signed(GR[rd]):474// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)475bool EmulateInstructionLoongArch::EmulateBGE64(uint32_t inst) {476bool success = false;477uint32_t rj = Bits32(inst, 9, 5);478uint32_t rd = Bits32(inst, 4, 0);479uint64_t pc = ReadPC(&success);480if (!success)481return false;482int64_t rj_val =483(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);484if (!success)485return false;486int64_t rd_val =487(int64_t)ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);488if (!success)489return false;490if (rj_val >= rd_val) {491uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);492return WritePC(next_pc);493} else494return WritePC(pc + 4);495}496497// bltu rj, rd, offs16498// if unsigned(GR[rj]) < unsigned(GR[rd]):499// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)500bool EmulateInstructionLoongArch::EmulateBLTU64(uint32_t inst) {501bool success = false;502uint32_t rj = Bits32(inst, 9, 5);503uint32_t rd = Bits32(inst, 4, 0);504uint64_t pc = ReadPC(&success);505if (!success)506return false;507uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);508if (!success)509return false;510uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);511if (!success)512return false;513if (rj_val < rd_val) {514uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);515return WritePC(next_pc);516} else517return WritePC(pc + 4);518}519520// bgeu rj, rd, offs16521// if unsigned(GR[rj]) >= unsigned(GR[rd]):522// PC = PC + SignExtend({offs16, 2'b0}, GRLEN)523bool EmulateInstructionLoongArch::EmulateBGEU64(uint32_t inst) {524bool success = false;525uint32_t rj = Bits32(inst, 9, 5);526uint32_t rd = Bits32(inst, 4, 0);527uint64_t pc = ReadPC(&success);528if (!success)529return false;530uint64_t rj_val = ReadRegisterUnsigned(eRegisterKindLLDB, rj, 0, &success);531if (!success)532return false;533uint64_t rd_val = ReadRegisterUnsigned(eRegisterKindLLDB, rd, 0, &success);534if (!success)535return false;536if (rj_val >= rd_val) {537uint64_t next_pc = pc + llvm::SignExtend64<18>(Bits32(inst, 25, 10) << 2);538return WritePC(next_pc);539} else540return WritePC(pc + 4);541}542543} // namespace lldb_private544545546