[Lldb-commits] [lldb] r326224 - [LLDB] Initial version of PPC64 InstEmulation

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Tue Feb 27 10:42:46 PST 2018


Author: labath
Date: Tue Feb 27 10:42:46 2018
New Revision: 326224

URL: http://llvm.org/viewvc/llvm-project?rev=326224&view=rev
Log:
[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 at gmail.com>

Added:
    lldb/trunk/source/Plugins/Instruction/PPC64/
    lldb/trunk/source/Plugins/Instruction/PPC64/CMakeLists.txt
    lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
    lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
    lldb/trunk/unittests/UnwindAssembly/ARM64/
    lldb/trunk/unittests/UnwindAssembly/ARM64/CMakeLists.txt
    lldb/trunk/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp
      - copied, changed from r326218, lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
    lldb/trunk/unittests/UnwindAssembly/PPC64/
    lldb/trunk/unittests/UnwindAssembly/PPC64/CMakeLists.txt
    lldb/trunk/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp
Removed:
    lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
    lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
Modified:
    lldb/trunk/source/API/SystemInitializerFull.cpp
    lldb/trunk/source/Plugins/Instruction/CMakeLists.txt
    lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp
    lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt

Modified: lldb/trunk/source/API/SystemInitializerFull.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SystemInitializerFull.cpp?rev=326224&r1=326223&r2=326224&view=diff
==============================================================================
--- lldb/trunk/source/API/SystemInitializerFull.cpp (original)
+++ lldb/trunk/source/API/SystemInitializerFull.cpp Tue Feb 27 10:42:46 2018
@@ -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();

Modified: lldb/trunk/source/Plugins/Instruction/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/CMakeLists.txt?rev=326224&r1=326223&r2=326224&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Instruction/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Instruction/CMakeLists.txt Tue Feb 27 10:42:46 2018
@@ -2,3 +2,4 @@ add_subdirectory(ARM)
 add_subdirectory(ARM64)
 add_subdirectory(MIPS)
 add_subdirectory(MIPS64)
+add_subdirectory(PPC64)

Added: lldb/trunk/source/Plugins/Instruction/PPC64/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/PPC64/CMakeLists.txt?rev=326224&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Instruction/PPC64/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/Instruction/PPC64/CMakeLists.txt Tue Feb 27 10:42:46 2018
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginInstructionPPC64 PLUGIN
+  EmulateInstructionPPC64.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbInterpreter
+    lldbSymbol
+    lldbPluginProcessUtility
+  LINK_COMPONENTS
+    Support
+  )

Added: lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp?rev=326224&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp (added)
+++ lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp Tue Feb 27 10:42:46 2018
@@ -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;
+}

Added: lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h?rev=326224&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h (added)
+++ lldb/trunk/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.h Tue Feb 27 10:42:46 2018
@@ -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_

Modified: lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp?rev=326224&r1=326223&r2=326224&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp (original)
+++ lldb/trunk/tools/lldb-test/SystemInitializerTest.cpp Tue Feb 27 10:42:46 2018
@@ -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();

Added: lldb/trunk/unittests/UnwindAssembly/ARM64/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/ARM64/CMakeLists.txt?rev=326224&view=auto
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/ARM64/CMakeLists.txt (added)
+++ lldb/trunk/unittests/UnwindAssembly/ARM64/CMakeLists.txt Tue Feb 27 10:42:46 2018
@@ -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})

Copied: lldb/trunk/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp (from r326218, lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp)
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp?p2=lldb/trunk/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp&p1=lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp&r1=326218&r2=326224&rev=326224&view=diff
==============================================================================
    (empty)

Modified: lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt?rev=326224&r1=326223&r2=326224&view=diff
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt (original)
+++ lldb/trunk/unittests/UnwindAssembly/CMakeLists.txt Tue Feb 27 10:42:46 2018
@@ -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)

Removed: lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt?rev=326223&view=auto
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt (original)
+++ lldb/trunk/unittests/UnwindAssembly/InstEmulation/CMakeLists.txt (removed)
@@ -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()

Removed: lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp?rev=326223&view=auto
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp (original)
+++ lldb/trunk/unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp (removed)
@@ -1,672 +0,0 @@
-//===-- TestArm64InstEmulation.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/ARM64/EmulateInstructionARM64.h"
-#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestArm64InstEmulation : public testing::Test {
-public:
-  static void SetUpTestCase();
-  static void TearDownTestCase();
-
-  //  virtual void SetUp() override { }
-  //  virtual void TearDown() override { }
-
-protected:
-};
-
-void TestArm64InstEmulation::SetUpTestCase() {
-  llvm::InitializeAllTargets();
-  llvm::InitializeAllAsmPrinters();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllDisassemblers();
-  DisassemblerLLVMC::Initialize();
-  EmulateInstructionARM64::Initialize();
-}
-
-void TestArm64InstEmulation::TearDownTestCase() {
-  DisassemblerLLVMC::Terminate();
-  EmulateInstructionARM64::Terminate();
-}
-
-TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {
-  ArchSpec arch("arm64-apple-ios10");
-  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;
-
-  // 'int main() { }' compiled for arm64-apple-ios with clang
-  uint8_t data[] = {
-      0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd :  stp x29, x30, [sp, #-0x10]!
-      0xfd, 0x03, 0x00, 0x91, // 0x910003fd :  mov x29, sp
-      0xff, 0x43, 0x00, 0xd1, // 0xd10043ff :  sub sp, sp, #0x10
-
-      0xbf, 0x03, 0x00, 0x91, // 0x910003bf :  mov sp, x29
-      0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd :  ldp x29, x30, [sp], #16
-      0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 :  ret
-  };
-
-  // UnwindPlan we expect:
-
-  // row[0]:    0: CFA=sp +0 =>
-  // row[1]:    4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
-  // row[2]:    8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
-  // row[2]:   16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
-  // row[3]:   20: CFA=sp +0 => fp= <same> lr= <same>
-
-  sample_range = AddressRange(0x1000, sizeof(data));
-
-  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
-      sample_range, data, sizeof(data), unwind_plan));
-
-  // CFA=sp +0
-  row_sp = unwind_plan.GetRowForFunctionOffset(0);
-  EXPECT_EQ(0ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(4);
-  EXPECT_EQ(4ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-16, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-8, regloc.GetOffset());
-
-  // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(8);
-  EXPECT_EQ(8ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-16, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-8, regloc.GetOffset());
-
-  // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(16);
-  EXPECT_EQ(16ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-16, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-8, regloc.GetOffset());
-
-  // CFA=sp +0 => fp= <same> lr= <same>
-  row_sp = unwind_plan.GetRowForFunctionOffset(20);
-  EXPECT_EQ(20ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
-  ArchSpec arch("arm64-apple-ios10");
-  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;
-
-  // disassembly of -[NSPlaceholderString initWithBytes:length:encoding:]
-  // from Foundation for iOS.
-  uint8_t data[] = {
-      0xf6, 0x57, 0xbd, 0xa9, // 0:  0xa9bd57f6 stp x22, x21, [sp, #-48]!
-      0xf4, 0x4f, 0x01, 0xa9, // 4:  0xa9014ff4 stp x20, x19, [sp, #16]
-      0xfd, 0x7b, 0x02, 0xa9, // 8:  0xa9027bfd stp x29, x30, [sp, #32]
-      0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32
-      0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16
-
-      // [... function body ...]
-      0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
-
-      0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32
-      0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32]
-      0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16]
-      0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48
-      0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b   0x18f640524 ; symbol stub
-                              // for: CFStringCreateWithBytes
-  };
-
-  // UnwindPlan we expect:
-  //  0: CFA=sp +0 =>
-  //  4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
-  //  8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-  // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-
-  // [... function body ...]
-
-  // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-  // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
-  // <same> lr= <same>
-  // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
-  // <same> lr= <same>
-  // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
-  // lr= <same>
-
-  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_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
-  row_sp = unwind_plan.GetRowForFunctionOffset(4);
-  EXPECT_EQ(4ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-40, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-48, regloc.GetOffset());
-
-  // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  row_sp = unwind_plan.GetRowForFunctionOffset(8);
-  EXPECT_EQ(8ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-24, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-32, regloc.GetOffset());
-
-  // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(12);
-  EXPECT_EQ(12ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-16, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-8, regloc.GetOffset());
-
-  // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(16);
-  EXPECT_EQ(16ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  // fp=[CFA-16] lr=[CFA-8]
-  row_sp = unwind_plan.GetRowForFunctionOffset(28);
-  EXPECT_EQ(28ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
-  // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
-  // <same> lr= <same>
-  row_sp = unwind_plan.GetRowForFunctionOffset(32);
-  EXPECT_EQ(32ull, row_sp->GetOffset());
-
-  // I'd prefer if these restored registers were cleared entirely instead of set
-  // to IsSame...
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-
-  // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
-  // <same> lr= <same>
-  row_sp = unwind_plan.GetRowForFunctionOffset(36);
-  EXPECT_EQ(36ull, row_sp->GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-
-  // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
-  // lr= <same>
-  row_sp = unwind_plan.GetRowForFunctionOffset(40);
-  EXPECT_EQ(40ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
-  EXPECT_TRUE(regloc.IsSame());
-}
-
-TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {
-  ArchSpec arch("arm64-apple-ios10");
-  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;
-
-  // disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u>
-  // from JavaScriptcore for iOS.
-  uint8_t data[] = {
-      0x08, 0x3c, 0x0f, 0x53, //  0: 0x530f3c08 ubfx   w8, w0, #15, #1
-      0x68, 0x00, 0x00, 0x39, //  4: 0x39000068 strb   w8, [x3]
-      0x08, 0x3c, 0x40, 0xd2, //  8: 0xd2403c08 eor    x8, x0, #0xffff
-      0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst    x0, #0x8000
-
-      // [...]
-
-      0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp    x9, x12
-      0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34
-      0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str    wzr, [x2]
-      0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr    w0, wzr, #0x1
-      0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret
-      0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor    x9, x12, x9
-
-      // [...]
-
-      0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add    w8, w8, #0x1
-      0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str    w8, [x2]
-      0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr    w0, wzr, #0x1
-      0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret
-      0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov    w0, #0x0
-      0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
-
-  };
-
-  // UnwindPlan we expect:
-  //  0: CFA=sp +0 =>
-  // (possibly with additional rows at offsets 36 and 56 saying the same thing)
-
-  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_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(32);
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x23_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x24_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x25_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
-  EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(36);
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(52);
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(56);
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(60);
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
-  ArchSpec arch("arm64-apple-ios10");
-  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;
-
-  // disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS.
-  uint8_t data[] = {
-
-      0xfc, 0x6f, 0xba, 0xa9, //  0: 0xa9ba6ffc stp  x28, x27, [sp, #-0x60]!
-      0xfa, 0x67, 0x01, 0xa9, //  4: 0xa90167fa stp  x26, x25, [sp, #0x10]
-      0xf8, 0x5f, 0x02, 0xa9, //  8: 0xa9025ff8 stp  x24, x23, [sp, #0x20]
-      0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp  x22, x21, [sp, #0x30]
-      0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp  x20, x19, [sp, #0x40]
-      0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp  x29, x30, [sp, #0x50]
-      0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add  x29, sp, #0x50
-      0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub  sp, sp, #0x30
-
-      // mid-function, store x20 & x24 on the stack at a different location.
-      // this should not show up in the unwind plan; caller's values are not
-      // being saved to stack.
-      0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp    x24, x20, [sp, #0x10]
-
-      // mid-function, copy x20 and x19 off of the stack -- but not from
-      // their original locations.  unwind plan should ignore this.
-      0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp  x20, x19, [sp, #0x10]
-
-      // epilogue
-      0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub  sp, x29, #0x50
-      0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp  x29, x30, [sp, #0x50]
-      0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp  x20, x19, [sp, #0x40]
-      0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp  x22, x21, [sp, #0x30]
-      0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp  x24, x23, [sp, #0x20]
-      0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp  x26, x25, [sp, #0x10]
-      0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp  x28, x27, [sp], #0x60
-      0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret
-  };
-
-  // UnwindPlan we expect:
-  //   0: CFA=sp +0 =>
-  //   4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
-  //   8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
-  //  12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
-  //  x27=[CFA-88] x28=[CFA-96]
-  //  16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
-  //  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
-  //  20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
-  //  x28=[CFA-96]
-  //  24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
-  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
-  //  28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
-  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
-
-  //  44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
-  //  x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
-  //  48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
-  //  x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
-  //  x28=[CFA-96]
-  //  52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
-  //  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
-  //  56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
-  //  x27=[CFA-88] x28=[CFA-96]
-  //  60: CFA=sp+96 =>  x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
-  //  64: CFA=sp+96 =>  x27=[CFA-88] x28=[CFA-96]
-  //  68: CFA=sp +0 =>
-
-  sample_range = AddressRange(0x1000, sizeof(data));
-
-  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
-      sample_range, data, sizeof(data), unwind_plan));
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(36);
-  EXPECT_EQ(28ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-32, regloc.GetOffset());
-
-  row_sp = unwind_plan.GetRowForFunctionOffset(40);
-  EXPECT_EQ(28ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-32, regloc.GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
-  ArchSpec arch("arm64-apple-ios10");
-  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;
-
-  // this file built with clang for iOS arch arm64 optimization -Os
-  // #include <stdio.h>
-  // double foo(double in) {
-  // double arr[32];
-  // for (int i = 0; i < 32; i++)
-  //   arr[i] = in + i;
-  // for (int i = 2; i < 30; i++)
-  //   arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) /
-  //   ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i]
-  //   * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) /
-  //   ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) +
-  //   ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i -
-  //   1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345)
-  //   + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i]
-  //   * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] +
-  //   17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888);
-  // return arr[16];
-  //}
-  // int main(int argc, char **argv) { printf("%g\n", foo(argc)); }
-
-  // so function foo() uses enough registers that it spills the callee-saved
-  // floating point registers.
-  uint8_t data[] = {
-      // prologue
-      0xef, 0x3b, 0xba, 0x6d, //  0: 0x6dba3bef   stp    d15, d14, [sp, #-0x60]!
-      0xed, 0x33, 0x01, 0x6d, //  4: 0x6d0133ed   stp    d13, d12, [sp, #0x10]
-      0xeb, 0x2b, 0x02, 0x6d, //  8: 0x6d022beb   stp    d11, d10, [sp, #0x20]
-      0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9   stp    d9, d8, [sp, #0x30]
-      0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc   stp    x28, x27, [sp, #0x40]
-      0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd   stp    x29, x30, [sp, #0x50]
-      0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd   add    x29, sp, #0x50
-      0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff   sub    sp, sp, #0x110
-
-      // epilogue
-      0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf   sub    sp, x29, #0x50
-      0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd   ldp    x29, x30, [sp, #0x50]
-      0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc   ldp    x28, x27, [sp, #0x40]
-      0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9   ldp    d9, d8, [sp, #0x30]
-      0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb   ldp    d11, d10, [sp, #0x20]
-      0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed   ldp    d13, d12, [sp, #0x10]
-      0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef   ldp    d15, d14, [sp], #0x60
-      0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0   ret
-  };
-
-  // UnwindPlan we expect:
-  //   0: CFA=sp +0 =>
-  //   4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
-  //   8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
-  //  d14=[CFA-88] d15=[CFA-96]
-  //  16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
-  //  d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
-  //  d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
-  //  d15=[CFA-96]
-  //  24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
-  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
-  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
-  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
-  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
-  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
-  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
-  //  d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
-  //  d15=[CFA-96]
-  //  44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
-  //  d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
-  //  d14=[CFA-88] d15=[CFA-96]
-  //  52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  //  56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
-  //  60: CFA=sp +0 =>
-
-  sample_range = AddressRange(0x1000, sizeof(data));
-
-  EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
-      sample_range, data, sizeof(data), unwind_plan));
-
-  //  28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
-  //  d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
-  //  d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
-  row_sp = unwind_plan.GetRowForFunctionOffset(28);
-  EXPECT_EQ(28ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d15_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-96, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d14_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-88, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d13_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-80, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d12_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-72, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d11_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-64, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d10_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-56, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d9_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-48, regloc.GetOffset());
-
-  EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d8_arm64, regloc));
-  EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
-  EXPECT_EQ(-40, regloc.GetOffset());
-
-  //  60: CFA=sp +0 =>
-  row_sp = unwind_plan.GetRowForFunctionOffset(60);
-  EXPECT_EQ(60ull, row_sp->GetOffset());
-  EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
-  EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
-  EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
-  if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-  if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc))
-    EXPECT_TRUE(regloc.IsSame());
-}

Added: lldb/trunk/unittests/UnwindAssembly/PPC64/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/PPC64/CMakeLists.txt?rev=326224&view=auto
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/PPC64/CMakeLists.txt (added)
+++ lldb/trunk/unittests/UnwindAssembly/PPC64/CMakeLists.txt Tue Feb 27 10:42:46 2018
@@ -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})

Added: lldb/trunk/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp?rev=326224&view=auto
==============================================================================
--- lldb/trunk/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp (added)
+++ lldb/trunk/unittests/UnwindAssembly/PPC64/TestPPC64InstEmulation.cpp Tue Feb 27 10:42:46 2018
@@ -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());
+}




More information about the lldb-commits mailing list