diff options
Diffstat (limited to 'source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp')
-rw-r--r-- | source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp new file mode 100644 index 000000000000..df0a008ff5f7 --- /dev/null +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -0,0 +1,230 @@ +//===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeRegisterContextLinux.h" + +#include "lldb/Core/RegisterValue.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Host/linux/Ptrace.h" + +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" + +using namespace lldb_private; +using namespace lldb_private::process_linux; + +NativeRegisterContextLinux::NativeRegisterContextLinux(NativeThreadProtocol &native_thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *reg_info_interface_p) : + NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, reg_info_interface_p) +{} + +lldb::ByteOrder +NativeRegisterContextLinux::GetByteOrder() const +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return byte_order; + + if (!process_sp->GetByteOrder (byte_order)) + { + // FIXME log here + } + + return byte_order; +} + +Error +NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) +{ + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return Error("register %" PRIu32 " not found", reg_index); + + return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); +} + +Error +NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue ®_value) +{ + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + Error error; + + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail ()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + + const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); + assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); + + return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); +} + +Error +NativeRegisterContextLinux::ReadGPR() +{ + void* buf = GetGPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetGPRSize(); + + return DoReadGPR(buf, buf_size); +} + +Error +NativeRegisterContextLinux::WriteGPR() +{ + void* buf = GetGPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetGPRSize(); + + return DoWriteGPR(buf, buf_size); +} + +Error +NativeRegisterContextLinux::ReadFPR() +{ + void* buf = GetFPRBuffer(); + if (!buf) + return Error("FPR buffer is NULL"); + size_t buf_size = GetFPRSize(); + + return DoReadFPR(buf, buf_size); +} + +Error +NativeRegisterContextLinux::WriteFPR() +{ + void* buf = GetFPRBuffer(); + if (!buf) + return Error("FPR buffer is NULL"); + size_t buf_size = GetFPRSize(); + + return DoWriteFPR(buf, buf_size); +} + +Error +NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), + static_cast<void *>(®set), buf, buf_size); +} + +Error +NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + static_cast<void *>(®set), buf, buf_size); +} + +Error +NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, + const char* reg_name, + uint32_t size, + RegisterValue &value) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); + + long data; + Error error = NativeProcessLinux::PtraceWrapper( + PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), nullptr, 0, &data); + + if (error.Success()) + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt64(static_cast<unsigned long>(data)); + + if (log) + log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%lx", __FUNCTION__, reg_name, data); + + return error; +} + +Error +NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset, + const char* reg_name, + const RegisterValue &value) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); + + void* buf = reinterpret_cast<void *>(value.GetAsUInt64()); + + if (log) + log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf); + + return NativeProcessLinux::PtraceWrapper( + PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf); +} + +Error +NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size); +} + +Error +NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size); +} + +Error +NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); +} + +Error +NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) +{ + return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); +} |