summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/API/SystemInitializerFull.cpp3
-rw-r--r--lldb/source/Plugins/Instruction/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Instruction/PPC64/CMakeLists.txt11
-rw-r--r--lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp406
-rw-r--r--lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h97
-rw-r--r--lldb/tools/lldb-test/SystemInitializerTest.cpp3
-rw-r--r--lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt13
-rw-r--r--lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp (renamed from lldb/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp)0
-rw-r--r--lldb/unittests/UnwindAssembly/CMakeLists.txt10
-rw-r--r--lldb/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt15
-rw-r--r--lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt13
-rw-r--r--lldb/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp259
12 files changed, 814 insertions, 17 deletions
diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp
index 977ebe62353..a27b649a519 100644
--- a/lldb/source/API/SystemInitializerFull.cpp
+++ b/lldb/source/API/SystemInitializerFull.cpp
@@ -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();
diff --git a/lldb/source/Plugins/Instruction/CMakeLists.txt b/lldb/source/Plugins/Instruction/CMakeLists.txt
index 78f2f64cf1a..89771e8f46d 100644
--- a/lldb/source/Plugins/Instruction/CMakeLists.txt
+++ b/lldb/source/Plugins/Instruction/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(ARM)
add_subdirectory(ARM64)
add_subdirectory(MIPS)
add_subdirectory(MIPS64)
+add_subdirectory(PPC64)
diff --git a/lldb/source/Plugins/Instruction/PPC64/CMakeLists.txt b/lldb/source/Plugins/Instruction/PPC64/CMakeLists.txt
new file mode 100644
index 00000000000..0926433fc77
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/PPC64/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginInstructionPPC64 PLUGIN
+ EmulateInstructionPPC64.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbInterpreter
+ lldbSymbol
+ lldbPluginProcessUtility
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
new file mode 100644
index 00000000000..807fc5ce9e2
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
@@ -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 &reg_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 &reg_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;
+}
diff --git a/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
new file mode 100644
index 00000000000..be65de9a506
--- /dev/null
+++ b/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
@@ -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 &reg_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_
diff --git a/lldb/tools/lldb-test/SystemInitializerTest.cpp b/lldb/tools/lldb-test/SystemInitializerTest.cpp
index cae395e133e..a58be5cd6ca 100644
--- a/lldb/tools/lldb-test/SystemInitializerTest.cpp
+++ b/lldb/tools/lldb-test/SystemInitializerTest.cpp
@@ -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();
diff --git a/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt b/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt
new file mode 100644
index 00000000000..77924792fe5
--- /dev/null
+++ b/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt
@@ -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})
diff --git a/lldb/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp
index 7831a6534fd..7831a6534fd 100644
--- a/lldb/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
+++ b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp
diff --git a/lldb/unittests/UnwindAssembly/CMakeLists.txt b/lldb/unittests/UnwindAssembly/CMakeLists.txt
index 0326011fda8..136fcd9ae97 100644
--- a/lldb/unittests/UnwindAssembly/CMakeLists.txt
+++ b/lldb/unittests/UnwindAssembly/CMakeLists.txt
@@ -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)
diff --git a/lldb/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt b/lldb/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
deleted file mode 100644
index 7cc0befa386..00000000000
--- a/lldb/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
+++ /dev/null
@@ -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()
diff --git a/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt b/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt
new file mode 100644
index 00000000000..d803f459363
--- /dev/null
+++ b/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt
@@ -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})
diff --git a/lldb/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp b/lldb/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp
new file mode 100644
index 00000000000..2318540870f
--- /dev/null
+++ b/lldb/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp
@@ -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());
+}
OpenPOWER on IntegriCloud