brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.7 KiB · db32bf8 Raw
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