diff options
| author | Tamas Berghammer <tberghammer@google.com> | 2015-05-26 11:58:52 +0000 |
|---|---|---|
| committer | Tamas Berghammer <tberghammer@google.com> | 2015-05-26 11:58:52 +0000 |
| commit | 068f8a7e2d7ece12cc00726bb2e6df180b217848 (patch) | |
| tree | 3ac16e6c32a2a44799ad79fa0f141f30c990c66a /lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp | |
| parent | b2b901c607ae3149b6d3a0c53a45f22e3542fb04 (diff) | |
| download | bcm5719-llvm-068f8a7e2d7ece12cc00726bb2e6df180b217848.tar.gz bcm5719-llvm-068f8a7e2d7ece12cc00726bb2e6df180b217848.zip | |
Move register reading form NativeProcessLinux to NativeRegisterContextLinux*
This change reorganize the register read/write code inside lldb-server on Linux
with moving the architecture independent code into a new class called
NativeRegisterContextLinux and all of the architecture dependent code into the
appropriate NativeRegisterContextLinux_* class. As part of it the compilation of
the architecture specific register contexts are only compiled on the specific
architecture because they can't be used in other cases.
The purpose of this change is to remove a lot of duplicated code from the different
register contexts and to remove the architecture dependent codes from the global
NativeProcessLinux class.
Differential revision: http://reviews.llvm.org/D9935
llvm-svn: 238196
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp')
| -rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp new file mode 100644 index 00000000000..8d99cdac49b --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -0,0 +1,452 @@ +//===-- 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; + +namespace +{ + +class ReadRegOperation : public NativeProcessLinux::Operation +{ +public: + ReadRegOperation(lldb::tid_t tid, uint32_t offset, const char *reg_name, RegisterValue &value) : + m_tid(tid), + m_offset(static_cast<uintptr_t>(offset)), + m_reg_name(reg_name), + m_value(value) + { } + + void + Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + uintptr_t m_offset; + const char *m_reg_name; + RegisterValue &m_value; +}; + +class WriteRegOperation : public NativeProcessLinux::Operation +{ +public: + WriteRegOperation(lldb::tid_t tid, unsigned offset, const char *reg_name, const RegisterValue &value) : + m_tid(tid), + m_offset(offset), + m_reg_name(reg_name), + m_value(value) + { } + + void + Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + uintptr_t m_offset; + const char *m_reg_name; + const RegisterValue &m_value; +}; + +class ReadGPROperation : public NativeProcessLinux::Operation +{ +public: + ReadGPROperation(lldb::tid_t tid, void *buf, size_t buf_size) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; +}; + +class WriteGPROperation : public NativeProcessLinux::Operation +{ +public: + WriteGPROperation(lldb::tid_t tid, void *buf, size_t buf_size) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; +}; + +class ReadFPROperation : public NativeProcessLinux::Operation +{ +public: + ReadFPROperation(lldb::tid_t tid, void *buf, size_t buf_size) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; +}; + +class WriteFPROperation : public NativeProcessLinux::Operation +{ +public: + WriteFPROperation(lldb::tid_t tid, void *buf, size_t buf_size) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; +}; + +class ReadRegisterSetOperation : public NativeProcessLinux::Operation +{ +public: + ReadRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; + const unsigned int m_regset; +}; + +class WriteRegisterSetOperation : public NativeProcessLinux::Operation +{ +public: + WriteRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) : + m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset) + { } + + void Execute(NativeProcessLinux *monitor) override; + +private: + lldb::tid_t m_tid; + void *m_buf; + size_t m_buf_size; + const unsigned int m_regset; +}; + +} // end of anonymous namespace + +void +ReadRegOperation::Execute(NativeProcessLinux *monitor) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); + + lldb::addr_t data = static_cast<unsigned long>(NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSER, m_tid, (void*)m_offset, nullptr, 0, m_error)); + if (m_error.Success()) + m_value = data; + + if (log) + log->Printf ("NativeProcessLinux::%s() reg %s: 0x%" PRIx64, __FUNCTION__, m_reg_name, data); +} + +void +WriteRegOperation::Execute(NativeProcessLinux *monitor) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); + + void* buf = (void*)m_value.GetAsUInt64(); + + if (log) + log->Printf ("NativeProcessLinux::%s() reg %s: %p", __FUNCTION__, m_reg_name, buf); + NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSER, m_tid, (void*)m_offset, buf, 0, m_error); +} + +void +ReadGPROperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_tid, nullptr, m_buf, m_buf_size, m_error); +} + +void +WriteGPROperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_tid, nullptr, m_buf, m_buf_size, m_error); +} + +void +ReadFPROperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_tid, nullptr, m_buf, m_buf_size, m_error); +} + +void +WriteFPROperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_tid, nullptr, m_buf, m_buf_size, m_error); +} + +void +ReadRegisterSetOperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size, m_error); +} + +void +WriteRegisterSetOperation::Execute(NativeProcessLinux *monitor) +{ + NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size, m_error); +} + +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); + + NativeProcessProtocolSP process_sp(m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation(GetReadRegisterValueOperation(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; + } + } + } + + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + 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); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); + return process_p->DoOperation(GetWriteRegisterValueOperation(reg_info->byte_offset, + reg_info->name, + reg_value)); +} + +Error +NativeRegisterContextLinux::ReadGPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + void* buf = GetGPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetGPRSize(); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation(GetReadGPROperation(buf, buf_size)); +} + +Error +NativeRegisterContextLinux::WriteGPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + void* buf = GetGPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetGPRSize(); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation(GetWriteGPROperation(buf, buf_size)); +} + +Error +NativeRegisterContextLinux::ReadFPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + void* buf = GetFPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetFPRSize(); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation(GetReadFPROperation(buf, buf_size)); +} + +Error +NativeRegisterContextLinux::WriteFPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + + void* buf = GetFPRBuffer(); + if (!buf) + return Error("GPR buffer is NULL"); + size_t buf_size = GetFPRSize(); + + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + return process_p->DoOperation(GetWriteFPROperation(buf, buf_size)); +} + +Error +NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + + ReadRegisterSetOperation op(m_thread.GetID(), buf, buf_size, regset); + return process_p->DoOperation(&op); +} + +Error +NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess()); + if (!process_sp) + return Error("NativeProcessProtocol is NULL"); + NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); + + WriteRegisterSetOperation op(m_thread.GetID(), buf, buf_size, regset); + return process_p->DoOperation(&op); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetReadRegisterValueOperation(uint32_t offset, + const char* reg_name, + uint32_t size, + RegisterValue &value) +{ + return NativeProcessLinux::OperationUP(new ReadRegOperation(m_thread.GetID(), offset, reg_name, value)); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetWriteRegisterValueOperation(uint32_t offset, + const char* reg_name, + const RegisterValue &value) +{ + return NativeProcessLinux::OperationUP(new WriteRegOperation(m_thread.GetID(), offset, reg_name, value)); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetReadGPROperation(void *buf, size_t buf_size) +{ + return NativeProcessLinux::OperationUP(new ReadGPROperation(m_thread.GetID(), buf, buf_size)); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetWriteGPROperation(void *buf, size_t buf_size) +{ + return NativeProcessLinux::OperationUP(new WriteGPROperation(m_thread.GetID(), buf, buf_size)); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetReadFPROperation(void *buf, size_t buf_size) +{ + return NativeProcessLinux::OperationUP(new ReadFPROperation(m_thread.GetID(), buf, buf_size)); +} + +NativeProcessLinux::OperationUP +NativeRegisterContextLinux::GetWriteFPROperation(void *buf, size_t buf_size) +{ + return NativeProcessLinux::OperationUP(new WriteFPROperation(m_thread.GetID(), buf, buf_size)); +} |

