brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.0 KiB · 29516c5 Raw
394 lines · cpp
1//===-- EmulateInstructionPPC64.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 "EmulateInstructionPPC64.h"10 11#include <cstdlib>12#include <optional>13 14#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"15#include "lldb/Core/PluginManager.h"16#include "lldb/Symbol/UnwindPlan.h"17#include "lldb/Utility/ArchSpec.h"18#include "lldb/Utility/ConstString.h"19#include "lldb/Utility/LLDBLog.h"20 21#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT22#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"23 24#include "Plugins/Process/Utility/InstructionUtils.h"25 26using namespace lldb;27using namespace lldb_private;28 29LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionPPC64, InstructionPPC64)30 31EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch)32    : EmulateInstruction(arch) {}33 34void EmulateInstructionPPC64::Initialize() {35  PluginManager::RegisterPlugin(GetPluginNameStatic(),36                                GetPluginDescriptionStatic(), CreateInstance);37}38 39void EmulateInstructionPPC64::Terminate() {40  PluginManager::UnregisterPlugin(CreateInstance);41}42 43llvm::StringRef EmulateInstructionPPC64::GetPluginDescriptionStatic() {44  return "Emulate instructions for the PPC64 architecture.";45}46 47EmulateInstruction *48EmulateInstructionPPC64::CreateInstance(const ArchSpec &arch,49                                        InstructionType inst_type) {50  if (EmulateInstructionPPC64::SupportsEmulatingInstructionsOfTypeStatic(51          inst_type))52    if (arch.GetTriple().isPPC64())53      return new EmulateInstructionPPC64(arch);54 55  return nullptr;56}57 58bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) {59  return arch.GetTriple().isPPC64();60}61 62static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {63  if (reg_num >= std::size(g_register_infos_ppc64le))64    return {};65  return g_register_infos_ppc64le[reg_num];66}67 68std::optional<RegisterInfo>69EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind,70                                         uint32_t reg_num) {71  if (reg_kind == eRegisterKindGeneric) {72    switch (reg_num) {73    case LLDB_REGNUM_GENERIC_PC:74      reg_kind = eRegisterKindLLDB;75      reg_num = gpr_pc_ppc64le;76      break;77    case LLDB_REGNUM_GENERIC_SP:78      reg_kind = eRegisterKindLLDB;79      reg_num = gpr_r1_ppc64le;80      break;81    case LLDB_REGNUM_GENERIC_RA:82      reg_kind = eRegisterKindLLDB;83      reg_num = gpr_lr_ppc64le;84      break;85    case LLDB_REGNUM_GENERIC_FLAGS:86      reg_kind = eRegisterKindLLDB;87      reg_num = gpr_cr_ppc64le;88      break;89 90    default:91      return {};92    }93  }94 95  if (reg_kind == eRegisterKindLLDB)96    return LLDBTableGetRegisterInfo(reg_num);97  return {};98}99 100bool EmulateInstructionPPC64::ReadInstruction() {101  bool success = false;102  m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,103                                LLDB_INVALID_ADDRESS, &success);104  if (success) {105    Context ctx;106    ctx.type = eContextReadOpcode;107    ctx.SetNoArgs();108    m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success),109                         GetByteOrder());110  }111  if (!success)112    m_addr = LLDB_INVALID_ADDRESS;113  return success;114}115 116bool EmulateInstructionPPC64::CreateFunctionEntryUnwind(117    UnwindPlan &unwind_plan) {118  unwind_plan.Clear();119  unwind_plan.SetRegisterKind(eRegisterKindLLDB);120 121  UnwindPlan::Row row;122 123  // Our previous Call Frame Address is the stack pointer124  row.GetCFAValue().SetIsRegisterPlusOffset(gpr_r1_ppc64le, 0);125 126  unwind_plan.AppendRow(std::move(row));127  unwind_plan.SetSourceName("EmulateInstructionPPC64");128  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);129  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);130  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);131  unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le);132  return true;133}134 135EmulateInstructionPPC64::Opcode *136EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) {137  static EmulateInstructionPPC64::Opcode g_opcodes[] = {138      {0xfc0007ff, 0x7c0002a6, &EmulateInstructionPPC64::EmulateMFSPR,139       "mfspr RT, SPR"},140      {0xfc000003, 0xf8000000, &EmulateInstructionPPC64::EmulateSTD,141       "std RS, DS(RA)"},142      {0xfc000003, 0xf8000001, &EmulateInstructionPPC64::EmulateSTD,143       "stdu RS, DS(RA)"},144      {0xfc0007fe, 0x7c000378, &EmulateInstructionPPC64::EmulateOR,145       "or RA, RS, RB"},146      {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI,147       "addi RT, RA, SI"},148      {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD,149       "ld RT, DS(RA)"}};150  static const size_t k_num_ppc_opcodes = std::size(g_opcodes);151 152  for (size_t i = 0; i < k_num_ppc_opcodes; ++i) {153    if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)154      return &g_opcodes[i];155  }156  return nullptr;157}158 159bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) {160  const uint32_t opcode = m_opcode.GetOpcode32();161  // LLDB_LOG(log, "PPC64::EvaluateInstruction: opcode={0:X+8}", opcode);162  Opcode *opcode_data = GetOpcodeForInstruction(opcode);163  if (!opcode_data)164    return false;165 166  // LLDB_LOG(log, "PPC64::EvaluateInstruction: {0}", opcode_data->name);167  const bool auto_advance_pc =168      evaluate_options & eEmulateInstructionOptionAutoAdvancePC;169 170  bool success = false;171 172  uint32_t orig_pc_value = 0;173  if (auto_advance_pc) {174    orig_pc_value =175        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);176    if (!success)177      return false;178  }179 180  // Call the Emulate... function.181  success = (this->*opcode_data->callback)(opcode);182  if (!success)183    return false;184 185  if (auto_advance_pc) {186    uint32_t new_pc_value =187        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);188    if (!success)189      return false;190 191    if (new_pc_value == orig_pc_value) {192      EmulateInstruction::Context context;193      context.type = eContextAdvancePC;194      context.SetNoArgs();195      if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_ppc64le,196                                 orig_pc_value + 4))197        return false;198    }199  }200  return true;201}202 203bool EmulateInstructionPPC64::EmulateMFSPR(uint32_t opcode) {204  uint32_t rt = Bits32(opcode, 25, 21);205  uint32_t spr = Bits32(opcode, 20, 11);206 207  enum { SPR_LR = 0x100 };208 209  // For now, we're only insterested in 'mfspr r0, lr'210  if (rt != gpr_r0_ppc64le || spr != SPR_LR)211    return false;212 213  Log *log = GetLog(LLDBLog::Unwind);214  LLDB_LOG(log, "EmulateMFSPR: {0:X+8}: mfspr r0, lr", m_addr);215 216  bool success;217  uint64_t lr =218      ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);219  if (!success)220    return false;221  Context context;222  context.type = eContextWriteRegisterRandomBits;223  WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_r0_ppc64le, lr);224  LLDB_LOG(log, "EmulateMFSPR: success!");225  return true;226}227 228bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) {229  uint32_t rt = Bits32(opcode, 25, 21);230  uint32_t ra = Bits32(opcode, 20, 16);231  uint32_t ds = Bits32(opcode, 15, 2);232 233  int32_t ids = llvm::SignExtend32<16>(ds << 2);234 235  // For now, tracking only loads from 0(r1) to r1 (0(r1) is the ABI defined236  // location to save previous SP)237  if (ra != gpr_r1_ppc64le || rt != gpr_r1_ppc64le || ids != 0)238    return false;239 240  Log *log = GetLog(LLDBLog::Unwind);241  LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra);242 243  std::optional<RegisterInfo> r1_info =244      GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);245  if (!r1_info)246    return false;247 248  // restore SP249  Context ctx;250  ctx.type = eContextRestoreStackPointer;251  ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);252 253  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, 0);254  LLDB_LOG(log, "EmulateLD: success!");255  return true;256}257 258bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) {259  uint32_t rs = Bits32(opcode, 25, 21);260  uint32_t ra = Bits32(opcode, 20, 16);261  uint32_t ds = Bits32(opcode, 15, 2);262  uint32_t u = Bits32(opcode, 1, 0);263 264  // For now, tracking only stores to r1265  if (ra != gpr_r1_ppc64le)266    return false;267  // ... and only stores of SP, FP and LR (moved into r0 by a previous mfspr)268  if (rs != gpr_r1_ppc64le && rs != gpr_r31_ppc64le && rs != gpr_r30_ppc64le &&269      rs != gpr_r0_ppc64le)270    return false;271 272  bool success;273  uint64_t rs_val = ReadRegisterUnsigned(eRegisterKindLLDB, rs, 0, &success);274  if (!success)275    return false;276 277  int32_t ids = llvm::SignExtend32<16>(ds << 2);278  Log *log = GetLog(LLDBLog::Unwind);279  LLDB_LOG(log, "EmulateSTD: {0:X+8}: std{1} r{2}, {3}(r{4})", m_addr,280           u ? "u" : "", rs, ids, ra);281 282  // Make sure that r0 is really holding LR value (this won't catch unlikely283  // cases, such as r0 being overwritten after mfspr)284  uint32_t rs_num = rs;285  if (rs == gpr_r0_ppc64le) {286    uint64_t lr =287        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);288    if (!success || lr != rs_val)289      return false;290    rs_num = gpr_lr_ppc64le;291  }292 293  // set context294  std::optional<RegisterInfo> rs_info =295      GetRegisterInfo(eRegisterKindLLDB, rs_num);296  if (!rs_info)297    return false;298  std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);299  if (!ra_info)300    return false;301 302  Context ctx;303  ctx.type = eContextPushRegisterOnStack;304  ctx.SetRegisterToRegisterPlusOffset(*rs_info, *ra_info, ids);305 306  // store307  uint64_t ra_val = ReadRegisterUnsigned(eRegisterKindLLDB, ra, 0, &success);308  if (!success)309    return false;310 311  lldb::addr_t addr = ra_val + ids;312  WriteMemory(ctx, addr, &rs_val, sizeof(rs_val));313 314  // update RA?315  if (u) {316    Context ctx;317    // NOTE Currently, RA will always be equal to SP(r1)318    ctx.type = eContextAdjustStackPointer;319    WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, addr);320  }321 322  LLDB_LOG(log, "EmulateSTD: success!");323  return true;324}325 326bool EmulateInstructionPPC64::EmulateOR(uint32_t opcode) {327  uint32_t rs = Bits32(opcode, 25, 21);328  uint32_t ra = Bits32(opcode, 20, 16);329  uint32_t rb = Bits32(opcode, 15, 11);330 331  // to be safe, process only the known 'mr r31/r30, r1' prologue instructions332  if (m_fp != LLDB_INVALID_REGNUM || rs != rb ||333      (ra != gpr_r30_ppc64le && ra != gpr_r31_ppc64le) || rb != gpr_r1_ppc64le)334    return false;335 336  Log *log = GetLog(LLDBLog::Unwind);337  LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb);338 339  // set context340  std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);341  if (!ra_info)342    return false;343 344  Context ctx;345  ctx.type = eContextSetFramePointer;346  ctx.SetRegister(*ra_info);347 348  // move349  bool success;350  uint64_t rb_val = ReadRegisterUnsigned(eRegisterKindLLDB, rb, 0, &success);351  if (!success)352    return false;353  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, rb_val);354  m_fp = ra;355  LLDB_LOG(log, "EmulateOR: success!");356  return true;357}358 359bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) {360  uint32_t rt = Bits32(opcode, 25, 21);361  uint32_t ra = Bits32(opcode, 20, 16);362  uint32_t si = Bits32(opcode, 15, 0);363 364  // handle stack adjustments only365  // (this is a typical epilogue operation, with ra == r1. If it's366  //  something else, then we won't know the correct value of ra)367  if (rt != gpr_r1_ppc64le || ra != gpr_r1_ppc64le)368    return false;369 370  int32_t si_val = llvm::SignExtend32<16>(si);371  Log *log = GetLog(LLDBLog::Unwind);372  LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val);373 374  // set context375  std::optional<RegisterInfo> r1_info =376      GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);377  if (!r1_info)378    return false;379 380  Context ctx;381  ctx.type = eContextRestoreStackPointer;382  ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);383 384  // adjust SP385  bool success;386  uint64_t r1 =387      ReadRegisterUnsigned(eRegisterKindLLDB, gpr_r1_ppc64le, 0, &success);388  if (!success)389    return false;390  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val);391  LLDB_LOG(log, "EmulateADDI: success!");392  return true;393}394