Skip to content

Commit

Permalink
Enable breakpoints and read/write GPRs for ppc64le
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Djuffin committed Oct 5, 2017
1 parent ca6c8e8 commit aae0a75
Show file tree
Hide file tree
Showing 13 changed files with 766 additions and 2 deletions.
3 changes: 2 additions & 1 deletion lldb/source/Plugins/Process/Linux/CMakeLists.txt
Expand Up @@ -7,9 +7,10 @@ add_lldb_library(lldbPluginProcessLinux PLUGIN
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
Expand Down
14 changes: 13 additions & 1 deletion lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
Expand Up @@ -1078,7 +1078,8 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) {
} 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
Expand Down Expand Up @@ -1579,6 +1580,7 @@ Status NativeProcessLinux::GetSoftwareBreakpointPCOffset(
// 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:
Expand All @@ -1590,6 +1592,10 @@ Status NativeProcessLinux::GetSoftwareBreakpointPCOffset(
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:
Expand Down Expand Up @@ -1635,6 +1641,7 @@ Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(
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:
Expand Down Expand Up @@ -1680,6 +1687,11 @@ Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(
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");
Expand Down
@@ -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__)
@@ -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__)
1 change: 1 addition & 0 deletions lldb/source/Plugins/Process/Utility/CMakeLists.txt
Expand Up @@ -44,6 +44,7 @@ add_lldb_library(lldbPluginProcessUtility PLUGIN
RegisterContextThreadMemory.cpp
RegisterInfoPOSIX_arm.cpp
RegisterInfoPOSIX_arm64.cpp
RegisterInfoPOSIX_ppc64le.cpp
StopInfoMachException.cpp
ThreadMemory.cpp
UnwindLLDB.cpp
Expand Down

0 comments on commit aae0a75

Please sign in to comment.