forked from OSchip/llvm-project
[LLDB] Initial version of PPC64 InstEmulation
Summary: Supports common prologue/epilogue instructions. Reviewers: clayborg, labath Reviewed By: clayborg, labath Subscribers: davide, anajuliapc, alexandreyy, lbianc, nemanjai, mgorny, kbarton Differential Revision: https://reviews.llvm.org/D43345 Author: Leandro Lupori <leandro.lupori@gmail.com> llvm-svn: 326224
This commit is contained in:
parent
e3e433b038
commit
a535a7a2a0
|
@ -50,6 +50,7 @@
|
|||
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
|
||||
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
|
||||
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
|
||||
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
|
||||
#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
|
||||
#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
|
||||
#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
|
||||
|
@ -326,6 +327,7 @@ void SystemInitializerFull::Initialize() {
|
|||
UnwindAssemblyInstEmulation::Initialize();
|
||||
UnwindAssembly_x86::Initialize();
|
||||
EmulateInstructionARM64::Initialize();
|
||||
EmulateInstructionPPC64::Initialize();
|
||||
SymbolFileDWARFDebugMap::Initialize();
|
||||
ItaniumABILanguageRuntime::Initialize();
|
||||
AppleObjCRuntimeV2::Initialize();
|
||||
|
@ -451,6 +453,7 @@ void SystemInitializerFull::Terminate() {
|
|||
UnwindAssembly_x86::Terminate();
|
||||
UnwindAssemblyInstEmulation::Terminate();
|
||||
EmulateInstructionARM64::Terminate();
|
||||
EmulateInstructionPPC64::Terminate();
|
||||
SymbolFileDWARFDebugMap::Terminate();
|
||||
ItaniumABILanguageRuntime::Terminate();
|
||||
AppleObjCRuntimeV2::Terminate();
|
||||
|
|
|
@ -2,3 +2,4 @@ add_subdirectory(ARM)
|
|||
add_subdirectory(ARM64)
|
||||
add_subdirectory(MIPS)
|
||||
add_subdirectory(MIPS64)
|
||||
add_subdirectory(PPC64)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
add_lldb_library(lldbPluginInstructionPPC64 PLUGIN
|
||||
EmulateInstructionPPC64.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbInterpreter
|
||||
lldbSymbol
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
|
@ -0,0 +1,406 @@
|
|||
//===-- EmulateInstructionPPC64.cpp ------------------------------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "EmulateInstructionPPC64.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Symbol/UnwindPlan.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
#include "lldb/Utility/ConstString.h"
|
||||
|
||||
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.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;
|
||||
|
||||
EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch)
|
||||
: EmulateInstruction(arch) {}
|
||||
|
||||
void EmulateInstructionPPC64::Initialize() {
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(), CreateInstance);
|
||||
}
|
||||
|
||||
void EmulateInstructionPPC64::Terminate() {
|
||||
PluginManager::UnregisterPlugin(CreateInstance);
|
||||
}
|
||||
|
||||
ConstString EmulateInstructionPPC64::GetPluginNameStatic() {
|
||||
ConstString g_plugin_name("lldb.emulate-instruction.ppc64");
|
||||
return g_plugin_name;
|
||||
}
|
||||
|
||||
ConstString EmulateInstructionPPC64::GetPluginName() {
|
||||
static ConstString g_plugin_name("EmulateInstructionPPC64");
|
||||
return g_plugin_name;
|
||||
}
|
||||
|
||||
const char *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().getArch() == llvm::Triple::ppc64 ||
|
||||
arch.GetTriple().getArch() == llvm::Triple::ppc64le) {
|
||||
return new EmulateInstructionPPC64(arch);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) {
|
||||
if (arch.GetTriple().getArch() == llvm::Triple::ppc64)
|
||||
return true;
|
||||
else if (arch.GetTriple().getArch() == llvm::Triple::ppc64le)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LLDBTableGetRegisterInfo(uint32_t reg_num, RegisterInfo ®_info) {
|
||||
if (reg_num >= llvm::array_lengthof(g_register_infos_ppc64le))
|
||||
return false;
|
||||
reg_info = g_register_infos_ppc64le[reg_num];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind,
|
||||
uint32_t reg_num,
|
||||
RegisterInfo ®_info) {
|
||||
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 false;
|
||||
}
|
||||
}
|
||||
|
||||
if (reg_kind == eRegisterKindLLDB)
|
||||
return LLDBTableGetRegisterInfo(reg_num, reg_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
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.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 = llvm::array_lengthof(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 (auto_advance_pc && (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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
|
||||
LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra);
|
||||
|
||||
RegisterInfo r1_info;
|
||||
if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, 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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_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
|
||||
RegisterInfo rs_info;
|
||||
if (!GetRegisterInfo(eRegisterKindLLDB, rs_num, rs_info))
|
||||
return false;
|
||||
RegisterInfo ra_info;
|
||||
if (!GetRegisterInfo(eRegisterKindLLDB, ra, 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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
|
||||
LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb);
|
||||
|
||||
// set context
|
||||
RegisterInfo ra_info;
|
||||
if (!GetRegisterInfo(eRegisterKindLLDB, ra, 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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
|
||||
LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val);
|
||||
|
||||
// set context
|
||||
RegisterInfo r1_info;
|
||||
if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, 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;
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
//===-- EmulateInstructionPPC64.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef EmulateInstructionPPC64_h_
|
||||
#define EmulateInstructionPPC64_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/EmulateInstruction.h"
|
||||
#include "lldb/Interpreter/OptionValue.h"
|
||||
#include "lldb/Utility/Log.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class EmulateInstructionPPC64 : public EmulateInstruction {
|
||||
public:
|
||||
EmulateInstructionPPC64(const ArchSpec &arch);
|
||||
|
||||
static void Initialize();
|
||||
|
||||
static void Terminate();
|
||||
|
||||
static ConstString GetPluginNameStatic();
|
||||
|
||||
static const char *GetPluginDescriptionStatic();
|
||||
|
||||
static EmulateInstruction *CreateInstance(const ArchSpec &arch,
|
||||
InstructionType inst_type);
|
||||
|
||||
static bool
|
||||
SupportsEmulatingInstructionsOfTypeStatic(InstructionType inst_type) {
|
||||
switch (inst_type) {
|
||||
case eInstructionTypeAny:
|
||||
case eInstructionTypePrologueEpilogue:
|
||||
return true;
|
||||
|
||||
case eInstructionTypePCModifying:
|
||||
case eInstructionTypeAll:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstString GetPluginName() override;
|
||||
|
||||
uint32_t GetPluginVersion() override { return 1; }
|
||||
|
||||
bool SetTargetTriple(const ArchSpec &arch) override;
|
||||
|
||||
bool SupportsEmulatingInstructionsOfType(InstructionType inst_type) override {
|
||||
return SupportsEmulatingInstructionsOfTypeStatic(inst_type);
|
||||
}
|
||||
|
||||
bool ReadInstruction() override;
|
||||
|
||||
bool EvaluateInstruction(uint32_t evaluate_options) override;
|
||||
|
||||
bool TestEmulation(Stream *out_stream, ArchSpec &arch,
|
||||
OptionValueDictionary *test_data) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num,
|
||||
RegisterInfo ®_info) override;
|
||||
|
||||
bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) override;
|
||||
|
||||
private:
|
||||
struct Opcode {
|
||||
uint32_t mask;
|
||||
uint32_t value;
|
||||
bool (EmulateInstructionPPC64::*callback)(uint32_t opcode);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
uint32_t m_fp = LLDB_INVALID_REGNUM;
|
||||
|
||||
Opcode *GetOpcodeForInstruction(uint32_t opcode);
|
||||
|
||||
bool EmulateMFSPR(uint32_t opcode);
|
||||
bool EmulateLD(uint32_t opcode);
|
||||
bool EmulateSTD(uint32_t opcode);
|
||||
bool EmulateOR(uint32_t opcode);
|
||||
bool EmulateADDI(uint32_t opcode);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // EmulateInstructionPPC64_h_
|
|
@ -40,6 +40,7 @@
|
|||
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
|
||||
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
|
||||
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
|
||||
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
|
||||
#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
|
||||
#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
|
||||
#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
|
||||
|
@ -180,6 +181,7 @@ void SystemInitializerTest::Initialize() {
|
|||
UnwindAssemblyInstEmulation::Initialize();
|
||||
UnwindAssembly_x86::Initialize();
|
||||
EmulateInstructionARM64::Initialize();
|
||||
EmulateInstructionPPC64::Initialize();
|
||||
SymbolFileDWARFDebugMap::Initialize();
|
||||
ItaniumABILanguageRuntime::Initialize();
|
||||
AppleObjCRuntimeV2::Initialize();
|
||||
|
@ -283,6 +285,7 @@ void SystemInitializerTest::Terminate() {
|
|||
UnwindAssembly_x86::Terminate();
|
||||
UnwindAssemblyInstEmulation::Terminate();
|
||||
EmulateInstructionARM64::Terminate();
|
||||
EmulateInstructionPPC64::Terminate();
|
||||
SymbolFileDWARFDebugMap::Terminate();
|
||||
ItaniumABILanguageRuntime::Terminate();
|
||||
AppleObjCRuntimeV2::Terminate();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
add_lldb_unittest(Arm64InstEmulationTests
|
||||
TestArm64InstEmulation.cpp
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbPluginUnwindAssemblyInstEmulation
|
||||
lldbPluginDisassemblerLLVM
|
||||
lldbPluginInstructionARM64
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
${LLVM_TARGETS_TO_BUILD})
|
|
@ -1,5 +1,11 @@
|
|||
if ("AArch64" IN_LIST LLVM_TARGETS_TO_BUILD)
|
||||
add_subdirectory(ARM64)
|
||||
endif()
|
||||
|
||||
if ("PowerPC" IN_LIST LLVM_TARGETS_TO_BUILD)
|
||||
add_subdirectory(PPC64)
|
||||
endif()
|
||||
|
||||
if ("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
|
||||
add_subdirectory(x86)
|
||||
endif()
|
||||
|
||||
add_subdirectory(InstEmulation)
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
if ("AArch64" IN_LIST LLVM_TARGETS_TO_BUILD)
|
||||
add_lldb_unittest(InstEmulationTests
|
||||
TestArm64InstEmulation.cpp
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbPluginUnwindAssemblyInstEmulation
|
||||
lldbPluginDisassemblerLLVM
|
||||
lldbPluginInstructionARM64
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
${LLVM_TARGETS_TO_BUILD})
|
||||
endif()
|
|
@ -0,0 +1,13 @@
|
|||
add_lldb_unittest(PPC64InstEmulationTests
|
||||
TestPPC64InstEmulation.cpp
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbPluginUnwindAssemblyInstEmulation
|
||||
lldbPluginDisassemblerLLVM
|
||||
lldbPluginInstructionPPC64
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
${LLVM_TARGETS_TO_BUILD})
|
|
@ -0,0 +1,259 @@
|
|||
//===-- TestPPC64InstEmulation.cpp ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
|
||||
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/AddressRange.h"
|
||||
#include "lldb/Symbol/UnwindPlan.h"
|
||||
#include "lldb/Target/UnwindAssembly.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
|
||||
#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
|
||||
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
|
||||
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
class TestPPC64InstEmulation : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
// virtual void SetUp() override { }
|
||||
// virtual void TearDown() override { }
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
void TestPPC64InstEmulation::SetUpTestCase() {
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllDisassemblers();
|
||||
DisassemblerLLVMC::Initialize();
|
||||
EmulateInstructionPPC64::Initialize();
|
||||
}
|
||||
|
||||
void TestPPC64InstEmulation::TearDownTestCase() {
|
||||
DisassemblerLLVMC::Terminate();
|
||||
EmulateInstructionPPC64::Terminate();
|
||||
}
|
||||
|
||||
TEST_F(TestPPC64InstEmulation, TestSimpleFunction) {
|
||||
ArchSpec arch("powerpc64le-linux-gnu");
|
||||
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
||||
static_cast<UnwindAssemblyInstEmulation *>(
|
||||
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
||||
ASSERT_NE(nullptr, engine);
|
||||
|
||||
UnwindPlan::RowSP row_sp;
|
||||
AddressRange sample_range;
|
||||
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
||||
UnwindPlan::Row::RegisterLocation regloc;
|
||||
|
||||
// prologue and epilogue of:
|
||||
// int main() {
|
||||
// int i = test();
|
||||
// return i;
|
||||
// }
|
||||
//
|
||||
// compiled with clang -O0 -g
|
||||
uint8_t data[] = {
|
||||
// prologue
|
||||
0x02, 0x10, 0x40, 0x3c, // 0: lis r2, 4098
|
||||
0x00, 0x7f, 0x42, 0x38, // 4: addi r2, r2, 32512
|
||||
0xa6, 0x02, 0x08, 0x7c, // 8: mflr r0
|
||||
0xf8, 0xff, 0xe1, 0xfb, // 12: std r31, -8(r1)
|
||||
0x10, 0x00, 0x01, 0xf8, // 16: std r0, 16(r1)
|
||||
0x91, 0xff, 0x21, 0xf8, // 20: stdu r1, -112(r1)
|
||||
0x78, 0x0b, 0x3f, 0x7c, // 24: mr r31, r1
|
||||
0x00, 0x00, 0x60, 0x38, // 28: li r3, 0
|
||||
0x64, 0x00, 0x7f, 0x90, // 32: stw r3, 100(r31)
|
||||
|
||||
// epilogue
|
||||
0x70, 0x00, 0x21, 0x38, // 36: addi r1, r1, 112
|
||||
0x10, 0x00, 0x01, 0xe8, // 40: ld r0, 16(r1)
|
||||
0xf8, 0xff, 0xe1, 0xeb, // 44: ld r31, -8(r1)
|
||||
0xa6, 0x03, 0x08, 0x7c, // 48: mtlr r0
|
||||
0x20, 0x00, 0x80, 0x4e // 52: blr
|
||||
};
|
||||
|
||||
sample_range = AddressRange(0x1000, sizeof(data));
|
||||
|
||||
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
||||
sample_range, data, sizeof(data), unwind_plan));
|
||||
|
||||
// 0: CFA=sp+0
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(0);
|
||||
EXPECT_EQ(0ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
// 1: CFA=sp+0 => fp=[CFA-8]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(16);
|
||||
EXPECT_EQ(16ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(-8, regloc.GetOffset());
|
||||
|
||||
// 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(20);
|
||||
EXPECT_EQ(20ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(16, regloc.GetOffset());
|
||||
|
||||
// 3: CFA=sp+112 => fp=[CFA-8] lr=[CFA+16]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(24);
|
||||
EXPECT_EQ(24ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(-8, regloc.GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(16, regloc.GetOffset());
|
||||
|
||||
// 4: CFA=r31+112 => fp=[CFA-8] lr=[CFA+16]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(28);
|
||||
EXPECT_EQ(28ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r31_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(-8, regloc.GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(16, regloc.GetOffset());
|
||||
|
||||
// 5: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(40);
|
||||
EXPECT_EQ(40ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(-8, regloc.GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(16, regloc.GetOffset());
|
||||
}
|
||||
|
||||
TEST_F(TestPPC64InstEmulation, TestMediumFunction) {
|
||||
ArchSpec arch("powerpc64le-linux-gnu");
|
||||
std::unique_ptr<UnwindAssemblyInstEmulation> engine(
|
||||
static_cast<UnwindAssemblyInstEmulation *>(
|
||||
UnwindAssemblyInstEmulation::CreateInstance(arch)));
|
||||
ASSERT_NE(nullptr, engine);
|
||||
|
||||
UnwindPlan::RowSP row_sp;
|
||||
AddressRange sample_range;
|
||||
UnwindPlan unwind_plan(eRegisterKindLLDB);
|
||||
UnwindPlan::Row::RegisterLocation regloc;
|
||||
|
||||
// prologue and epilogue of main() (call-func.c),
|
||||
// with several calls and stack variables.
|
||||
//
|
||||
// compiled with clang -O0 -g
|
||||
uint8_t data[] = {
|
||||
// prologue
|
||||
0xa6, 0x02, 0x08, 0x7c, // 0: mflr r0
|
||||
0xf8, 0xff, 0xe1, 0xfb, // 4: std r31, -8(r1)
|
||||
0x10, 0x00, 0x01, 0xf8, // 8: std r0, 16(r1)
|
||||
0x78, 0x0b, 0x3e, 0x7c, // 12: mr r30, r1
|
||||
0xe0, 0x06, 0x20, 0x78, // 16: clrldi r0, r1, 59
|
||||
0xa0, 0xfa, 0x00, 0x20, // 20: subfic r0, r0, -1376
|
||||
0x6a, 0x01, 0x21, 0x7c, // 24: stdux r1, r1, r0
|
||||
0x78, 0x0b, 0x3f, 0x7c, // 28: mr r31, r1
|
||||
|
||||
// epilogue
|
||||
0x00, 0x00, 0x21, 0xe8, // 32: ld r1, 0(r1)
|
||||
0x20, 0x00, 0x80, 0x4e // 36: blr
|
||||
};
|
||||
|
||||
sample_range = AddressRange(0x1000, sizeof(data));
|
||||
|
||||
EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
|
||||
sample_range, data, sizeof(data), unwind_plan));
|
||||
|
||||
// 0: CFA=sp+0
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(0);
|
||||
EXPECT_EQ(0ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
// 1: CFA=sp+0 => fp=[CFA-8]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(8);
|
||||
EXPECT_EQ(8ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(-8, regloc.GetOffset());
|
||||
|
||||
// 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(12);
|
||||
EXPECT_EQ(12ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
|
||||
EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
|
||||
EXPECT_EQ(16, regloc.GetOffset());
|
||||
|
||||
// 3: CFA=r30
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(16);
|
||||
EXPECT_EQ(16ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(32);
|
||||
EXPECT_EQ(16ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
|
||||
// 4: CFA=sp+0
|
||||
row_sp = unwind_plan.GetRowForFunctionOffset(36);
|
||||
EXPECT_EQ(36ull, row_sp->GetOffset());
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
|
||||
EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
|
||||
EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
|
||||
}
|
Loading…
Reference in New Issue