forked from OSchip/llvm-project
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
This commit is contained in:
parent
b2b901c607
commit
068f8a7e2d
|
@ -7,6 +7,7 @@ include_directories(../Utility)
|
|||
add_lldb_library(lldbPluginProcessLinux
|
||||
LinuxThread.cpp
|
||||
NativeProcessLinux.cpp
|
||||
NativeRegisterContextLinux.cpp
|
||||
NativeRegisterContextLinux_arm.cpp
|
||||
NativeRegisterContextLinux_arm64.cpp
|
||||
NativeRegisterContextLinux_x86_64.cpp
|
||||
|
@ -16,4 +17,3 @@ add_lldb_library(lldbPluginProcessLinux
|
|||
ProcessMonitor.cpp
|
||||
ProcFileReader.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -61,11 +61,6 @@
|
|||
#include <sys/user.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
// NT_PRSTATUS and NT_FPREGSET definition
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
#include "lldb/Host/linux/Personality.h"
|
||||
#include "lldb/Host/linux/Ptrace.h"
|
||||
#include "lldb/Host/linux/Signalfd.h"
|
||||
|
@ -78,16 +73,6 @@
|
|||
#define TRAP_HWBKPT 4
|
||||
#endif
|
||||
|
||||
// We disable the tracing of ptrace calls for integration builds to
|
||||
// avoid the additional indirection and checks.
|
||||
#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
#define PTRACE(req, pid, addr, data, data_size, error) \
|
||||
PtraceWrapper((req), (pid), (addr), (data), (data_size), (error), #req, __FILE__, __LINE__)
|
||||
#else
|
||||
#define PTRACE(req, pid, addr, data, data_size, error) \
|
||||
PtraceWrapper((req), (pid), (addr), (data), (data_size), (error))
|
||||
#endif
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::process_linux;
|
||||
|
@ -204,72 +189,6 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
// Wrapper for ptrace to catch errors and log calls.
|
||||
// Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
|
||||
long
|
||||
PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, Error& error,
|
||||
const char* reqName, const char* file, int line)
|
||||
{
|
||||
long int result;
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
|
||||
|
||||
PtraceDisplayBytes(req, data, data_size);
|
||||
|
||||
error.Clear();
|
||||
errno = 0;
|
||||
if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), *(unsigned int *)addr, data);
|
||||
else
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), addr, data);
|
||||
|
||||
if (result == -1)
|
||||
error.SetErrorToErrno();
|
||||
|
||||
if (log)
|
||||
log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d",
|
||||
reqName, pid, addr, data, data_size, result, file, line);
|
||||
|
||||
PtraceDisplayBytes(req, data, data_size);
|
||||
|
||||
if (log && error.GetError() != 0)
|
||||
{
|
||||
const char* str;
|
||||
switch (error.GetError())
|
||||
{
|
||||
case ESRCH: str = "ESRCH"; break;
|
||||
case EINVAL: str = "EINVAL"; break;
|
||||
case EBUSY: str = "EBUSY"; break;
|
||||
case EPERM: str = "EPERM"; break;
|
||||
default: str = error.AsCString();
|
||||
}
|
||||
log->Printf("ptrace() failed; errno=%d (%s)", error.GetError(), str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
// Wrapper for ptrace when logging is not required.
|
||||
// Sets errno to 0 prior to calling ptrace.
|
||||
long
|
||||
PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, Error& error)
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
error.Clear();
|
||||
errno = 0;
|
||||
if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), *(unsigned int *)addr, data);
|
||||
else
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), addr, data);
|
||||
|
||||
if (result == -1)
|
||||
error.SetErrorToErrno();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Static implementations of NativeProcessLinux::ReadMemory and
|
||||
// NativeProcessLinux::WriteMemory. This enables mutual recursion between these
|
||||
|
@ -300,7 +219,7 @@ namespace
|
|||
assert(sizeof(data) >= word_size);
|
||||
for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
|
||||
{
|
||||
data = PTRACE(PTRACE_PEEKDATA, pid, (void*)vm_addr, nullptr, 0, error);
|
||||
data = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKDATA, pid, (void*)vm_addr, nullptr, 0, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
if (log)
|
||||
|
@ -377,7 +296,7 @@ namespace
|
|||
log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
|
||||
(void*)vm_addr, *(const unsigned long*)src, data);
|
||||
|
||||
if (PTRACE(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data, 0, error))
|
||||
if (NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data, 0, error))
|
||||
{
|
||||
if (log)
|
||||
ProcessPOSIXLog::DecNestLevel();
|
||||
|
@ -421,39 +340,10 @@ namespace
|
|||
return bytes_written;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class Operation
|
||||
/// @brief Represents a NativeProcessLinux operation.
|
||||
///
|
||||
/// Under Linux, it is not possible to ptrace() from any other thread but the
|
||||
/// one that spawned or attached to the process from the start. Therefore, when
|
||||
/// a NativeProcessLinux is asked to deliver or change the state of an inferior
|
||||
/// process the operation must be "funneled" to a specific thread to perform the
|
||||
/// task. The Operation class provides an abstract base for all services the
|
||||
/// NativeProcessLinux must perform via the single virtual function Execute, thus
|
||||
/// encapsulating the code that needs to run in the privileged context.
|
||||
class Operation
|
||||
{
|
||||
public:
|
||||
Operation () : m_error() { }
|
||||
|
||||
virtual
|
||||
~Operation() {}
|
||||
|
||||
virtual void
|
||||
Execute (NativeProcessLinux *process) = 0;
|
||||
|
||||
const Error &
|
||||
GetError () const { return m_error; }
|
||||
|
||||
protected:
|
||||
Error m_error;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadOperation
|
||||
/// @brief Implements NativeProcessLinux::ReadMemory.
|
||||
class ReadOperation : public Operation
|
||||
class ReadOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
ReadOperation(
|
||||
|
@ -487,7 +377,7 @@ namespace
|
|||
//------------------------------------------------------------------------------
|
||||
/// @class WriteOperation
|
||||
/// @brief Implements NativeProcessLinux::WriteMemory.
|
||||
class WriteOperation : public Operation
|
||||
class WriteOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
WriteOperation(
|
||||
|
@ -518,464 +408,10 @@ namespace
|
|||
m_result = DoWriteMemory (process->GetID (), m_addr, m_buff, m_size, m_error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadRegOperation
|
||||
/// @brief Implements NativeProcessLinux::ReadRegisterValue.
|
||||
class ReadRegOperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
ReadRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
if (m_offset > sizeof(struct user_pt_regs))
|
||||
{
|
||||
uintptr_t offset = m_offset - sizeof(struct user_pt_regs);
|
||||
if (offset > sizeof(struct user_fpsimd_state))
|
||||
{
|
||||
m_error.SetErrorString("invalid offset value");
|
||||
return;
|
||||
}
|
||||
elf_fpregset_t regs;
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(regs)) + m_offset), 8, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
}
|
||||
#elif defined (__mips__)
|
||||
elf_gregset_t regs;
|
||||
PTRACE(PTRACE_GETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
lldb_private::ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(regs)) + m_offset), 8, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
#else
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
|
||||
|
||||
lldb::addr_t data = static_cast<unsigned long>(PTRACE(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);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class WriteRegOperation
|
||||
/// @brief Implements NativeProcessLinux::WriteRegisterValue.
|
||||
class WriteRegOperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
WriteRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
if (m_offset > sizeof(struct user_pt_regs))
|
||||
{
|
||||
uintptr_t offset = m_offset - sizeof(struct user_pt_regs);
|
||||
if (offset > sizeof(struct user_fpsimd_state))
|
||||
{
|
||||
m_error.SetErrorString("invalid offset value");
|
||||
return;
|
||||
}
|
||||
elf_fpregset_t regs;
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + offset), m_value.GetBytes(), 16);
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + m_offset), m_value.GetBytes(), 8);
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
}
|
||||
}
|
||||
#elif defined (__mips__)
|
||||
elf_gregset_t regs;
|
||||
PTRACE(PTRACE_GETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + m_offset), m_value.GetBytes(), 8);
|
||||
PTRACE(PTRACE_SETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
}
|
||||
#else
|
||||
void* buf;
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
|
||||
|
||||
buf = (void*) m_value.GetAsUInt64();
|
||||
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() reg %s: %p", __FUNCTION__, m_reg_name, buf);
|
||||
PTRACE(PTRACE_POKEUSER, m_tid, (void*)m_offset, buf, 0, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadGPROperation
|
||||
/// @brief Implements NativeProcessLinux::ReadGPR.
|
||||
class ReadGPROperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
ReadGPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
#else
|
||||
PTRACE(PTRACE_GETREGS, m_tid, nullptr, m_buf, m_buf_size, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadFPROperation
|
||||
/// @brief Implements NativeProcessLinux::ReadFPR.
|
||||
class ReadFPROperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
ReadFPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
#else
|
||||
PTRACE(PTRACE_GETFPREGS, m_tid, nullptr, m_buf, m_buf_size, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadDBGROperation
|
||||
/// @brief Implements NativeProcessLinux::ReadHardwareDebugInfo.
|
||||
class ReadDBGROperation : public Operation
|
||||
{
|
||||
public:
|
||||
ReadDBGROperation(lldb::tid_t tid, unsigned int &count_wp, unsigned int &count_bp)
|
||||
: m_tid(tid),
|
||||
m_count_wp(count_wp),
|
||||
m_count_bp(count_bp)
|
||||
{ }
|
||||
|
||||
void Execute(NativeProcessLinux *monitor) override;
|
||||
|
||||
private:
|
||||
lldb::tid_t m_tid;
|
||||
unsigned int &m_count_wp;
|
||||
unsigned int &m_count_bp;
|
||||
};
|
||||
|
||||
void
|
||||
ReadDBGROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
int regset = NT_ARM_HW_WATCH;
|
||||
struct iovec ioVec;
|
||||
struct user_hwdebug_state dreg_state;
|
||||
|
||||
ioVec.iov_base = &dreg_state;
|
||||
ioVec.iov_len = sizeof (dreg_state);
|
||||
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len, m_error);
|
||||
|
||||
m_count_wp = dreg_state.dbg_info & 0xff;
|
||||
regset = NT_ARM_HW_BREAK;
|
||||
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len, m_error);
|
||||
m_count_bp = dreg_state.dbg_info & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadRegisterSetOperation
|
||||
/// @brief Implements NativeProcessLinux::ReadRegisterSet.
|
||||
class ReadRegisterSetOperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
ReadRegisterSetOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
PTRACE(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class WriteGPROperation
|
||||
/// @brief Implements NativeProcessLinux::WriteGPR.
|
||||
class WriteGPROperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
WriteGPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
#else
|
||||
PTRACE(PTRACE_SETREGS, m_tid, NULL, m_buf, m_buf_size, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class WriteFPROperation
|
||||
/// @brief Implements NativeProcessLinux::WriteFPR.
|
||||
class WriteFPROperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
WriteFPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
#else
|
||||
PTRACE(PTRACE_SETFPREGS, m_tid, NULL, m_buf, m_buf_size, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class WriteDBGROperation
|
||||
/// @brief Implements NativeProcessLinux::WriteHardwareDebugRegs.
|
||||
class WriteDBGROperation : public Operation
|
||||
{
|
||||
public:
|
||||
WriteDBGROperation(lldb::tid_t tid, lldb::addr_t *addr_buf,
|
||||
uint32_t *cntrl_buf, int type, int count)
|
||||
: m_tid(tid),
|
||||
m_address(addr_buf),
|
||||
m_control(cntrl_buf),
|
||||
m_type(type),
|
||||
m_count(count)
|
||||
{ }
|
||||
|
||||
void Execute(NativeProcessLinux *monitor) override;
|
||||
|
||||
private:
|
||||
lldb::tid_t m_tid;
|
||||
lldb::addr_t * m_address;
|
||||
uint32_t * m_control;
|
||||
int m_type;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
void
|
||||
WriteDBGROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
struct iovec ioVec;
|
||||
struct user_hwdebug_state dreg_state;
|
||||
|
||||
memset (&dreg_state, 0, sizeof (dreg_state));
|
||||
ioVec.iov_base = &dreg_state;
|
||||
ioVec.iov_len = sizeof (dreg_state);
|
||||
|
||||
if (m_type == 0)
|
||||
m_type = NT_ARM_HW_WATCH;
|
||||
else
|
||||
m_type = NT_ARM_HW_BREAK;
|
||||
|
||||
for (int i = 0; i < m_count; i++)
|
||||
{
|
||||
dreg_state.dbg_regs[i].addr = m_address[i];
|
||||
dreg_state.dbg_regs[i].ctrl = m_control[i];
|
||||
}
|
||||
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len, m_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class WriteRegisterSetOperation
|
||||
/// @brief Implements NativeProcessLinux::WriteRegisterSet.
|
||||
class WriteRegisterSetOperation : public 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;
|
||||
};
|
||||
|
||||
void
|
||||
WriteRegisterSetOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
PTRACE(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ResumeOperation
|
||||
/// @brief Implements NativeProcessLinux::Resume.
|
||||
class ResumeOperation : public Operation
|
||||
class ResumeOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
ResumeOperation(lldb::tid_t tid, uint32_t signo) :
|
||||
|
@ -996,7 +432,7 @@ namespace
|
|||
if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
data = m_signo;
|
||||
|
||||
PTRACE(PTRACE_CONT, m_tid, nullptr, (void*)data, 0, m_error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_CONT, m_tid, nullptr, (void*)data, 0, m_error);
|
||||
if (m_error.Fail())
|
||||
{
|
||||
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||
|
@ -1009,7 +445,7 @@ namespace
|
|||
//------------------------------------------------------------------------------
|
||||
/// @class SingleStepOperation
|
||||
/// @brief Implements NativeProcessLinux::SingleStep.
|
||||
class SingleStepOperation : public Operation
|
||||
class SingleStepOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
SingleStepOperation(lldb::tid_t tid, uint32_t signo)
|
||||
|
@ -1030,13 +466,13 @@ namespace
|
|||
if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
data = m_signo;
|
||||
|
||||
PTRACE(PTRACE_SINGLESTEP, m_tid, nullptr, (void*)data, 0, m_error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, m_tid, nullptr, (void*)data, 0, m_error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class SiginfoOperation
|
||||
/// @brief Implements NativeProcessLinux::GetSignalInfo.
|
||||
class SiginfoOperation : public Operation
|
||||
class SiginfoOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
SiginfoOperation(lldb::tid_t tid, void *info)
|
||||
|
@ -1052,13 +488,13 @@ namespace
|
|||
void
|
||||
SiginfoOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
PTRACE(PTRACE_GETSIGINFO, m_tid, nullptr, m_info, 0, m_error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETSIGINFO, m_tid, nullptr, m_info, 0, m_error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class EventMessageOperation
|
||||
/// @brief Implements NativeProcessLinux::GetEventMessage.
|
||||
class EventMessageOperation : public Operation
|
||||
class EventMessageOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
EventMessageOperation(lldb::tid_t tid, unsigned long *message)
|
||||
|
@ -1074,10 +510,10 @@ namespace
|
|||
void
|
||||
EventMessageOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
PTRACE(PTRACE_GETEVENTMSG, m_tid, nullptr, m_message, 0, m_error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETEVENTMSG, m_tid, nullptr, m_message, 0, m_error);
|
||||
}
|
||||
|
||||
class DetachOperation : public Operation
|
||||
class DetachOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
DetachOperation(lldb::tid_t tid) : m_tid(tid) { }
|
||||
|
@ -1091,7 +527,7 @@ namespace
|
|||
void
|
||||
DetachOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
PTRACE(PTRACE_DETACH, m_tid, nullptr, 0, 0, m_error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_DETACH, m_tid, nullptr, 0, 0, m_error);
|
||||
}
|
||||
} // end of anonymous namespace
|
||||
|
||||
|
@ -1833,7 +1269,7 @@ NativeProcessLinux::Launch(LaunchArgs *args, Error &error)
|
|||
// send log info to parent re: launch status, in place of the log lines removed here.
|
||||
|
||||
// Start tracing this child that is about to exec.
|
||||
PTRACE(PTRACE_TRACEME, 0, nullptr, nullptr, 0, error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_TRACEME, 0, nullptr, nullptr, 0, error);
|
||||
if (error.Fail())
|
||||
exit(ePtraceFailed);
|
||||
|
||||
|
@ -2070,7 +1506,7 @@ NativeProcessLinux::Attach(lldb::pid_t pid, Error &error)
|
|||
|
||||
// Attach to the requested process.
|
||||
// An attach will cause the thread to stop with a SIGSTOP.
|
||||
PTRACE(PTRACE_ATTACH, tid, nullptr, nullptr, 0, error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_ATTACH, tid, nullptr, nullptr, 0, error);
|
||||
if (error.Fail())
|
||||
{
|
||||
// No such thread. The thread may have exited.
|
||||
|
@ -2162,7 +1598,7 @@ NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid)
|
|||
ptrace_opts |= PTRACE_O_TRACEEXEC;
|
||||
|
||||
Error error;
|
||||
PTRACE(PTRACE_SETOPTIONS, pid, nullptr, (void*)ptrace_opts, 0, error);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void*)ptrace_opts, 0, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -3841,88 +3277,6 @@ NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
|
|||
return op.GetError ();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::ReadRegisterValue(lldb::tid_t tid, uint32_t offset, const char* reg_name,
|
||||
uint32_t size, RegisterValue &value)
|
||||
{
|
||||
ReadRegOperation op(tid, offset, reg_name, value);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
|
||||
const char* reg_name, const RegisterValue &value)
|
||||
{
|
||||
WriteRegOperation op(tid, offset, reg_name, value);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
|
||||
{
|
||||
ReadGPROperation op(tid, buf, buf_size);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
|
||||
{
|
||||
ReadFPROperation op(tid, buf, buf_size);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
|
||||
{
|
||||
ReadRegisterSetOperation op(tid, buf, buf_size, regset);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count , unsigned int &break_count)
|
||||
{
|
||||
ReadDBGROperation op(tid, watch_count, break_count);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count)
|
||||
{
|
||||
WriteDBGROperation op(tid, addr_buf, cntrl_buf, type, count);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
|
||||
{
|
||||
WriteGPROperation op(tid, buf, buf_size);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
|
||||
{
|
||||
WriteFPROperation op(tid, buf, buf_size);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
|
||||
{
|
||||
WriteRegisterSetOperation op(tid, buf, buf_size, regset);
|
||||
m_monitor_up->DoOperation(&op);
|
||||
return op.GetError();
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
|
||||
{
|
||||
|
@ -4431,3 +3785,53 @@ NativeProcessLinux::ThreadWasCreated (lldb::tid_t tid)
|
|||
thread_sp->RequestStop();
|
||||
}
|
||||
}
|
||||
|
||||
Error
|
||||
NativeProcessLinux::DoOperation(Operation* op)
|
||||
{
|
||||
m_monitor_up->DoOperation(op);
|
||||
return op->GetError();
|
||||
}
|
||||
|
||||
// Wrapper for ptrace to catch errors and log calls.
|
||||
// Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
|
||||
long
|
||||
NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, Error& error)
|
||||
{
|
||||
long int result;
|
||||
|
||||
Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
|
||||
|
||||
PtraceDisplayBytes(req, data, data_size);
|
||||
|
||||
error.Clear();
|
||||
errno = 0;
|
||||
if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), *(unsigned int *)addr, data);
|
||||
else
|
||||
result = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), addr, data);
|
||||
|
||||
if (result == -1)
|
||||
error.SetErrorToErrno();
|
||||
|
||||
if (log)
|
||||
log->Printf("ptrace(%d, %" PRIu64 ", %p, %p, %zu)=%lX", req, pid, addr, data, data_size, result);
|
||||
|
||||
PtraceDisplayBytes(req, data, data_size);
|
||||
|
||||
if (log && error.GetError() != 0)
|
||||
{
|
||||
const char* str;
|
||||
switch (error.GetError())
|
||||
{
|
||||
case ESRCH: str = "ESRCH"; break;
|
||||
case EINVAL: str = "EINVAL"; break;
|
||||
case EBUSY: str = "EBUSY"; break;
|
||||
case EPERM: str = "EPERM"; break;
|
||||
default: str = error.AsCString();
|
||||
}
|
||||
log->Printf("ptrace() failed; errno=%d (%s)", error.GetError(), str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,37 @@ namespace process_linux {
|
|||
NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
NativeProcessProtocolSP &native_process_sp);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class Operation
|
||||
/// @brief Represents a NativeProcessLinux operation.
|
||||
///
|
||||
/// Under Linux, it is not possible to ptrace() from any other thread but the
|
||||
/// one that spawned or attached to the process from the start. Therefore, when
|
||||
/// a NativeProcessLinux is asked to deliver or change the state of an inferior
|
||||
/// process the operation must be "funneled" to a specific thread to perform the
|
||||
/// task. The Operation class provides an abstract base for all services the
|
||||
/// NativeProcessLinux must perform via the single virtual function Execute, thus
|
||||
/// encapsulating the code that needs to run in the privileged context.
|
||||
class Operation
|
||||
{
|
||||
public:
|
||||
Operation () : m_error() { }
|
||||
|
||||
virtual
|
||||
~Operation() {}
|
||||
|
||||
virtual void
|
||||
Execute (NativeProcessLinux *process) = 0;
|
||||
|
||||
const Error &
|
||||
GetError () const { return m_error; }
|
||||
|
||||
protected:
|
||||
Error m_error;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Operation> OperationUP;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// NativeProcessProtocol Interface
|
||||
// ---------------------------------------------------------------------
|
||||
|
@ -123,64 +154,20 @@ namespace process_linux {
|
|||
void
|
||||
Terminate () override;
|
||||
|
||||
Error
|
||||
GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) override;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Interface used by NativeRegisterContext-derived classes.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// Reads the contents from the register identified by the given (architecture
|
||||
/// dependent) offset.
|
||||
///
|
||||
/// This method is provided for use by RegisterContextLinux derivatives.
|
||||
Error
|
||||
ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
|
||||
unsigned size, RegisterValue &value);
|
||||
|
||||
/// Writes the given value to the register identified by the given
|
||||
/// (architecture dependent) offset.
|
||||
///
|
||||
/// This method is provided for use by RegisterContextLinux derivatives.
|
||||
Error
|
||||
WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
|
||||
const RegisterValue &value);
|
||||
|
||||
/// Reads all general purpose registers into the specified buffer.
|
||||
Error
|
||||
ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
|
||||
|
||||
/// Reads generic floating point registers into the specified buffer.
|
||||
Error
|
||||
ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
|
||||
|
||||
/// Reads hardware breakpoints and watchpoints capability information.
|
||||
Error
|
||||
ReadHardwareDebugInfo (lldb::tid_t tid, unsigned int &watch_count ,
|
||||
unsigned int &break_count);
|
||||
|
||||
/// Write hardware breakpoint/watchpoint control and address registers.
|
||||
Error
|
||||
WriteHardwareDebugRegs (lldb::tid_t tid, lldb::addr_t *addr_buf,
|
||||
uint32_t *cntrl_buf, int type, int count);
|
||||
|
||||
/// Reads the specified register set into the specified buffer.
|
||||
/// For instance, the extended floating-point register set.
|
||||
Error
|
||||
ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
|
||||
|
||||
/// Writes all general purpose registers into the specified buffer.
|
||||
Error
|
||||
WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
|
||||
|
||||
/// Writes generic floating point registers into the specified buffer.
|
||||
Error
|
||||
WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
|
||||
|
||||
/// Writes the specified register set into the specified buffer.
|
||||
/// For instance, the extended floating-point register set.
|
||||
Error
|
||||
WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
|
||||
DoOperation(Operation* op);
|
||||
|
||||
Error
|
||||
GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) override;
|
||||
DoOperation(OperationUP op) { return DoOperation(op.get()); }
|
||||
|
||||
static long
|
||||
PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, Error& error);
|
||||
|
||||
protected:
|
||||
// ---------------------------------------------------------------------
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
//===-- NativeRegisterContextLinux.h ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_NativeRegisterContextLinux_h
|
||||
#define lldb_NativeRegisterContextLinux_h
|
||||
|
||||
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
|
||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace process_linux {
|
||||
|
||||
class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo
|
||||
{
|
||||
public:
|
||||
NativeRegisterContextLinux(NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
RegisterInfoInterface *reg_info_interface_p);
|
||||
|
||||
// This function is implemented in the NativeRegisterContextLinux_* subclasses to create a new
|
||||
// instance of the host specific NativeRegisterContextLinux. The implementations can't collide
|
||||
// as only one NativeRegisterContextLinux_* variant should be compiled into the final
|
||||
// executable.
|
||||
static NativeRegisterContextLinux*
|
||||
CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
protected:
|
||||
lldb::ByteOrder
|
||||
GetByteOrder() const;
|
||||
|
||||
virtual Error
|
||||
ReadRegisterRaw(uint32_t reg_index, RegisterValue& reg_value);
|
||||
|
||||
virtual Error
|
||||
WriteRegisterRaw(uint32_t reg_index, const RegisterValue& reg_value);
|
||||
|
||||
virtual Error
|
||||
ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset);
|
||||
|
||||
virtual Error
|
||||
WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset);
|
||||
|
||||
virtual Error
|
||||
ReadGPR();
|
||||
|
||||
virtual Error
|
||||
WriteGPR();
|
||||
|
||||
virtual Error
|
||||
ReadFPR();
|
||||
|
||||
virtual Error
|
||||
WriteFPR();
|
||||
|
||||
virtual void*
|
||||
GetGPRBuffer() { return nullptr; };
|
||||
|
||||
virtual size_t
|
||||
GetGPRSize() { return GetRegisterInfoInterface().GetGPRSize(); }
|
||||
|
||||
virtual void*
|
||||
GetFPRBuffer() { return nullptr; }
|
||||
|
||||
virtual size_t
|
||||
GetFPRSize() { return 0; }
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetReadRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
uint32_t size,
|
||||
RegisterValue &value);
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetWriteRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
const RegisterValue &value);
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetReadGPROperation(void *buf, size_t buf_size);
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetWriteGPROperation(void *buf, size_t buf_size);
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetReadFPROperation(void *buf, size_t buf_size);
|
||||
|
||||
virtual NativeProcessLinux::OperationUP
|
||||
GetWriteFPROperation(void *buf, size_t buf_size);
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // #ifndef lldb_NativeRegisterContextLinux_h
|
||||
|
|
@ -7,15 +7,15 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
#include "NativeRegisterContextLinux_arm.h"
|
||||
|
||||
#include "lldb/lldb-private-forward.h"
|
||||
#include "lldb/Core/DataBufferHeap.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
|
||||
|
||||
#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
|
||||
|
||||
|
@ -105,13 +105,20 @@ g_reg_sets_arm[k_num_register_sets] =
|
|||
{ "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
|
||||
};
|
||||
|
||||
NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
RegisterInfoInterface *reg_info_interface_p) :
|
||||
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
|
||||
NativeRegisterContextLinux*
|
||||
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx)
|
||||
{
|
||||
switch (reg_info_interface_p->m_target_arch.GetMachine())
|
||||
return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
|
||||
}
|
||||
|
||||
NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx) :
|
||||
NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch))
|
||||
{
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::arm:
|
||||
m_reg_info.num_registers = k_num_registers_arm;
|
||||
|
@ -172,11 +179,9 @@ NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, Regi
|
|||
|
||||
if (IsFPR(reg))
|
||||
{
|
||||
if (!ReadFPR())
|
||||
{
|
||||
error.SetErrorString ("failed to read floating point register");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -262,10 +267,9 @@ NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, con
|
|||
return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
|
||||
}
|
||||
|
||||
if (!WriteFPR())
|
||||
{
|
||||
return Error ("NativeRegisterContextLinux_arm::WriteRegister: WriteFPR failed");
|
||||
}
|
||||
Error error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
|
||||
return Error ();
|
||||
}
|
||||
|
@ -282,17 +286,13 @@ NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_
|
|||
if (!data_sp)
|
||||
return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE);
|
||||
|
||||
if (!ReadGPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadGPR() failed");
|
||||
error = ReadGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!ReadFPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadFPR() failed");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t *dst = data_sp->GetBytes ();
|
||||
if (dst == nullptr)
|
||||
|
@ -334,196 +334,30 @@ NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP
|
|||
}
|
||||
::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
|
||||
|
||||
if (!WriteGPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
|
||||
error = WriteGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
src += GetRegisterInfoInterface ().GetGPRSize ();
|
||||
::memcpy (&m_fpr, src, sizeof(m_fpr));
|
||||
|
||||
if (!WriteFPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
|
||||
error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_arm::WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteRegisterValue(m_thread.GetID(),
|
||||
register_to_write_info_p->byte_offset,
|
||||
register_to_write_info_p->name,
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_arm::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
|
||||
if (!reg_info)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadRegisterValue(m_thread.GetID(),
|
||||
reg_info->byte_offset,
|
||||
reg_info->name,
|
||||
reg_info->byte_size,
|
||||
reg_value);
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
|
||||
{
|
||||
return reg <= m_reg_info.last_gpr; // GPR's come first.
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::ReadGPR()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::WriteGPR()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
|
||||
{
|
||||
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::ReadFPR ()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm::WriteFPR ()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
|
||||
}
|
||||
|
||||
lldb::ByteOrder
|
||||
NativeRegisterContextLinux_arm::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;
|
||||
}
|
||||
|
||||
size_t
|
||||
NativeRegisterContextLinux_arm::GetGPRSize() const
|
||||
{
|
||||
return GetRegisterInfoInterface().GetGPRSize();
|
||||
}
|
||||
#endif // defined(__arm__)
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__arm__) // arm register context only needed on arm devices
|
||||
|
||||
#ifndef lldb_NativeRegisterContextLinux_arm_h
|
||||
#define lldb_NativeRegisterContextLinux_arm_h
|
||||
|
||||
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
|
||||
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
|
||||
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
@ -19,10 +20,12 @@ namespace process_linux {
|
|||
|
||||
class NativeProcessLinux;
|
||||
|
||||
class NativeRegisterContextLinux_arm : public NativeRegisterContextRegisterInfo
|
||||
class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux
|
||||
{
|
||||
public:
|
||||
NativeRegisterContextLinux_arm (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
|
||||
NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
uint32_t
|
||||
GetRegisterSetCount () const override;
|
||||
|
@ -45,6 +48,16 @@ namespace process_linux {
|
|||
Error
|
||||
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
|
||||
|
||||
protected:
|
||||
void*
|
||||
GetGPRBuffer() override { return &m_gpr_arm; }
|
||||
|
||||
void*
|
||||
GetFPRBuffer() override { return &m_fpr; }
|
||||
|
||||
size_t
|
||||
GetFPRSize() override { return sizeof(m_fpr); }
|
||||
|
||||
private:
|
||||
struct RegInfo
|
||||
{
|
||||
|
@ -84,32 +97,8 @@ namespace process_linux {
|
|||
bool
|
||||
IsGPR(unsigned reg) const;
|
||||
|
||||
bool
|
||||
ReadGPR ();
|
||||
|
||||
bool
|
||||
WriteGPR ();
|
||||
|
||||
bool
|
||||
IsFPR(unsigned reg) const;
|
||||
|
||||
bool
|
||||
ReadFPR ();
|
||||
|
||||
bool
|
||||
WriteFPR ();
|
||||
|
||||
Error
|
||||
ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value);
|
||||
|
||||
Error
|
||||
WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value);
|
||||
|
||||
lldb::ByteOrder
|
||||
GetByteOrder() const;
|
||||
|
||||
size_t
|
||||
GetGPRSize() const;
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
|
@ -117,3 +106,4 @@ namespace process_linux {
|
|||
|
||||
#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h
|
||||
|
||||
#endif // defined(__arm__)
|
||||
|
|
|
@ -7,19 +7,31 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
|
||||
#include "NativeRegisterContextLinux_arm64.h"
|
||||
|
||||
#include "lldb/lldb-private-forward.h"
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Core/DataBufferHeap.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
|
||||
#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
#include "Plugins/Process/Linux/Procfs.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.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>
|
||||
// NT_PRSTATUS and NT_FPREGSET definition
|
||||
#include <elf.h>
|
||||
|
||||
#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
@ -125,13 +137,341 @@ g_reg_sets_arm64[k_num_register_sets] =
|
|||
{ "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
|
||||
};
|
||||
|
||||
NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
RegisterInfoInterface *reg_info_interface_p) :
|
||||
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
|
||||
namespace
|
||||
{
|
||||
switch (reg_info_interface_p->m_target_arch.GetMachine())
|
||||
|
||||
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 ReadDBGROperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
ReadDBGROperation(lldb::tid_t tid, unsigned int &count_wp, unsigned int &count_bp)
|
||||
: m_tid(tid),
|
||||
m_count_wp(count_wp),
|
||||
m_count_bp(count_bp)
|
||||
{ }
|
||||
|
||||
void Execute(NativeProcessLinux *monitor) override;
|
||||
|
||||
private:
|
||||
lldb::tid_t m_tid;
|
||||
unsigned int &m_count_wp;
|
||||
unsigned int &m_count_bp;
|
||||
};
|
||||
|
||||
class WriteDBGROperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
WriteDBGROperation(lldb::tid_t tid, lldb::addr_t *addr_buf,
|
||||
uint32_t *cntrl_buf, int type, int count)
|
||||
: m_tid(tid),
|
||||
m_address(addr_buf),
|
||||
m_control(cntrl_buf),
|
||||
m_type(type),
|
||||
m_count(count)
|
||||
{ }
|
||||
|
||||
void Execute(NativeProcessLinux *monitor) override;
|
||||
|
||||
private:
|
||||
lldb::tid_t m_tid;
|
||||
lldb::addr_t * m_address;
|
||||
uint32_t * m_control;
|
||||
int m_type;
|
||||
int m_count;
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
void
|
||||
ReadRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
if (m_offset > sizeof(struct user_pt_regs))
|
||||
{
|
||||
uintptr_t offset = m_offset - sizeof(struct user_pt_regs);
|
||||
if (offset > sizeof(struct user_fpsimd_state))
|
||||
{
|
||||
m_error.SetErrorString("invalid offset value");
|
||||
return;
|
||||
}
|
||||
elf_fpregset_t regs;
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(regs)) + m_offset), 8, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WriteRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
if (m_offset > sizeof(struct user_pt_regs))
|
||||
{
|
||||
uintptr_t offset = m_offset - sizeof(struct user_pt_regs);
|
||||
if (offset > sizeof(struct user_fpsimd_state))
|
||||
{
|
||||
m_error.SetErrorString("invalid offset value");
|
||||
return;
|
||||
}
|
||||
elf_fpregset_t regs;
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + offset), m_value.GetBytes(), 16);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = ®s;
|
||||
ioVec.iov_len = sizeof regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + m_offset), m_value.GetBytes(), 8);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, ®set, &ioVec, sizeof regs, m_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReadGPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
void
|
||||
WriteGPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
int regset = NT_PRSTATUS;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
void
|
||||
ReadFPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
void
|
||||
WriteFPROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
int regset = NT_FPREGSET;
|
||||
struct iovec ioVec;
|
||||
|
||||
ioVec.iov_base = m_buf;
|
||||
ioVec.iov_len = m_buf_size;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, ®set, &ioVec, m_buf_size, m_error);
|
||||
}
|
||||
|
||||
void
|
||||
ReadDBGROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
int regset = NT_ARM_HW_WATCH;
|
||||
struct iovec ioVec;
|
||||
struct user_hwdebug_state dreg_state;
|
||||
|
||||
ioVec.iov_base = &dreg_state;
|
||||
ioVec.iov_len = sizeof (dreg_state);
|
||||
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len, m_error);
|
||||
|
||||
m_count_wp = dreg_state.dbg_info & 0xff;
|
||||
regset = NT_ARM_HW_BREAK;
|
||||
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, ®set, &ioVec, ioVec.iov_len, m_error);
|
||||
m_count_bp = dreg_state.dbg_info & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
WriteDBGROperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
struct iovec ioVec;
|
||||
struct user_hwdebug_state dreg_state;
|
||||
|
||||
memset (&dreg_state, 0, sizeof (dreg_state));
|
||||
ioVec.iov_base = &dreg_state;
|
||||
ioVec.iov_len = sizeof (dreg_state);
|
||||
|
||||
if (m_type == 0)
|
||||
m_type = NT_ARM_HW_WATCH;
|
||||
else
|
||||
m_type = NT_ARM_HW_BREAK;
|
||||
|
||||
for (int i = 0; i < m_count; i++)
|
||||
{
|
||||
dreg_state.dbg_regs[i].addr = m_address[i];
|
||||
dreg_state.dbg_regs[i].ctrl = m_control[i];
|
||||
}
|
||||
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, &m_type, &ioVec, ioVec.iov_len, m_error);
|
||||
}
|
||||
|
||||
NativeRegisterContextLinux*
|
||||
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx)
|
||||
{
|
||||
return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx);
|
||||
}
|
||||
|
||||
NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx) :
|
||||
NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch))
|
||||
{
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::aarch64:
|
||||
m_reg_info.num_registers = k_num_registers_arm64;
|
||||
|
@ -189,11 +529,9 @@ NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, Re
|
|||
|
||||
if (IsFPR(reg))
|
||||
{
|
||||
if (!ReadFPR())
|
||||
{
|
||||
error.SetErrorString ("failed to read floating point register");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -279,10 +617,9 @@ NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, c
|
|||
return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
|
||||
}
|
||||
|
||||
if (!WriteFPR())
|
||||
{
|
||||
return Error ("NativeRegisterContextLinux_arm64::WriteRegister: WriteFPR failed");
|
||||
}
|
||||
Error error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
|
||||
return Error ();
|
||||
}
|
||||
|
@ -299,17 +636,13 @@ NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &dat
|
|||
if (!data_sp)
|
||||
return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
|
||||
|
||||
if (!ReadGPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadGPR() failed");
|
||||
error = ReadGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!ReadFPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadFPR() failed");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t *dst = data_sp->GetBytes ();
|
||||
if (dst == nullptr)
|
||||
|
@ -351,200 +684,32 @@ NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBuffer
|
|||
}
|
||||
::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
|
||||
|
||||
if (!WriteGPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
|
||||
error = WriteGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
src += GetRegisterInfoInterface ().GetGPRSize ();
|
||||
::memcpy (&m_fpr, src, sizeof(m_fpr));
|
||||
|
||||
if (!WriteFPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
|
||||
error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteRegisterValue(m_thread.GetID(),
|
||||
register_to_write_info_p->byte_offset,
|
||||
register_to_write_info_p->name,
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_arm64::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
|
||||
if (!reg_info)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadRegisterValue(m_thread.GetID(),
|
||||
reg_info->byte_offset,
|
||||
reg_info->name,
|
||||
reg_info->byte_size,
|
||||
reg_value);
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
|
||||
{
|
||||
return reg <= m_reg_info.last_gpr; // GPR's come first.
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::ReadGPR()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::WriteGPR()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
|
||||
{
|
||||
return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::ReadFPR ()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::WriteFPR ()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
|
||||
}
|
||||
|
||||
lldb::ByteOrder
|
||||
NativeRegisterContextLinux_arm64::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;
|
||||
}
|
||||
|
||||
size_t
|
||||
NativeRegisterContextLinux_arm64::GetGPRSize() const
|
||||
{
|
||||
return GetRegisterInfoInterface().GetGPRSize();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
|
||||
{
|
||||
|
@ -557,12 +722,10 @@ NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size
|
|||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
// Check if our hardware breakpoint and watchpoint information is updated.
|
||||
if (m_refresh_hwdebug_info)
|
||||
{
|
||||
process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
|
||||
m_max_hbp_supported);
|
||||
ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported);
|
||||
m_refresh_hwdebug_info = false;
|
||||
}
|
||||
|
||||
|
@ -668,12 +831,11 @@ NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size
|
|||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
// Check if our hardware breakpoint and watchpoint information is updated.
|
||||
if (m_refresh_hwdebug_info)
|
||||
{
|
||||
process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
|
||||
m_max_hbp_supported);
|
||||
ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported);
|
||||
m_refresh_hwdebug_info = false;
|
||||
}
|
||||
|
||||
|
@ -724,8 +886,7 @@ NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size
|
|||
m_hwp_regs[wp_index].refcount = 1;
|
||||
|
||||
// PTRACE call to set corresponding watchpoint register.
|
||||
process_p->WriteHardwareDebugRegs(m_thread.GetID (), &addr,
|
||||
&control_value, 0, wp_index);
|
||||
WriteHardwareDebugRegs(&addr, &control_value, 0, wp_index);
|
||||
}
|
||||
else
|
||||
m_hwp_regs[wp_index].refcount++;
|
||||
|
@ -745,8 +906,6 @@ NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
|
|||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
if (wp_index >= m_max_hwp_supported)
|
||||
return false;
|
||||
|
||||
|
@ -763,10 +922,7 @@ NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
|
|||
m_hwp_regs[wp_index].refcount = 0;
|
||||
|
||||
//TODO: PTRACE CALL HERE for an UPDATE
|
||||
process_p->WriteHardwareDebugRegs(m_thread.GetID (),
|
||||
&m_hwp_regs[wp_index].address,
|
||||
&m_hwp_regs[wp_index].control,
|
||||
0, wp_index);
|
||||
WriteHardwareDebugRegs(&m_hwp_regs[wp_index].address, &m_hwp_regs[wp_index].control, 0, wp_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -788,8 +944,6 @@ NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
|
|||
if (!process_sp)
|
||||
return ml_error;
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
for (uint32_t i = 0; i < m_max_hwp_supported; i++)
|
||||
{
|
||||
if (m_hwp_regs[i].control & 0x01)
|
||||
|
@ -798,10 +952,7 @@ NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
|
|||
m_hwp_regs[i].address = 0;
|
||||
m_hwp_regs[i].refcount = 0;
|
||||
|
||||
process_p->WriteHardwareDebugRegs(m_thread.GetID (),
|
||||
&m_hwp_regs[i].address,
|
||||
&m_hwp_regs[i].control,
|
||||
0, i);
|
||||
WriteHardwareDebugRegs(&m_hwp_regs[i].address, &m_hwp_regs[i].control, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,13 +1038,73 @@ NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
|
|||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_arm64::HardwareSingleStep (bool enable)
|
||||
Error
|
||||
NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo(unsigned int &watch_count,
|
||||
unsigned int &break_count)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess());
|
||||
if (!process_sp)
|
||||
return Error("NativeProcessProtocol is NULL");
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get());
|
||||
|
||||
if (log)
|
||||
log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
|
||||
|
||||
return false;
|
||||
ReadDBGROperation op(m_thread.GetID(), watch_count, break_count);
|
||||
return process_p->DoOperation(&op);
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(lldb::addr_t *addr_buf,
|
||||
uint32_t *cntrl_buf,
|
||||
int type,
|
||||
int count)
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess());
|
||||
if (!process_sp)
|
||||
return Error("NativeProcessProtocol is NULL");
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get());
|
||||
|
||||
WriteDBGROperation op(m_thread.GetID(), addr_buf, cntrl_buf, type, count);
|
||||
return process_p->DoOperation(&op);
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_arm64::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_arm64::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_arm64::GetReadGPROperation(void *buf, size_t buf_size)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new ReadGPROperation(m_thread.GetID(), buf, buf_size));
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_arm64::GetWriteGPROperation(void *buf, size_t buf_size)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new WriteGPROperation(m_thread.GetID(), buf, buf_size));
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_arm64::GetReadFPROperation(void *buf, size_t buf_size)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new ReadFPROperation(m_thread.GetID(), buf, buf_size));
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_arm64::GetWriteFPROperation(void *buf, size_t buf_size)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new WriteFPROperation(m_thread.GetID(), buf, buf_size));
|
||||
}
|
||||
|
||||
#endif // defined (__arm64__) || defined (__aarch64__)
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__arm64__) || defined (__aarch64__)
|
||||
|
||||
#ifndef lldb_NativeRegisterContextLinux_arm64_h
|
||||
#define lldb_NativeRegisterContextLinux_arm64_h
|
||||
|
||||
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
|
||||
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
|
||||
#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
@ -19,12 +20,12 @@ namespace process_linux {
|
|||
|
||||
class NativeProcessLinux;
|
||||
|
||||
class NativeRegisterContextLinux_arm64 : public NativeRegisterContextRegisterInfo
|
||||
class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux
|
||||
{
|
||||
public:
|
||||
NativeRegisterContextLinux_arm64 (NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx,
|
||||
RegisterInfoInterface *reg_info_interface_p);
|
||||
NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
uint32_t
|
||||
GetRegisterSetCount () const override;
|
||||
|
@ -72,15 +73,45 @@ namespace process_linux {
|
|||
lldb::addr_t
|
||||
GetWatchpointAddress (uint32_t wp_index) override;
|
||||
|
||||
bool
|
||||
HardwareSingleStep (bool enable) override;
|
||||
|
||||
uint32_t
|
||||
GetWatchpointSize(uint32_t wp_index);
|
||||
|
||||
bool
|
||||
WatchpointIsEnabled(uint32_t wp_index);
|
||||
|
||||
protected:
|
||||
NativeProcessLinux::OperationUP
|
||||
GetReadRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
uint32_t size,
|
||||
RegisterValue &value) override;
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
GetWriteRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
const RegisterValue &value) override;
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
GetReadGPROperation(void *buf, size_t buf_size) override;
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
GetWriteGPROperation(void *buf, size_t buf_size) override;
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
GetReadFPROperation(void *buf, size_t buf_size) override;
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
GetWriteFPROperation(void *buf, size_t buf_size) override;
|
||||
|
||||
void*
|
||||
GetGPRBuffer() override { return &m_gpr_arm64; }
|
||||
|
||||
void*
|
||||
GetFPRBuffer() override { return &m_fpr; }
|
||||
|
||||
size_t
|
||||
GetFPRSize() override { return sizeof(m_fpr); }
|
||||
|
||||
private:
|
||||
struct RegInfo
|
||||
{
|
||||
|
@ -134,32 +165,14 @@ namespace process_linux {
|
|||
bool
|
||||
IsGPR(unsigned reg) const;
|
||||
|
||||
bool
|
||||
ReadGPR ();
|
||||
|
||||
bool
|
||||
WriteGPR ();
|
||||
|
||||
bool
|
||||
IsFPR(unsigned reg) const;
|
||||
|
||||
bool
|
||||
ReadFPR ();
|
||||
|
||||
bool
|
||||
WriteFPR ();
|
||||
Error
|
||||
ReadHardwareDebugInfo(unsigned int &watch_count , unsigned int &break_count);
|
||||
|
||||
Error
|
||||
ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value);
|
||||
|
||||
Error
|
||||
WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value);
|
||||
|
||||
lldb::ByteOrder
|
||||
GetByteOrder() const;
|
||||
|
||||
size_t
|
||||
GetGPRSize() const;
|
||||
WriteHardwareDebugRegs(lldb::addr_t *addr_buf, uint32_t *cntrl_buf, int type, int count);
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
|
@ -167,3 +180,4 @@ namespace process_linux {
|
|||
|
||||
#endif // #ifndef lldb_NativeRegisterContextLinux_arm64_h
|
||||
|
||||
#endif // defined (__arm64__) || defined (__aarch64__)
|
||||
|
|
|
@ -7,15 +7,20 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__mips__)
|
||||
|
||||
#include "NativeRegisterContextLinux_mips64.h"
|
||||
|
||||
#include "lldb/lldb-private-forward.h"
|
||||
#include "lldb/Core/DataBufferHeap.h"
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
#include "Plugins/Process/Linux/Procfs.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::process_linux;
|
||||
|
@ -86,15 +91,90 @@ namespace
|
|||
{
|
||||
{ "General Purpose Registers", "gpr", k_num_gp_reg_mips64, g_gp_regnums_mips64 }
|
||||
};
|
||||
|
||||
class ReadRegOperation : public NativeProcessLinux::Operation
|
||||
{
|
||||
public:
|
||||
ReadRegOperation(lldb::tid_t tid, uint32_t offset, RegisterValue &value) :
|
||||
m_tid(tid),
|
||||
m_offset(static_cast<uintptr_t>(offset)),
|
||||
m_value(value)
|
||||
{ }
|
||||
|
||||
void
|
||||
Execute(NativeProcessLinux *monitor) override;
|
||||
|
||||
private:
|
||||
lldb::tid_t m_tid;
|
||||
uintptr_t m_offset;
|
||||
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;
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
void
|
||||
ReadRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
lldb_private::ArchSpec arch;
|
||||
if (monitor->GetArchitecture(arch))
|
||||
m_value.SetBytes((void *)(((unsigned char *)(regs)) + m_offset), 8, arch.GetByteOrder());
|
||||
else
|
||||
m_error.SetErrorString("failed to get architecture");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WriteRegOperation::Execute(NativeProcessLinux *monitor)
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
if (m_error.Success())
|
||||
{
|
||||
::memcpy((void *)(((unsigned char *)(®s)) + m_offset), m_value.GetBytes(), 8);
|
||||
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_tid, NULL, ®s, sizeof regs, m_error);
|
||||
}
|
||||
}
|
||||
|
||||
NativeRegisterContextLinux*
|
||||
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx)
|
||||
{
|
||||
return new NativeRegisterContextLinux_mips64(target_arch, native_thread, concrete_frame_idx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// NativeRegisterContextLinux_mips64 members.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64 (NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) :
|
||||
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
|
||||
NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx) :
|
||||
NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_mips64 (target_arch))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -123,33 +203,6 @@ NativeRegisterContextLinux_mips64::GetRegisterSet (uint32_t set_index) const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
lldb_private::Error
|
||||
NativeRegisterContextLinux_mips64::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
|
||||
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
|
||||
if (!reg_info)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadRegisterValue(m_thread.GetID(),
|
||||
reg_info->byte_offset,
|
||||
reg_info->name,
|
||||
reg_info->byte_size,
|
||||
reg_value);
|
||||
}
|
||||
|
||||
lldb_private::Error
|
||||
NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value)
|
||||
{
|
||||
|
@ -182,39 +235,6 @@ NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, R
|
|||
return error;
|
||||
}
|
||||
|
||||
lldb_private::Error
|
||||
NativeRegisterContextLinux_mips64::WriteRegister(const uint32_t reg,
|
||||
const RegisterValue &value)
|
||||
{
|
||||
Error error;
|
||||
|
||||
uint32_t reg_to_write = reg;
|
||||
RegisterValue value_to_write = value;
|
||||
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteRegisterValue(m_thread.GetID(),
|
||||
register_to_write_info_p->byte_offset,
|
||||
register_to_write_info_p->name,
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
|
||||
|
||||
lldb_private::Error
|
||||
NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value)
|
||||
{
|
||||
|
@ -225,7 +245,7 @@ NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info,
|
|||
if (reg_index == LLDB_INVALID_REGNUM)
|
||||
return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
|
||||
|
||||
return WriteRegister(reg_index, reg_value);
|
||||
return WriteRegisterRaw(reg_index, reg_value);
|
||||
}
|
||||
|
||||
Error
|
||||
|
@ -299,3 +319,22 @@ NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints ()
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_mips64::GetReadRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
uint32_t size,
|
||||
RegisterValue &value)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new ReadRegOperation(m_thread.GetID(), offset, value));
|
||||
}
|
||||
|
||||
NativeProcessLinux::OperationUP
|
||||
NativeRegisterContextLinux_mips64::GetWriteRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
const RegisterValue &value)
|
||||
{
|
||||
return NativeProcessLinux::OperationUP(new WriteRegOperation(m_thread.GetID(), offset, reg_name, value));
|
||||
}
|
||||
|
||||
#endif // defined (__mips__)
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__mips__)
|
||||
|
||||
#ifndef lldb_NativeRegisterContextLinux_mips64_h
|
||||
#define lldb_NativeRegisterContextLinux_mips64_h
|
||||
|
||||
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
|
||||
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
|
||||
#include "Plugins/Process/Utility/RegisterContext_mips64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
|
||||
|
||||
|
@ -68,11 +69,12 @@ namespace process_linux {
|
|||
k_num_gp_reg_mips64,
|
||||
};
|
||||
|
||||
class NativeRegisterContextLinux_mips64 : public NativeRegisterContextRegisterInfo
|
||||
class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux
|
||||
{
|
||||
public:
|
||||
NativeRegisterContextLinux_mips64 (NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
|
||||
NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
uint32_t
|
||||
GetRegisterSetCount () const override;
|
||||
|
@ -118,13 +120,17 @@ namespace process_linux {
|
|||
uint32_t
|
||||
NumSupportedHardwareWatchpoints () override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
NativeProcessLinux::OperationUP
|
||||
GetReadRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
uint32_t size,
|
||||
RegisterValue &value) override;
|
||||
|
||||
lldb_private::Error
|
||||
WriteRegister(const uint32_t reg, const RegisterValue &value);
|
||||
|
||||
lldb_private::Error
|
||||
ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value);
|
||||
NativeProcessLinux::OperationUP
|
||||
GetWriteRegisterValueOperation(uint32_t offset,
|
||||
const char* reg_name,
|
||||
const RegisterValue &value) override;
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
|
@ -132,3 +138,4 @@ namespace process_linux {
|
|||
|
||||
#endif // #ifndef lldb_NativeRegisterContextLinux_mips64_h
|
||||
|
||||
#endif // defined (__mips__)
|
||||
|
|
|
@ -7,16 +7,18 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
#include "NativeRegisterContextLinux_x86_64.h"
|
||||
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/lldb-private-forward.h"
|
||||
#include "lldb/Core/DataBufferHeap.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Host/common/NativeThreadProtocol.h"
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::process_linux;
|
||||
|
@ -326,12 +328,39 @@ namespace
|
|||
#define NT_X86_XSTATE 0x202
|
||||
#endif
|
||||
|
||||
NativeRegisterContextLinux*
|
||||
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx)
|
||||
{
|
||||
return new NativeRegisterContextLinux_x86_64(target_arch, native_thread, concrete_frame_idx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// NativeRegisterContextLinux_x86_64 members.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) :
|
||||
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p),
|
||||
static RegisterInfoInterface*
|
||||
CreateRegisterInfoInterface(const ArchSpec& target_arch)
|
||||
{
|
||||
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
|
||||
{
|
||||
// 32-bit hosts run with a RegisterContextLinux_i386 context.
|
||||
return new RegisterContextLinux_i386(target_arch);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
|
||||
"Register setting path assumes this is a 64-bit host");
|
||||
// X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
|
||||
return new RegisterContextLinux_x86_64 (target_arch);
|
||||
}
|
||||
}
|
||||
|
||||
NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx) :
|
||||
NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)),
|
||||
m_fpr_type (eFPRTypeNotValid),
|
||||
m_fpr (),
|
||||
m_iovec (),
|
||||
|
@ -340,7 +369,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (NativeThre
|
|||
m_gpr_x86_64 ()
|
||||
{
|
||||
// Set up data about ranges of valid registers.
|
||||
switch (reg_info_interface_p->GetTargetArchitecture ().GetMachine ())
|
||||
switch (target_arch.GetMachine ())
|
||||
{
|
||||
case llvm::Triple::x86:
|
||||
m_reg_info.num_registers = k_num_registers_i386;
|
||||
|
@ -443,32 +472,6 @@ NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value)
|
||||
{
|
||||
Error error;
|
||||
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
|
||||
if (!reg_info)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->ReadRegisterValue(m_thread.GetID(),
|
||||
reg_info->byte_offset,
|
||||
reg_info->name,
|
||||
reg_info->byte_size,
|
||||
reg_value);
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value)
|
||||
{
|
||||
|
@ -490,11 +493,9 @@ NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, R
|
|||
|
||||
if (IsFPR(reg, GetFPRType()))
|
||||
{
|
||||
if (!ReadFPR())
|
||||
{
|
||||
error.SetErrorString ("failed to read floating point register");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -580,78 +581,6 @@ NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, R
|
|||
return error;
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::WriteRegister(const uint32_t reg,
|
||||
const RegisterValue &value)
|
||||
{
|
||||
Error error;
|
||||
|
||||
uint32_t reg_to_write = reg;
|
||||
RegisterValue value_to_write = value;
|
||||
|
||||
// Check if this is a subregister of a full register.
|
||||
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
|
||||
if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
|
||||
{
|
||||
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 = 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)
|
||||
{
|
||||
error.SetErrorString ("NativeProcessProtocol is NULL");
|
||||
return error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
|
||||
return error;
|
||||
}
|
||||
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
return process_p->WriteRegisterValue(m_thread.GetID(),
|
||||
register_to_write_info_p->byte_offset,
|
||||
register_to_write_info_p->name,
|
||||
value_to_write);
|
||||
}
|
||||
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value)
|
||||
{
|
||||
|
@ -662,7 +591,7 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info,
|
|||
return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
|
||||
|
||||
if (IsGPR(reg_index))
|
||||
return WriteRegister(reg_index, reg_value);
|
||||
return WriteRegisterRaw(reg_index, reg_value);
|
||||
|
||||
if (IsFPR(reg_index, GetFPRType()))
|
||||
{
|
||||
|
@ -710,15 +639,16 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info,
|
|||
}
|
||||
}
|
||||
|
||||
if (WriteFPR())
|
||||
Error error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
|
||||
if (IsAVX(reg_index))
|
||||
{
|
||||
if (IsAVX(reg_index))
|
||||
{
|
||||
if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
|
||||
return Error ("CopyYMMtoXSTATE() failed");
|
||||
}
|
||||
return Error ();
|
||||
if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
|
||||
return Error ("CopyYMMtoXSTATE() failed");
|
||||
}
|
||||
return Error ();
|
||||
}
|
||||
return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
|
||||
}
|
||||
|
@ -735,17 +665,13 @@ NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &da
|
|||
return error;
|
||||
}
|
||||
|
||||
if (!ReadGPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadGPR() failed");
|
||||
error = ReadGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!ReadFPR ())
|
||||
{
|
||||
error.SetErrorString ("ReadFPR() failed");
|
||||
error = ReadFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t *dst = data_sp->GetBytes ();
|
||||
if (dst == nullptr)
|
||||
|
@ -810,11 +736,9 @@ NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBuffe
|
|||
}
|
||||
::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
|
||||
|
||||
if (!WriteGPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
|
||||
error = WriteGPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
src += GetRegisterInfoInterface ().GetGPRSize ();
|
||||
if (GetFPRType () == eFPRTypeFXSAVE)
|
||||
|
@ -822,11 +746,9 @@ NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBuffe
|
|||
else if (GetFPRType () == eFPRTypeXSAVE)
|
||||
::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
|
||||
|
||||
if (!WriteFPR ())
|
||||
{
|
||||
error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
|
||||
error = WriteFPR();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
|
||||
if (GetFPRType() == eFPRTypeXSAVE)
|
||||
{
|
||||
|
@ -860,24 +782,6 @@ NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) c
|
|||
return (set_index < num_sets);
|
||||
}
|
||||
|
||||
lldb::ByteOrder
|
||||
NativeRegisterContextLinux_x86_64::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;
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
|
||||
{
|
||||
|
@ -894,7 +798,7 @@ NativeRegisterContextLinux_x86_64::GetFPRType () const
|
|||
|
||||
// Try and see if AVX register retrieval works.
|
||||
m_fpr_type = eFPRTypeXSAVE;
|
||||
if (!const_cast<NativeRegisterContextLinux_x86_64*> (this)->ReadFPR ())
|
||||
if (const_cast<NativeRegisterContextLinux_x86_64*>(this)->ReadFPR().Fail())
|
||||
{
|
||||
// Fall back to general floating point with no AVX support.
|
||||
m_fpr_type = eFPRTypeFXSAVE;
|
||||
|
@ -920,20 +824,19 @@ NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) c
|
|||
return generic_fpr;
|
||||
}
|
||||
|
||||
bool
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::WriteFPR()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
if (GetFPRType() == eFPRTypeFXSAVE)
|
||||
return process_p->WriteFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave)).Success();
|
||||
|
||||
if (GetFPRType() == eFPRTypeXSAVE)
|
||||
return process_p->WriteRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE).Success();
|
||||
return false;
|
||||
const FPRType fpr_type = GetFPRType ();
|
||||
switch (fpr_type)
|
||||
{
|
||||
case FPRType::eFPRTypeFXSAVE:
|
||||
return NativeRegisterContextLinux::WriteFPR();
|
||||
case FPRType::eFPRTypeXSAVE:
|
||||
return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
|
||||
default:
|
||||
return Error("Unrecognized FPR type");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1003,48 +906,49 @@ NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder
|
|||
return false; // unsupported or invalid byte order
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_x86_64::ReadFPR ()
|
||||
void*
|
||||
NativeRegisterContextLinux_x86_64::GetFPRBuffer()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
const FPRType fpr_type = GetFPRType ();
|
||||
switch (fpr_type)
|
||||
{
|
||||
case FPRType::eFPRTypeFXSAVE:
|
||||
return process_p->ReadFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave)).Success();
|
||||
|
||||
return &m_fpr.xstate.fxsave;
|
||||
case FPRType::eFPRTypeXSAVE:
|
||||
return process_p->ReadRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE).Success();
|
||||
|
||||
return &m_iovec;
|
||||
default:
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_x86_64::ReadGPR()
|
||||
size_t
|
||||
NativeRegisterContextLinux_x86_64::GetFPRSize()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->ReadGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
const FPRType fpr_type = GetFPRType ();
|
||||
switch (fpr_type)
|
||||
{
|
||||
case FPRType::eFPRTypeFXSAVE:
|
||||
return sizeof(m_fpr.xstate.fxsave);
|
||||
case FPRType::eFPRTypeXSAVE:
|
||||
return sizeof(m_iovec);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NativeRegisterContextLinux_x86_64::WriteGPR()
|
||||
Error
|
||||
NativeRegisterContextLinux_x86_64::ReadFPR ()
|
||||
{
|
||||
NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
|
||||
|
||||
return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
|
||||
const FPRType fpr_type = GetFPRType ();
|
||||
switch (fpr_type)
|
||||
{
|
||||
case FPRType::eFPRTypeFXSAVE:
|
||||
return NativeRegisterContextLinux::ReadFPR();
|
||||
case FPRType::eFPRTypeXSAVE:
|
||||
return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
|
||||
default:
|
||||
return Error("Unrecognized FPR type");
|
||||
}
|
||||
}
|
||||
|
||||
Error
|
||||
|
@ -1148,10 +1052,10 @@ NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex(
|
|||
|
||||
control_bits |= enable_bit | rw_bits | size_bits;
|
||||
|
||||
error = WriteRegister(m_reg_info.first_dr + wp_index, RegisterValue(addr));
|
||||
error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
|
||||
if (error.Fail()) return error;
|
||||
|
||||
error = WriteRegister(m_reg_info.first_dr + 7, RegisterValue(control_bits));
|
||||
error = WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
|
||||
if (error.Fail()) return error;
|
||||
|
||||
error.Clear();
|
||||
|
@ -1172,7 +1076,7 @@ NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
|
|||
if (error.Fail()) return false;
|
||||
uint64_t bit_mask = 1 << wp_index;
|
||||
uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||
error = WriteRegister(m_reg_info.first_dr + 6, RegisterValue(status_bits));
|
||||
error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
|
||||
if (error.Fail()) return false;
|
||||
|
||||
// for watchpoints 0, 1, 2, or 3, respectively,
|
||||
|
@ -1182,7 +1086,7 @@ NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index)
|
|||
if (error.Fail()) return false;
|
||||
bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
|
||||
uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||
return WriteRegister(m_reg_info.first_dr + 7, RegisterValue(control_bits)).Success();
|
||||
return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)).Success();
|
||||
}
|
||||
|
||||
Error
|
||||
|
@ -1195,7 +1099,7 @@ NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
|
|||
if (error.Fail()) return error;
|
||||
uint64_t bit_mask = 0xF;
|
||||
uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||
error = WriteRegister(m_reg_info.first_dr + 6, RegisterValue(status_bits));
|
||||
error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
|
||||
if (error.Fail()) return error;
|
||||
|
||||
// clear bits {0-7,16-31} of the debug control register (DR7)
|
||||
|
@ -1203,7 +1107,7 @@ NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints()
|
|||
if (error.Fail()) return error;
|
||||
bit_mask = 0xFF | (0xFFFF << 16);
|
||||
uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
|
||||
return WriteRegister(m_reg_info.first_dr + 7, RegisterValue(control_bits));
|
||||
return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -1248,3 +1152,5 @@ NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints ()
|
|||
// Available debug address registers: dr0, dr1, dr2, dr3
|
||||
return 4;
|
||||
}
|
||||
|
||||
#endif // defined(__i386__) || defined(__x86_64__)
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
#ifndef lldb_NativeRegisterContextLinux_x86_64_h
|
||||
#define lldb_NativeRegisterContextLinux_x86_64_h
|
||||
|
||||
#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
|
||||
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
|
||||
#include "Plugins/Process/Utility/RegisterContext_x86.h"
|
||||
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
|
||||
|
||||
|
@ -20,10 +21,12 @@ namespace process_linux {
|
|||
|
||||
class NativeProcessLinux;
|
||||
|
||||
class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextRegisterInfo
|
||||
class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux
|
||||
{
|
||||
public:
|
||||
NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
|
||||
NativeRegisterContextLinux_x86_64 (const ArchSpec& target_arch,
|
||||
NativeThreadProtocol &native_thread,
|
||||
uint32_t concrete_frame_idx);
|
||||
|
||||
uint32_t
|
||||
GetRegisterSetCount () const override;
|
||||
|
@ -75,6 +78,22 @@ namespace process_linux {
|
|||
uint32_t
|
||||
NumSupportedHardwareWatchpoints() override;
|
||||
|
||||
protected:
|
||||
void*
|
||||
GetGPRBuffer() override { return &m_gpr_x86_64; }
|
||||
|
||||
void*
|
||||
GetFPRBuffer() override;
|
||||
|
||||
size_t
|
||||
GetFPRSize() override;
|
||||
|
||||
Error
|
||||
ReadFPR() override;
|
||||
|
||||
Error
|
||||
WriteFPR() override;
|
||||
|
||||
private:
|
||||
|
||||
// Private member types.
|
||||
|
@ -119,14 +138,8 @@ namespace process_linux {
|
|||
uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
|
||||
|
||||
// Private member methods.
|
||||
Error
|
||||
WriteRegister(const uint32_t reg, const RegisterValue &value);
|
||||
|
||||
bool IsRegisterSetAvailable (uint32_t set_index) const;
|
||||
|
||||
lldb::ByteOrder
|
||||
GetByteOrder() const;
|
||||
|
||||
bool
|
||||
IsGPR(uint32_t reg_index) const;
|
||||
|
||||
|
@ -137,9 +150,7 @@ namespace process_linux {
|
|||
IsFPR(uint32_t reg_index) const;
|
||||
|
||||
bool
|
||||
WriteFPR();
|
||||
|
||||
bool IsFPR(uint32_t reg_index, FPRType fpr_type) const;
|
||||
IsFPR(uint32_t reg_index, FPRType fpr_type) const;
|
||||
|
||||
bool
|
||||
CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order);
|
||||
|
@ -149,18 +160,6 @@ namespace process_linux {
|
|||
|
||||
bool
|
||||
IsAVX (uint32_t reg_index) const;
|
||||
|
||||
bool
|
||||
ReadFPR ();
|
||||
|
||||
Error
|
||||
ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value);
|
||||
|
||||
bool
|
||||
ReadGPR();
|
||||
|
||||
bool
|
||||
WriteGPR();
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
|
@ -168,3 +167,4 @@ namespace process_linux {
|
|||
|
||||
#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h
|
||||
|
||||
#endif // defined(__i386__) || defined(__x86_64__)
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
#include "lldb/Host/HostNativeThread.h"
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
@ -30,13 +28,6 @@
|
|||
|
||||
#include "Plugins/Process/POSIX/CrashReason.h"
|
||||
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
|
||||
#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
|
||||
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
// Try to define a macro to encapsulate the tgkill syscall
|
||||
#define tgkill(pid, tid, sig) \
|
||||
|
@ -172,8 +163,6 @@ NativeThreadLinux::GetRegisterContext ()
|
|||
if (m_reg_context_sp)
|
||||
return m_reg_context_sp;
|
||||
|
||||
// First select the appropriate RegisterInfoInterface.
|
||||
RegisterInfoInterface *reg_interface = nullptr;
|
||||
NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
|
||||
if (!m_process_sp)
|
||||
return NativeRegisterContextSP ();
|
||||
|
@ -182,93 +171,10 @@ NativeThreadLinux::GetRegisterContext ()
|
|||
if (!m_process_sp->GetArchitecture (target_arch))
|
||||
return NativeRegisterContextSP ();
|
||||
|
||||
switch (target_arch.GetTriple().getOS())
|
||||
{
|
||||
case llvm::Triple::Linux:
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
case llvm::Triple::aarch64:
|
||||
assert((HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host");
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch));
|
||||
break;
|
||||
case llvm::Triple::arm:
|
||||
assert(HostInfo::GetArchitecture ().GetAddressByteSize() == 4);
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm(target_arch));
|
||||
break;
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4)
|
||||
{
|
||||
// 32-bit hosts run with a RegisterContextLinux_i386 context.
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
|
||||
"Register setting path assumes this is a 64-bit host");
|
||||
// X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
|
||||
reg_interface = static_cast<RegisterInfoInterface*> (new RegisterContextLinux_x86_64 (target_arch));
|
||||
}
|
||||
break;
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
assert((HostInfo::GetArchitecture ().GetAddressByteSize() == 8)
|
||||
&& "Register setting path assumes this is a 64-bit host");
|
||||
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_mips64 (target_arch));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(reg_interface && "OS or CPU not supported!");
|
||||
if (!reg_interface)
|
||||
return NativeRegisterContextSP ();
|
||||
|
||||
// Now create the register context.
|
||||
switch (target_arch.GetMachine())
|
||||
{
|
||||
#if 0
|
||||
case llvm::Triple::mips64:
|
||||
{
|
||||
RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
|
||||
m_posix_thread = reg_ctx;
|
||||
m_reg_context_sp.reset(reg_ctx);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
{
|
||||
const uint32_t concrete_frame_idx = 0;
|
||||
m_reg_context_sp.reset (new NativeRegisterContextLinux_mips64 (*this, concrete_frame_idx, reg_interface));
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::aarch64:
|
||||
{
|
||||
const uint32_t concrete_frame_idx = 0;
|
||||
m_reg_context_sp.reset (new NativeRegisterContextLinux_arm64(*this, concrete_frame_idx, reg_interface));
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::arm:
|
||||
{
|
||||
const uint32_t concrete_frame_idx = 0;
|
||||
m_reg_context_sp.reset (new NativeRegisterContextLinux_arm(*this, concrete_frame_idx, reg_interface));
|
||||
break;
|
||||
}
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
{
|
||||
const uint32_t concrete_frame_idx = 0;
|
||||
m_reg_context_sp.reset (new NativeRegisterContextLinux_x86_64(*this, concrete_frame_idx, reg_interface));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const uint32_t concrete_frame_idx = 0;
|
||||
m_reg_context_sp.reset (NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(target_arch,
|
||||
*this,
|
||||
concrete_frame_idx));
|
||||
|
||||
return m_reg_context_sp;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
|
|||
#ifndef NT_FPREGSET
|
||||
#define NT_FPREGSET NT_PRFPREG
|
||||
#endif // NT_FPREGSET
|
||||
#endif // defined (__arm64__) || defined (__aarch64__)
|
||||
#elif defined (__mips__)
|
||||
typedef unsigned long elf_greg_t;
|
||||
typedef elf_greg_t elf_gregset_t[(sizeof (struct user_regs_struct) / sizeof(elf_greg_t))];
|
||||
typedef struct user_fpsimd_state elf_fpregset_t;
|
||||
#ifndef NT_FPREGSET
|
||||
#define NT_FPREGSET NT_PRFPREG
|
||||
#endif // NT_FPREGSET
|
||||
#endif
|
||||
#else // __ANDROID__
|
||||
#include <sys/procfs.h>
|
||||
#endif // __ANDROID__
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__mips__)
|
||||
|
||||
#include <vector>
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -150,3 +152,4 @@ RegisterContextLinux_mips64::GetRegisterCount () const
|
|||
return m_register_info_count;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__mips__)
|
||||
|
||||
#ifndef liblldb_RegisterContextLinux_mips64_H_
|
||||
#define liblldb_RegisterContextLinux_mips64_H_
|
||||
|
||||
|
@ -34,3 +36,5 @@ private:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue