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:
Tamas Berghammer 2015-05-26 11:58:52 +00:00
parent b2b901c607
commit 068f8a7e2d
17 changed files with 1464 additions and 1595 deletions

View File

@ -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
)

View File

@ -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 = &regs;
ioVec.iov_len = sizeof regs;
PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
ArchSpec arch;
if (monitor->GetArchitecture(arch))
m_value.SetBytes((void *)(((unsigned char *)(&regs)) + 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 = &regs;
ioVec.iov_len = sizeof regs;
PTRACE(PTRACE_GETREGSET, m_tid, &regset, &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, &regs, 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 = &regs;
ioVec.iov_len = sizeof regs;
PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + offset), m_value.GetBytes(), 16);
PTRACE(PTRACE_SETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
}
}
else
{
elf_gregset_t regs;
int regset = NT_PRSTATUS;
struct iovec ioVec;
ioVec.iov_base = &regs;
ioVec.iov_len = sizeof regs;
PTRACE(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + m_offset), m_value.GetBytes(), 8);
PTRACE(PTRACE_SETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
}
}
#elif defined (__mips__)
elf_gregset_t regs;
PTRACE(PTRACE_GETREGS, m_tid, NULL, &regs, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + m_offset), m_value.GetBytes(), 8);
PTRACE(PTRACE_SETREGS, m_tid, NULL, &regs, 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, &regset, &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, &regset, &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, &regset, &ioVec, ioVec.iov_len, m_error);
m_count_wp = dreg_state.dbg_info & 0xff;
regset = NT_ARM_HW_BREAK;
PTRACE(PTRACE_GETREGSET, m_tid, &regset, &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, &regset, &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, &regset, &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;
}

View File

@ -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:
// ---------------------------------------------------------------------

View File

@ -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 &reg_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 &reg_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));
}

View File

@ -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

View File

@ -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 (
NativeRegisterContextLinux*
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
NativeThreadProtocol &native_thread,
uint32_t concrete_frame_idx,
RegisterInfoInterface *reg_info_interface_p) :
NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
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,12 +179,10 @@ 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
{
uint32_t full_reg = reg;
@ -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__);
return error;
}
return error;
}
Error
NativeRegisterContextLinux_arm::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_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);
error = WriteFPR();
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 &reg_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__)

View File

@ -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 &reg_value);
Error
WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_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__)

View File

@ -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 = &regs;
ioVec.iov_len = sizeof regs;
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
ArchSpec arch;
if (monitor->GetArchitecture(arch))
m_value.SetBytes((void *)(((unsigned char *)(&regs)) + 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 = &regs;
ioVec.iov_len = sizeof regs;
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, &regset, &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 = &regs;
ioVec.iov_len = sizeof regs;
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + offset), m_value.GetBytes(), 16);
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
}
}
else
{
elf_gregset_t regs;
int regset = NT_PRSTATUS;
struct iovec ioVec;
ioVec.iov_base = &regs;
ioVec.iov_len = sizeof regs;
NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_tid, &regset, &ioVec, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + m_offset), m_value.GetBytes(), 8);
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_tid, &regset, &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, &regset, &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, &regset, &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, &regset, &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, &regset, &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, &regset, &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, &regset, &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,12 +529,10 @@ 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
{
uint32_t full_reg = reg;
@ -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__);
return error;
}
return error;
}
Error
NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_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);
error = WriteFPR();
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 &reg_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__)

View File

@ -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 &reg_value);
Error
WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_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__)

View File

@ -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, &regs, 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, &regs, sizeof regs, m_error);
if (m_error.Success())
{
::memcpy((void *)(((unsigned char *)(&regs)) + m_offset), m_value.GetBytes(), 8);
NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_tid, NULL, &regs, 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 &reg_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 &reg_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 &reg_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__)

View File

@ -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 &reg_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__)

View File

@ -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 &reg_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 &reg_value)
{
@ -490,12 +493,10 @@ 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
{
uint32_t full_reg = reg;
@ -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 &reg_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,8 +639,10 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info,
}
}
if (WriteFPR())
{
Error error = WriteFPR();
if (error.Fail())
return error;
if (IsAVX(reg_index))
{
if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
@ -719,7 +650,6 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info,
}
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__)

View File

@ -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 &reg_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__)

View File

@ -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;
}
m_reg_context_sp.reset (NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(target_arch,
*this,
concrete_frame_idx));
return m_reg_context_sp;
}

View File

@ -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__

View File

@ -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

View File

@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
#if defined (__mips__)
#ifndef liblldb_RegisterContextLinux_mips64_H_
#define liblldb_RegisterContextLinux_mips64_H_
@ -34,3 +36,5 @@ private:
};
#endif
#endif