Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
39648 views
//===-- EmulateInstructionPPC64.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 "EmulateInstructionPPC64.h"910#include <cstdlib>11#include <optional>1213#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"14#include "lldb/Core/PluginManager.h"15#include "lldb/Symbol/UnwindPlan.h"16#include "lldb/Utility/ArchSpec.h"17#include "lldb/Utility/ConstString.h"18#include "lldb/Utility/LLDBLog.h"1920#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT21#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"2223#include "Plugins/Process/Utility/InstructionUtils.h"2425using namespace lldb;26using namespace lldb_private;2728LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionPPC64, InstructionPPC64)2930EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch)31: EmulateInstruction(arch) {}3233void EmulateInstructionPPC64::Initialize() {34PluginManager::RegisterPlugin(GetPluginNameStatic(),35GetPluginDescriptionStatic(), CreateInstance);36}3738void EmulateInstructionPPC64::Terminate() {39PluginManager::UnregisterPlugin(CreateInstance);40}4142llvm::StringRef EmulateInstructionPPC64::GetPluginDescriptionStatic() {43return "Emulate instructions for the PPC64 architecture.";44}4546EmulateInstruction *47EmulateInstructionPPC64::CreateInstance(const ArchSpec &arch,48InstructionType inst_type) {49if (EmulateInstructionPPC64::SupportsEmulatingInstructionsOfTypeStatic(50inst_type))51if (arch.GetTriple().isPPC64())52return new EmulateInstructionPPC64(arch);5354return nullptr;55}5657bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) {58return arch.GetTriple().isPPC64();59}6061static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {62if (reg_num >= std::size(g_register_infos_ppc64le))63return {};64return g_register_infos_ppc64le[reg_num];65}6667std::optional<RegisterInfo>68EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind,69uint32_t reg_num) {70if (reg_kind == eRegisterKindGeneric) {71switch (reg_num) {72case LLDB_REGNUM_GENERIC_PC:73reg_kind = eRegisterKindLLDB;74reg_num = gpr_pc_ppc64le;75break;76case LLDB_REGNUM_GENERIC_SP:77reg_kind = eRegisterKindLLDB;78reg_num = gpr_r1_ppc64le;79break;80case LLDB_REGNUM_GENERIC_RA:81reg_kind = eRegisterKindLLDB;82reg_num = gpr_lr_ppc64le;83break;84case LLDB_REGNUM_GENERIC_FLAGS:85reg_kind = eRegisterKindLLDB;86reg_num = gpr_cr_ppc64le;87break;8889default:90return {};91}92}9394if (reg_kind == eRegisterKindLLDB)95return LLDBTableGetRegisterInfo(reg_num);96return {};97}9899bool EmulateInstructionPPC64::ReadInstruction() {100bool success = false;101m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,102LLDB_INVALID_ADDRESS, &success);103if (success) {104Context ctx;105ctx.type = eContextReadOpcode;106ctx.SetNoArgs();107m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success),108GetByteOrder());109}110if (!success)111m_addr = LLDB_INVALID_ADDRESS;112return success;113}114115bool EmulateInstructionPPC64::CreateFunctionEntryUnwind(116UnwindPlan &unwind_plan) {117unwind_plan.Clear();118unwind_plan.SetRegisterKind(eRegisterKindLLDB);119120UnwindPlan::RowSP row(new UnwindPlan::Row);121122// Our previous Call Frame Address is the stack pointer123row->GetCFAValue().SetIsRegisterPlusOffset(gpr_r1_ppc64le, 0);124125unwind_plan.AppendRow(row);126unwind_plan.SetSourceName("EmulateInstructionPPC64");127unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);128unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);129unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);130unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le);131return true;132}133134EmulateInstructionPPC64::Opcode *135EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) {136static EmulateInstructionPPC64::Opcode g_opcodes[] = {137{0xfc0007ff, 0x7c0002a6, &EmulateInstructionPPC64::EmulateMFSPR,138"mfspr RT, SPR"},139{0xfc000003, 0xf8000000, &EmulateInstructionPPC64::EmulateSTD,140"std RS, DS(RA)"},141{0xfc000003, 0xf8000001, &EmulateInstructionPPC64::EmulateSTD,142"stdu RS, DS(RA)"},143{0xfc0007fe, 0x7c000378, &EmulateInstructionPPC64::EmulateOR,144"or RA, RS, RB"},145{0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI,146"addi RT, RA, SI"},147{0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD,148"ld RT, DS(RA)"}};149static const size_t k_num_ppc_opcodes = std::size(g_opcodes);150151for (size_t i = 0; i < k_num_ppc_opcodes; ++i) {152if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)153return &g_opcodes[i];154}155return nullptr;156}157158bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) {159const uint32_t opcode = m_opcode.GetOpcode32();160// LLDB_LOG(log, "PPC64::EvaluateInstruction: opcode={0:X+8}", opcode);161Opcode *opcode_data = GetOpcodeForInstruction(opcode);162if (!opcode_data)163return false;164165// LLDB_LOG(log, "PPC64::EvaluateInstruction: {0}", opcode_data->name);166const bool auto_advance_pc =167evaluate_options & eEmulateInstructionOptionAutoAdvancePC;168169bool success = false;170171uint32_t orig_pc_value = 0;172if (auto_advance_pc) {173orig_pc_value =174ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);175if (!success)176return false;177}178179// Call the Emulate... function.180success = (this->*opcode_data->callback)(opcode);181if (!success)182return false;183184if (auto_advance_pc) {185uint32_t new_pc_value =186ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);187if (!success)188return false;189190if (new_pc_value == orig_pc_value) {191EmulateInstruction::Context context;192context.type = eContextAdvancePC;193context.SetNoArgs();194if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_ppc64le,195orig_pc_value + 4))196return false;197}198}199return true;200}201202bool EmulateInstructionPPC64::EmulateMFSPR(uint32_t opcode) {203uint32_t rt = Bits32(opcode, 25, 21);204uint32_t spr = Bits32(opcode, 20, 11);205206enum { SPR_LR = 0x100 };207208// For now, we're only insterested in 'mfspr r0, lr'209if (rt != gpr_r0_ppc64le || spr != SPR_LR)210return false;211212Log *log = GetLog(LLDBLog::Unwind);213LLDB_LOG(log, "EmulateMFSPR: {0:X+8}: mfspr r0, lr", m_addr);214215bool success;216uint64_t lr =217ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);218if (!success)219return false;220Context context;221context.type = eContextWriteRegisterRandomBits;222WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_r0_ppc64le, lr);223LLDB_LOG(log, "EmulateMFSPR: success!");224return true;225}226227bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) {228uint32_t rt = Bits32(opcode, 25, 21);229uint32_t ra = Bits32(opcode, 20, 16);230uint32_t ds = Bits32(opcode, 15, 2);231232int32_t ids = llvm::SignExtend32<16>(ds << 2);233234// For now, tracking only loads from 0(r1) to r1 (0(r1) is the ABI defined235// location to save previous SP)236if (ra != gpr_r1_ppc64le || rt != gpr_r1_ppc64le || ids != 0)237return false;238239Log *log = GetLog(LLDBLog::Unwind);240LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra);241242std::optional<RegisterInfo> r1_info =243GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);244if (!r1_info)245return false;246247// restore SP248Context ctx;249ctx.type = eContextRestoreStackPointer;250ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);251252WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, 0);253LLDB_LOG(log, "EmulateLD: success!");254return true;255}256257bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) {258uint32_t rs = Bits32(opcode, 25, 21);259uint32_t ra = Bits32(opcode, 20, 16);260uint32_t ds = Bits32(opcode, 15, 2);261uint32_t u = Bits32(opcode, 1, 0);262263// For now, tracking only stores to r1264if (ra != gpr_r1_ppc64le)265return false;266// ... and only stores of SP, FP and LR (moved into r0 by a previous mfspr)267if (rs != gpr_r1_ppc64le && rs != gpr_r31_ppc64le && rs != gpr_r30_ppc64le &&268rs != gpr_r0_ppc64le)269return false;270271bool success;272uint64_t rs_val = ReadRegisterUnsigned(eRegisterKindLLDB, rs, 0, &success);273if (!success)274return false;275276int32_t ids = llvm::SignExtend32<16>(ds << 2);277Log *log = GetLog(LLDBLog::Unwind);278LLDB_LOG(log, "EmulateSTD: {0:X+8}: std{1} r{2}, {3}(r{4})", m_addr,279u ? "u" : "", rs, ids, ra);280281// Make sure that r0 is really holding LR value (this won't catch unlikely282// cases, such as r0 being overwritten after mfspr)283uint32_t rs_num = rs;284if (rs == gpr_r0_ppc64le) {285uint64_t lr =286ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);287if (!success || lr != rs_val)288return false;289rs_num = gpr_lr_ppc64le;290}291292// set context293std::optional<RegisterInfo> rs_info =294GetRegisterInfo(eRegisterKindLLDB, rs_num);295if (!rs_info)296return false;297std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);298if (!ra_info)299return false;300301Context ctx;302ctx.type = eContextPushRegisterOnStack;303ctx.SetRegisterToRegisterPlusOffset(*rs_info, *ra_info, ids);304305// store306uint64_t ra_val = ReadRegisterUnsigned(eRegisterKindLLDB, ra, 0, &success);307if (!success)308return false;309310lldb::addr_t addr = ra_val + ids;311WriteMemory(ctx, addr, &rs_val, sizeof(rs_val));312313// update RA?314if (u) {315Context ctx;316// NOTE Currently, RA will always be equal to SP(r1)317ctx.type = eContextAdjustStackPointer;318WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, addr);319}320321LLDB_LOG(log, "EmulateSTD: success!");322return true;323}324325bool EmulateInstructionPPC64::EmulateOR(uint32_t opcode) {326uint32_t rs = Bits32(opcode, 25, 21);327uint32_t ra = Bits32(opcode, 20, 16);328uint32_t rb = Bits32(opcode, 15, 11);329330// to be safe, process only the known 'mr r31/r30, r1' prologue instructions331if (m_fp != LLDB_INVALID_REGNUM || rs != rb ||332(ra != gpr_r30_ppc64le && ra != gpr_r31_ppc64le) || rb != gpr_r1_ppc64le)333return false;334335Log *log = GetLog(LLDBLog::Unwind);336LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb);337338// set context339std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);340if (!ra_info)341return false;342343Context ctx;344ctx.type = eContextSetFramePointer;345ctx.SetRegister(*ra_info);346347// move348bool success;349uint64_t rb_val = ReadRegisterUnsigned(eRegisterKindLLDB, rb, 0, &success);350if (!success)351return false;352WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, rb_val);353m_fp = ra;354LLDB_LOG(log, "EmulateOR: success!");355return true;356}357358bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) {359uint32_t rt = Bits32(opcode, 25, 21);360uint32_t ra = Bits32(opcode, 20, 16);361uint32_t si = Bits32(opcode, 15, 0);362363// handle stack adjustments only364// (this is a typical epilogue operation, with ra == r1. If it's365// something else, then we won't know the correct value of ra)366if (rt != gpr_r1_ppc64le || ra != gpr_r1_ppc64le)367return false;368369int32_t si_val = llvm::SignExtend32<16>(si);370Log *log = GetLog(LLDBLog::Unwind);371LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val);372373// set context374std::optional<RegisterInfo> r1_info =375GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);376if (!r1_info)377return false;378379Context ctx;380ctx.type = eContextRestoreStackPointer;381ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);382383// adjust SP384bool success;385uint64_t r1 =386ReadRegisterUnsigned(eRegisterKindLLDB, gpr_r1_ppc64le, 0, &success);387if (!success)388return false;389WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val);390LLDB_LOG(log, "EmulateADDI: success!");391return true;392}393394395