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