Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
13 changed files
with
766 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
245 changes: 245 additions & 0 deletions
245
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ®_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 ®_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(), | ||
®set, 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(), | ||
®set, buf, buf_size); | ||
} | ||
|
||
#endif // defined(__powerpc64__) |
70 changes: 70 additions & 0 deletions
70
lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ®_value) override; | ||
|
||
Status WriteRegister(const RegisterInfo *reg_info, | ||
const RegisterValue ®_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__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.