Enable breakpoints and read/write GPRs for ppc64le

Add support for ppc64le to create breakpoints and read/write
general purpose registers.
Other features for ppc64le and functions to read/write
other registers are being implemented.

Patch by Alexandre Yukio Yamashita (alexandreyy)
Differential Revision: https://reviews.llvm.org/D38323

llvm-svn: 315008
diff --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
index 8330cac..390dbd9 100644
--- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
@@ -7,9 +7,10 @@
   NativeRegisterContextLinux.cpp
   NativeRegisterContextLinux_arm.cpp
   NativeRegisterContextLinux_arm64.cpp
-  NativeRegisterContextLinux_x86_64.cpp
   NativeRegisterContextLinux_mips64.cpp
+  NativeRegisterContextLinux_ppc64le.cpp
   NativeRegisterContextLinux_s390x.cpp
+  NativeRegisterContextLinux_x86_64.cpp
   NativeThreadLinux.cpp
   ProcessorTrace.cpp
   SingleStepCheck.cpp
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 170d3b1..a5dac2a 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1078,7 +1078,8 @@
   } else if (m_arch.GetMachine() == llvm::Triple::mips64 ||
              m_arch.GetMachine() == llvm::Triple::mips64el ||
              m_arch.GetMachine() == llvm::Triple::mips ||
-             m_arch.GetMachine() == llvm::Triple::mipsel)
+             m_arch.GetMachine() == llvm::Triple::mipsel ||
+             m_arch.GetMachine() == llvm::Triple::ppc64le)
     error = SetSoftwareBreakpoint(next_pc, 4);
   else {
     // No size hint is given for the next breakpoint
@@ -1579,6 +1580,7 @@
   // set per architecture.  Need ARM, MIPS support here.
   static const uint8_t g_i386_opcode[] = {0xCC};
   static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
+  static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
 
   switch (m_arch.GetMachine()) {
   case llvm::Triple::x86:
@@ -1590,6 +1592,10 @@
     actual_opcode_size = static_cast<uint32_t>(sizeof(g_s390x_opcode));
     return Status();
 
+  case llvm::Triple::ppc64le:
+    actual_opcode_size = static_cast<uint32_t>(sizeof(g_ppc64le_opcode));
+    return Status();
+
   case llvm::Triple::arm:
   case llvm::Triple::aarch64:
   case llvm::Triple::mips64:
@@ -1635,6 +1641,7 @@
   static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00};
   static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
   static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};
+  static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
 
   switch (m_arch.GetMachine()) {
   case llvm::Triple::aarch64:
@@ -1680,6 +1687,11 @@
     actual_opcode_size = sizeof(g_s390x_opcode);
     return Status();
 
+  case llvm::Triple::ppc64le:
+    trap_opcode_bytes = g_ppc64le_opcode;
+    actual_opcode_size = sizeof(g_ppc64le_opcode);
+    return Status();
+
   default:
     assert(false && "CPU type not supported!");
     return Status("CPU type not supported");
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp
new file mode 100644
index 0000000..e6cabef
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp
@@ -0,0 +1,245 @@
+//===-- NativeRegisterContextLinux_ppc64le.cpp ------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This implementation is related to the OpenPOWER ABI for Power Architecture
+// 64-bit ELF V2 ABI
+
+#if defined(__powerpc64__)
+
+#include "NativeRegisterContextLinux_ppc64le.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+#include "Plugins/Process/Linux/Procfs.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
+
+// System includes - They have to be included after framework includes because
+// they define some
+// macros which collide with variable names in other modules
+#include <sys/socket.h>
+#include <elf.h>
+#include <asm/ptrace.h>
+
+#define REG_CONTEXT_SIZE GetGPRSize()
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_linux;
+
+static const uint32_t g_gpr_regnums_ppc64le[] = {
+    gpr_r0_ppc64le,   gpr_r1_ppc64le,  gpr_r2_ppc64le,     gpr_r3_ppc64le,
+    gpr_r4_ppc64le,   gpr_r5_ppc64le,  gpr_r6_ppc64le,     gpr_r7_ppc64le,
+    gpr_r8_ppc64le,   gpr_r9_ppc64le,  gpr_r10_ppc64le,    gpr_r11_ppc64le,
+    gpr_r12_ppc64le,  gpr_r13_ppc64le, gpr_r14_ppc64le,    gpr_r15_ppc64le,
+    gpr_r16_ppc64le,  gpr_r17_ppc64le, gpr_r18_ppc64le,    gpr_r19_ppc64le,
+    gpr_r20_ppc64le,  gpr_r21_ppc64le, gpr_r22_ppc64le,    gpr_r23_ppc64le,
+    gpr_r24_ppc64le,  gpr_r25_ppc64le, gpr_r26_ppc64le,    gpr_r27_ppc64le,
+    gpr_r28_ppc64le,  gpr_r29_ppc64le, gpr_r30_ppc64le,    gpr_r31_ppc64le,
+    gpr_pc_ppc64le,   gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
+    gpr_lr_ppc64le,   gpr_xer_ppc64le, gpr_cr_ppc64le,     gpr_softe_ppc64le,
+    gpr_trap_ppc64le,
+};
+
+namespace {
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 1 };
+}
+
+static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
+    {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
+     g_gpr_regnums_ppc64le},
+};
+
+NativeRegisterContextLinux *
+NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+    uint32_t concrete_frame_idx) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::ppc64le:
+    return new NativeRegisterContextLinux_ppc64le(target_arch, native_thread,
+                                              concrete_frame_idx);
+  default:
+    llvm_unreachable("have no register context for architecture");
+  }
+}
+
+NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+    uint32_t concrete_frame_idx)
+    : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
+                                 new RegisterInfoPOSIX_ppc64le(target_arch)) {
+  if (target_arch.GetMachine() != llvm::Triple::ppc64le) {
+    llvm_unreachable("Unhandled target architecture.");
+  }
+
+  ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
+}
+
+uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
+  return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
+  if (set_index < k_num_register_sets)
+    return &g_reg_sets_ppc64le[set_index];
+
+  return nullptr;
+}
+
+uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
+  uint32_t count = 0;
+  for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+    count += g_reg_sets_ppc64le[set_index].num_registers;
+  return count;
+}
+
+Status NativeRegisterContextLinux_ppc64le::ReadRegister(
+    const RegisterInfo *reg_info, RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+  if (IsGPR(reg)) {
+    error = ReadGPR();
+    if (error.Fail())
+      return error;
+
+    uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
+    reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
+                                eByteOrderLittle, error);
+  } else {
+    return Status("failed - register wasn't recognized to be a GPR, "
+                  "read strategy unknown");
+  }
+
+  return error;
+}
+
+Status NativeRegisterContextLinux_ppc64le::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+  Status error;
+  if (!reg_info)
+    return Status("reg_info NULL");
+
+  const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+  if (reg_index == LLDB_INVALID_REGNUM)
+    return Status("no lldb regnum for %s", reg_info && reg_info->name
+                                               ? reg_info->name
+                                               : "<unknown register>");
+
+  if (IsGPR(reg_index)) {
+      error = ReadGPR();
+      if (error.Fail())
+        return error;
+
+      uint8_t *dst = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
+      ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
+
+      error = WriteGPR();
+      if (error.Fail())
+        return error;
+
+      return Status();
+  }
+
+  return Status("failed - register wasn't recognized to be a GPR, "
+                "write strategy unknown");
+}
+
+Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
+    lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+  if (!data_sp)
+    return Status("failed to allocate DataBufferHeap instance of size %" PRIu64,
+                  REG_CONTEXT_SIZE);
+
+  error = ReadGPR();
+  if (error.Fail())
+    return error;
+
+  uint8_t *dst = data_sp->GetBytes();
+  if (dst == nullptr) {
+    error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
+                                   " returned a null pointer",
+                                   REG_CONTEXT_SIZE);
+    return error;
+  }
+
+  ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
+
+  return error;
+}
+
+Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  if (!data_sp) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
+        __FUNCTION__);
+    return error;
+  }
+
+  if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
+        "data size, expected %" PRIu64 ", actual %" PRIu64,
+        __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+    return error;
+  }
+
+  uint8_t *src = data_sp->GetBytes();
+  if (src == nullptr) {
+    error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s "
+                                   "DataBuffer::GetBytes() returned a null "
+                                   "pointer",
+                                   __FUNCTION__);
+    return error;
+  }
+
+  ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
+  error = WriteGPR();
+
+  return error;
+}
+
+bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
+  return reg <= k_last_gpr_ppc64le; // GPR's come first.
+}
+
+Status NativeRegisterContextLinux_ppc64le::DoReadGPR(
+    void *buf, size_t buf_size) {
+  int regset = NT_PRSTATUS;
+  return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
+                                           &regset, buf, buf_size);
+}
+
+Status NativeRegisterContextLinux_ppc64le::DoWriteGPR(
+    void *buf, size_t buf_size) {
+  int regset = NT_PRSTATUS;
+  return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
+                                           &regset, buf, buf_size);
+}
+
+#endif // defined(__powerpc64__)
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h
new file mode 100644
index 0000000..d9bad42
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h
@@ -0,0 +1,70 @@
+//===-- NativeRegisterContextLinux_ppc64le.h ---------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This implementation is related to the OpenPOWER ABI for Power Architecture
+// 64-bit ELF V2 ABI
+
+#if defined(__powerpc64__)
+
+#ifndef lldb_NativeRegisterContextLinux_ppc64le_h
+#define lldb_NativeRegisterContextLinux_ppc64le_h
+
+#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
+
+#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+#include "RegisterInfos_ppc64le.h"
+#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
+
+namespace lldb_private {
+namespace process_linux {
+
+class NativeProcessLinux;
+
+class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux {
+public:
+  NativeRegisterContextLinux_ppc64le(const ArchSpec &target_arch,
+                                   NativeThreadProtocol &native_thread,
+                                   uint32_t concrete_frame_idx);
+
+  uint32_t GetRegisterSetCount() const override;
+
+  uint32_t GetUserRegisterCount() const override;
+
+  const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+  Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+protected:
+  Status DoReadGPR(void *buf, size_t buf_size) override;
+
+  Status DoWriteGPR(void *buf, size_t buf_size) override;
+
+  void *GetGPRBuffer() override { return &m_gpr_ppc64le; }
+
+private:
+  GPR m_gpr_ppc64le; // 64-bit general purpose registers.
+
+  bool IsGPR(unsigned reg) const;
+};
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_ppc64le_h
+
+#endif // defined(__powerpc64__)