diff options
| author | Eugene Zemtsov <ezemtsov@google.com> | 2017-10-05 19:44:05 +0000 |
|---|---|---|
| committer | Eugene Zemtsov <ezemtsov@google.com> | 2017-10-05 19:44:05 +0000 |
| commit | aae0a752c5d700731d00cb0e0413a20a64081c8e (patch) | |
| tree | a3bf7a498e320c627b9b4a7e143c6d86f5978630 /lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp | |
| parent | ca6c8e85d1130837dd08301f7708b41a02698a90 (diff) | |
| download | bcm5719-llvm-aae0a752c5d700731d00cb0e0413a20a64081c8e.tar.gz bcm5719-llvm-aae0a752c5d700731d00cb0e0413a20a64081c8e.zip | |
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
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp')
| -rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
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 00000000000..e6cabef4f1a --- /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 ®_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__) |

