This patch fixes debugging of single threaded apps on Linux.
It also adds some asserts and additional logging support. from dawn@burble.org llvm-svn: 142384
This commit is contained in:
parent
d1bc6da657
commit
0d5f2d425a
@ -13,14 +13,15 @@
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
||||
#include "LinuxStopInfo.h"
|
||||
#include "LinuxThread.h"
|
||||
#include "ProcessLinux.h"
|
||||
#include "ProcessLinuxLog.h"
|
||||
#include "ProcessMonitor.h"
|
||||
#include "RegisterContextLinux_i386.h"
|
||||
#include "RegisterContextLinux_x86_64.h"
|
||||
@ -33,6 +34,9 @@ LinuxThread::LinuxThread(Process &process, lldb::tid_t tid)
|
||||
: Thread(process, tid),
|
||||
m_frame_ap(0)
|
||||
{
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("LinuxThread::%s (tid = %i)", __FUNCTION__, tid);
|
||||
}
|
||||
|
||||
LinuxThread::~LinuxThread()
|
||||
@ -50,6 +54,14 @@ LinuxThread::GetMonitor()
|
||||
void
|
||||
LinuxThread::RefreshStateAfterStop()
|
||||
{
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("LinuxThread::%s ()", __FUNCTION__);
|
||||
|
||||
// Let all threads recover from stopping and do any clean up based
|
||||
// on the previous thread state (if any).
|
||||
ProcessLinux &process = static_cast<ProcessLinux&>(GetProcess());
|
||||
process.GetThreadList().RefreshStateAfterStop();
|
||||
}
|
||||
|
||||
const char *
|
||||
@ -91,13 +103,20 @@ LinuxThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
|
||||
lldb::RegisterContextSP reg_ctx_sp;
|
||||
uint32_t concrete_frame_idx = 0;
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("LinuxThread::%s ()", __FUNCTION__);
|
||||
|
||||
if (frame)
|
||||
concrete_frame_idx = frame->GetConcreteFrameIndex();
|
||||
|
||||
if (concrete_frame_idx == 0)
|
||||
reg_ctx_sp = GetRegisterContext();
|
||||
else
|
||||
{
|
||||
assert(GetUnwinder());
|
||||
reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
|
||||
}
|
||||
|
||||
return reg_ctx_sp;
|
||||
}
|
||||
@ -136,6 +155,10 @@ LinuxThread::Resume()
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
bool status;
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("LinuxThread::%s ()", __FUNCTION__);
|
||||
|
||||
switch (resume_state)
|
||||
{
|
||||
default:
|
||||
@ -160,6 +183,10 @@ LinuxThread::Resume()
|
||||
void
|
||||
LinuxThread::Notify(const ProcessMessage &message)
|
||||
{
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("LinuxThread::%s () message kind = '%s'", __FUNCTION__, message.PrintKind());
|
||||
|
||||
switch (message.GetKind())
|
||||
{
|
||||
default:
|
||||
@ -196,14 +223,20 @@ void
|
||||
LinuxThread::BreakNotify(const ProcessMessage &message)
|
||||
{
|
||||
bool status;
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
|
||||
assert(GetRegisterContextLinux());
|
||||
status = GetRegisterContextLinux()->UpdateAfterBreakpoint();
|
||||
assert(status && "Breakpoint update failed!");
|
||||
|
||||
// With our register state restored, resolve the breakpoint object
|
||||
// corresponding to our current PC.
|
||||
assert(GetRegisterContext());
|
||||
lldb::addr_t pc = GetRegisterContext()->GetPC();
|
||||
if (log)
|
||||
log->Printf ("LinuxThread::%s () PC=0x%8.8llx", __FUNCTION__, pc);
|
||||
lldb::BreakpointSiteSP bp_site(GetProcess().GetBreakpointSiteList().FindByAddress(pc));
|
||||
assert(bp_site);
|
||||
lldb::break_id_t bp_id = bp_site->GetID();
|
||||
assert(bp_site && bp_site->ValidForThisThread(this));
|
||||
|
||||
@ -250,7 +283,68 @@ LinuxThread::CrashNotify(const ProcessMessage &message)
|
||||
|
||||
assert(message.GetKind() == ProcessMessage::eCrashMessage);
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf ("LinuxThread::%s () signo = %i, reason = '%s'", __FUNCTION__, signo, message.PrintCrashReason());
|
||||
|
||||
m_stop_info = lldb::StopInfoSP(new LinuxCrashStopInfo(
|
||||
*this, signo, message.GetCrashReason()));
|
||||
SetResumeSignal(signo);
|
||||
}
|
||||
|
||||
unsigned
|
||||
LinuxThread::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg;
|
||||
ArchSpec arch = Host::GetArchitecture();
|
||||
|
||||
switch (arch.GetCore())
|
||||
{
|
||||
default:
|
||||
assert(false && "CPU type not supported!");
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_x86_32_i386:
|
||||
case ArchSpec::eCore_x86_32_i486:
|
||||
case ArchSpec::eCore_x86_32_i486sx:
|
||||
reg = RegisterContextLinux_i386::GetRegisterIndexFromOffset(offset);
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_x86_64_x86_64:
|
||||
reg = RegisterContextLinux_x86_64::GetRegisterIndexFromOffset(offset);
|
||||
break;
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
const char *
|
||||
LinuxThread::GetRegisterName(unsigned reg)
|
||||
{
|
||||
const char * name;
|
||||
ArchSpec arch = Host::GetArchitecture();
|
||||
|
||||
switch (arch.GetCore())
|
||||
{
|
||||
default:
|
||||
assert(false && "CPU type not supported!");
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_x86_32_i386:
|
||||
case ArchSpec::eCore_x86_32_i486:
|
||||
case ArchSpec::eCore_x86_32_i486sx:
|
||||
name = RegisterContextLinux_i386::GetRegisterName(reg);
|
||||
break;
|
||||
|
||||
case ArchSpec::eCore_x86_64_x86_64:
|
||||
name = RegisterContextLinux_x86_64::GetRegisterName(reg);
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
LinuxThread::GetRegisterNameFromOffset(unsigned offset)
|
||||
{
|
||||
return GetRegisterName(GetRegisterIndexFromOffset(offset));
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,20 @@ public:
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// These static functions provide a mapping from the register offset
|
||||
// back to the register index or name for use in debugging or log
|
||||
// output.
|
||||
|
||||
static unsigned
|
||||
GetRegisterIndexFromOffset(unsigned offset);
|
||||
|
||||
static const char *
|
||||
GetRegisterName(unsigned reg);
|
||||
|
||||
static const char *
|
||||
GetRegisterNameFromOffset(unsigned offset);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// These methods form a specialized interface to linux threads.
|
||||
//
|
||||
|
||||
@ -119,7 +119,7 @@ ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessLinux::%s (pid = %i)", __FUNCTION__, GetID());
|
||||
log->Printf ("ProcessLinux::%s(pid = %i)", __FUNCTION__, GetID());
|
||||
|
||||
m_monitor = new ProcessMonitor(this, pid, error);
|
||||
|
||||
@ -328,6 +328,10 @@ ProcessLinux::SendMessage(const ProcessMessage &message)
|
||||
void
|
||||
ProcessLinux::RefreshStateAfterStop()
|
||||
{
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessLinux::%s()", __FUNCTION__);
|
||||
|
||||
Mutex::Locker lock(m_message_mutex);
|
||||
if (m_message_queue.empty())
|
||||
return;
|
||||
@ -335,10 +339,15 @@ ProcessLinux::RefreshStateAfterStop()
|
||||
ProcessMessage &message = m_message_queue.front();
|
||||
|
||||
// Resolve the thread this message corresponds to and pass it along.
|
||||
// FIXME: we're really dealing with the pid here. This should get
|
||||
// fixed when this code is fixed to handle multiple threads.
|
||||
lldb::tid_t tid = message.GetTID();
|
||||
if (log)
|
||||
log->Printf ("ProcessLinux::%s() pid = %i", __FUNCTION__, tid);
|
||||
LinuxThread *thread = static_cast<LinuxThread*>(
|
||||
GetThreadList().FindThreadByID(tid, false).get());
|
||||
|
||||
assert(thread);
|
||||
thread->Notify(message);
|
||||
|
||||
m_message_queue.pop();
|
||||
@ -355,6 +364,7 @@ size_t
|
||||
ProcessLinux::DoReadMemory(addr_t vm_addr,
|
||||
void *buf, size_t size, Error &error)
|
||||
{
|
||||
assert(m_monitor);
|
||||
return m_monitor->ReadMemory(vm_addr, buf, size, error);
|
||||
}
|
||||
|
||||
@ -362,6 +372,7 @@ size_t
|
||||
ProcessLinux::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
assert(m_monitor);
|
||||
return m_monitor->WriteMemory(vm_addr, buf, size, error);
|
||||
}
|
||||
|
||||
@ -453,12 +464,22 @@ ProcessLinux::UpdateThreadListIfNeeded()
|
||||
uint32_t
|
||||
ProcessLinux::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
|
||||
{
|
||||
// FIXME: Should this be implemented?
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessLinux::%s (pid = %i)", __FUNCTION__, GetID());
|
||||
log->Printf ("ProcessLinux::%s() (pid = %i)", __FUNCTION__, GetID());
|
||||
|
||||
return 0;
|
||||
// Update the process thread list with this new thread.
|
||||
// FIXME: We should be using tid, not pid.
|
||||
assert(m_monitor);
|
||||
ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
|
||||
if (!thread_sp)
|
||||
thread_sp.reset(new LinuxThread(*this, GetID()));
|
||||
|
||||
if (log && log->GetMask().Test(LINUX_LOG_VERBOSE))
|
||||
log->Printf ("ProcessLinux::%s() updated pid = %i", __FUNCTION__, GetID());
|
||||
new_thread_list.AddThread(thread_sp);
|
||||
|
||||
return new_thread_list.GetSize(false);
|
||||
}
|
||||
|
||||
ByteOrder
|
||||
|
||||
@ -177,7 +177,8 @@ public:
|
||||
/// Registers the given message with this process.
|
||||
void SendMessage(const ProcessMessage &message);
|
||||
|
||||
ProcessMonitor &GetMonitor() { return *m_monitor; }
|
||||
ProcessMonitor &
|
||||
GetMonitor() { assert(m_monitor); return *m_monitor; }
|
||||
|
||||
lldb_private::UnixSignals &
|
||||
GetUnixSignals();
|
||||
|
||||
@ -69,6 +69,8 @@ ProcessLinuxLog::DisableLog (Args &args, Stream *feedback_strm)
|
||||
else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~LINUX_LOG_MEMORY_DATA_SHORT;
|
||||
else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~LINUX_LOG_MEMORY_DATA_LONG;
|
||||
else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~LINUX_LOG_PROCESS;
|
||||
else if (::strcasecmp (arg, "ptrace") == 0 ) flag_bits &= ~LINUX_LOG_PTRACE;
|
||||
else if (::strcasecmp (arg, "registers") == 0 ) flag_bits &= ~LINUX_LOG_REGISTERS;
|
||||
else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~LINUX_LOG_STEP;
|
||||
else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~LINUX_LOG_THREAD;
|
||||
else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~LINUX_LOG_VERBOSE;
|
||||
@ -126,6 +128,8 @@ ProcessLinuxLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args
|
||||
else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= LINUX_LOG_MEMORY_DATA_SHORT;
|
||||
else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= LINUX_LOG_MEMORY_DATA_LONG;
|
||||
else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= LINUX_LOG_PROCESS;
|
||||
else if (::strcasecmp (arg, "ptrace") == 0 ) flag_bits |= LINUX_LOG_PTRACE;
|
||||
else if (::strcasecmp (arg, "registers") == 0 ) flag_bits |= LINUX_LOG_REGISTERS;
|
||||
else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= LINUX_LOG_STEP;
|
||||
else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= LINUX_LOG_THREAD;
|
||||
else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= LINUX_LOG_VERBOSE;
|
||||
@ -162,6 +166,10 @@ ProcessLinuxLog::ListLogCategories (Stream *strm)
|
||||
" data-short - log memory bytes for memory reads and writes for short transactions only\n"
|
||||
" data-long - log memory bytes for memory reads and writes for all transactions\n"
|
||||
" process - log process events and activities\n"
|
||||
#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
" ptrace - log all calls to ptrace\n"
|
||||
#endif
|
||||
" registers - log register read/writes\n"
|
||||
" thread - log thread events and activities\n"
|
||||
" step - log step related activities\n"
|
||||
" verbose - enable verbose logging\n"
|
||||
@ -181,3 +189,5 @@ ProcessLinuxLog::LogIf (uint32_t mask, const char *format, ...)
|
||||
va_end (args);
|
||||
}
|
||||
}
|
||||
|
||||
int ProcessLinuxLog::m_nestinglevel;
|
||||
|
||||
@ -29,11 +29,18 @@
|
||||
#define LINUX_LOG_STEP (1u << 9)
|
||||
#define LINUX_LOG_COMM (1u << 10)
|
||||
#define LINUX_LOG_ASYNC (1u << 11)
|
||||
#define LINUX_LOG_PTRACE (1u << 12)
|
||||
#define LINUX_LOG_REGISTERS (1u << 13)
|
||||
#define LINUX_LOG_ALL (UINT32_MAX)
|
||||
#define LINUX_LOG_DEFAULT LINUX_LOG_PACKETS
|
||||
|
||||
// The size which determines "short memory reads/writes".
|
||||
#define LINUX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
|
||||
|
||||
class ProcessLinuxLog
|
||||
{
|
||||
static int m_nestinglevel;
|
||||
|
||||
public:
|
||||
static lldb::LogSP
|
||||
GetLogIfAllCategoriesSet(uint32_t mask = 0);
|
||||
@ -42,13 +49,50 @@ public:
|
||||
DisableLog (lldb_private::Args &args, lldb_private::Stream *feedback_strm);
|
||||
|
||||
static lldb::LogSP
|
||||
EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, lldb_private::Stream *feedback_strm);
|
||||
EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options,
|
||||
lldb_private::Args &args, lldb_private::Stream *feedback_strm);
|
||||
|
||||
static void
|
||||
ListLogCategories (lldb_private::Stream *strm);
|
||||
|
||||
static void
|
||||
LogIf (uint32_t mask, const char *format, ...);
|
||||
|
||||
// The following functions can be used to enable the client to limit
|
||||
// logging to only the top level function calls. This is useful for
|
||||
// recursive functions. FIXME: not thread safe!
|
||||
// Example:
|
||||
// void NestingFunc() {
|
||||
// LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet(LINUX_LOG_ALL));
|
||||
// if (log)
|
||||
// {
|
||||
// ProcessLinuxLog::IncNestLevel();
|
||||
// if (ProcessLinuxLog::AtTopNestLevel())
|
||||
// log->Print(msg);
|
||||
// }
|
||||
// NestingFunc();
|
||||
// if (log)
|
||||
// ProcessLinuxLog::DecNestLevel();
|
||||
// }
|
||||
|
||||
static bool
|
||||
AtTopNestLevel()
|
||||
{
|
||||
return m_nestinglevel == 1;
|
||||
}
|
||||
|
||||
static void
|
||||
IncNestLevel()
|
||||
{
|
||||
++m_nestinglevel;
|
||||
}
|
||||
|
||||
static void
|
||||
DecNestLevel()
|
||||
{
|
||||
--m_nestinglevel;
|
||||
assert(m_nestinglevel >= 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // liblldb_ProcessLinuxLog_h_
|
||||
|
||||
@ -89,3 +89,157 @@ ProcessMessage::GetCrashReasonString(CrashReason reason)
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *
|
||||
ProcessMessage::PrintCrashReason(CrashReason reason)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
// Just return the code in asci for integration builds.
|
||||
chcar str[8];
|
||||
sprintf(str, "%d", reason);
|
||||
#else
|
||||
const char *str = NULL;
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
default:
|
||||
assert(false && "invalid CrashReason");
|
||||
break;
|
||||
|
||||
case eInvalidCrashReason:
|
||||
str = "eInvalidCrashReason";
|
||||
break;
|
||||
|
||||
// SIGSEGV crash rcase easons.
|
||||
case eInvalidAddress:
|
||||
str = "eInvalidAddress";
|
||||
break;
|
||||
case ePrivilegedAddress:
|
||||
str = "ePrivilegedAddress";
|
||||
break;
|
||||
|
||||
// SIGILL crash rcase easons.
|
||||
case eIllegalOpcode:
|
||||
str = "eIllegalOpcode";
|
||||
break;
|
||||
case eIllegalOperand:
|
||||
str = "eIllegalOperand";
|
||||
break;
|
||||
case eIllegalAddressingMode:
|
||||
str = "eIllegalAddressingMode";
|
||||
break;
|
||||
case eIllegalTrap:
|
||||
str = "eIllegalTrap";
|
||||
break;
|
||||
case ePrivilegedOpcode:
|
||||
str = "ePrivilegedOpcode";
|
||||
break;
|
||||
case ePrivilegedRegister:
|
||||
str = "ePrivilegedRegister";
|
||||
break;
|
||||
case eCoprocessorError:
|
||||
str = "eCoprocessorError";
|
||||
break;
|
||||
case eInternalStackError:
|
||||
str = "eInternalStackError";
|
||||
break;
|
||||
|
||||
// SIGBUS crash rcase easons:
|
||||
case eIllegalAlignment:
|
||||
str = "eIllegalAlignment";
|
||||
break;
|
||||
case eIllegalAddress:
|
||||
str = "eIllegalAddress";
|
||||
break;
|
||||
case eHardwareError:
|
||||
str = "eHardwareError";
|
||||
break;
|
||||
|
||||
// SIGFPE crash rcase easons:
|
||||
case eIntegerDivideByZero:
|
||||
str = "eIntegerDivideByZero";
|
||||
break;
|
||||
case eIntegerOverflow:
|
||||
str = "eIntegerOverflow";
|
||||
break;
|
||||
case eFloatDivideByZero:
|
||||
str = "eFloatDivideByZero";
|
||||
break;
|
||||
case eFloatOverflow:
|
||||
str = "eFloatOverflow";
|
||||
break;
|
||||
case eFloatUnderflow:
|
||||
str = "eFloatUnderflow";
|
||||
break;
|
||||
case eFloatInexactResult:
|
||||
str = "eFloatInexactResult";
|
||||
break;
|
||||
case eFloatInvalidOperation:
|
||||
str = "eFloatInvalidOperation";
|
||||
break;
|
||||
case eFloatSubscriptRange:
|
||||
str = "eFloatSubscriptRange";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *
|
||||
ProcessMessage::PrintCrashReason() const
|
||||
{
|
||||
return PrintCrashReason(m_crash_reason);
|
||||
}
|
||||
|
||||
const char *
|
||||
ProcessMessage::PrintKind(Kind kind)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
// Just return the code in asci for integration builds.
|
||||
chcar str[8];
|
||||
sprintf(str, "%d", reason);
|
||||
#else
|
||||
const char *str = NULL;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
default:
|
||||
assert(false && "invalid Kind");
|
||||
break;
|
||||
|
||||
case eInvalidMessage:
|
||||
str = "eInvalidMessage";
|
||||
break;
|
||||
case eExitMessage:
|
||||
str = "eExitMessage";
|
||||
break;
|
||||
case eLimboMessage:
|
||||
str = "eLimboMessage";
|
||||
break;
|
||||
case eSignalMessage:
|
||||
str = "eSignalMessage";
|
||||
break;
|
||||
case eSignalDeliveredMessage:
|
||||
str = "eSignalDeliveredMessage";
|
||||
break;
|
||||
case eTraceMessage:
|
||||
str = "eTraceMessage";
|
||||
break;
|
||||
case eBreakpointMessage:
|
||||
str = "eBreakpointMessage";
|
||||
break;
|
||||
case eCrashMessage:
|
||||
str = "eCrashMessage";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *
|
||||
ProcessMessage::PrintKind() const
|
||||
{
|
||||
return PrintKind(m_kind);
|
||||
}
|
||||
|
||||
@ -140,6 +140,18 @@ public:
|
||||
static const char *
|
||||
GetCrashReasonString(CrashReason reason);
|
||||
|
||||
const char *
|
||||
PrintCrashReason() const;
|
||||
|
||||
static const char *
|
||||
PrintCrashReason(CrashReason reason);
|
||||
|
||||
const char *
|
||||
PrintKind() const;
|
||||
|
||||
static const char *
|
||||
PrintKind(Kind);
|
||||
|
||||
private:
|
||||
ProcessMessage(lldb::tid_t tid, Kind kind,
|
||||
int status = 0, lldb::addr_t addr = 0)
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Core/Scalar.h"
|
||||
@ -29,11 +30,60 @@
|
||||
|
||||
#include "LinuxThread.h"
|
||||
#include "ProcessLinux.h"
|
||||
#include "ProcessLinuxLog.h"
|
||||
#include "ProcessMonitor.h"
|
||||
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
// FIXME: this code is host-dependent with respect to types and
|
||||
// endianness and needs to be fixed. For example, lldb::addr_t is
|
||||
// hard-coded to uint64_t, but on a 32-bit Linux host, ptrace requires
|
||||
// 32-bit pointer arguments. This code uses casts to work around the
|
||||
// problem.
|
||||
|
||||
// We disable the tracing of ptrace calls for integration builds to
|
||||
// avoid the additional indirection and checks.
|
||||
#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
|
||||
|
||||
// Wrapper for ptrace to catch errors and log calls.
|
||||
extern long
|
||||
PtraceWrapper(__ptrace_request req, pid_t pid, void *addr, void *data,
|
||||
const char* reqName, const char* file, int line)
|
||||
{
|
||||
int result;
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PTRACE));
|
||||
if (log)
|
||||
log->Printf("ptrace(%s, %u, %p, %p) called from file %s line %d",
|
||||
reqName, pid, addr, data, file, line);
|
||||
|
||||
errno = 0;
|
||||
result = ptrace(req, pid, addr, data);
|
||||
|
||||
if (log && (result == -1 || errno != 0))
|
||||
{
|
||||
const char* str;
|
||||
switch (errno)
|
||||
{
|
||||
case ESRCH: str = "ESRCH"; break;
|
||||
case EINVAL: str = "EINVAL"; break;
|
||||
case EBUSY: str = "EBUSY"; break;
|
||||
case EPERM: str = "EPERM"; break;
|
||||
default: str = "<unknown>";
|
||||
}
|
||||
log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define PTRACE(req, pid, addr, data) \
|
||||
PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
|
||||
#else
|
||||
#define PTRACE ptrace
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Static implementations of ProcessMonitor::ReadMemory and
|
||||
// ProcessMonitor::WriteMemory. This enables mutual recursion between these
|
||||
@ -48,25 +98,49 @@ DoReadMemory(lldb::pid_t pid, unsigned word_size,
|
||||
size_t remainder;
|
||||
long data;
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_ALL));
|
||||
if (log)
|
||||
ProcessLinuxLog::IncNestLevel();
|
||||
if (log && ProcessLinuxLog::AtTopNestLevel() && log->GetMask().Test(LINUX_LOG_MEMORY))
|
||||
log->Printf ("ProcessMonitor::%s(%d, %d, %p, %p, %d, _)", __FUNCTION__,
|
||||
pid, word_size, (void*)vm_addr, buf, size);
|
||||
|
||||
assert(sizeof(data) >= word_size);
|
||||
assert(sizeof(void*) == word_size);
|
||||
for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
|
||||
{
|
||||
errno = 0;
|
||||
data = ptrace(PTRACE_PEEKDATA, pid, vm_addr, NULL);
|
||||
|
||||
data = PTRACE(PTRACE_PEEKDATA, pid, (void*)vm_addr, NULL);
|
||||
if (data == -1L && errno)
|
||||
{
|
||||
error.SetErrorToErrno();
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
remainder = size - bytes_read;
|
||||
remainder = remainder > word_size ? word_size : remainder;
|
||||
|
||||
// Copy the data into our buffer
|
||||
if (log)
|
||||
memset(dst, 0, sizeof(dst));
|
||||
for (unsigned i = 0; i < remainder; ++i)
|
||||
dst[i] = ((data >> i*8) & 0xFF);
|
||||
|
||||
if (log && ProcessLinuxLog::AtTopNestLevel() &&
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_LONG) ||
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_SHORT) &&
|
||||
size <= LINUX_LOG_MEMORY_SHORT_BYTES)))
|
||||
log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
|
||||
(void*)vm_addr, *(unsigned long*)dst, (unsigned long)data);
|
||||
|
||||
vm_addr += word_size;
|
||||
dst += word_size;
|
||||
}
|
||||
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
@ -78,6 +152,14 @@ DoWriteMemory(lldb::pid_t pid, unsigned word_size,
|
||||
size_t bytes_written = 0;
|
||||
size_t remainder;
|
||||
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_ALL));
|
||||
if (log)
|
||||
ProcessLinuxLog::IncNestLevel();
|
||||
if (log && ProcessLinuxLog::AtTopNestLevel() && log->GetMask().Test(LINUX_LOG_MEMORY))
|
||||
log->Printf ("ProcessMonitor::%s(%d, %d, %p, %p, %d, _)", __FUNCTION__,
|
||||
pid, word_size, (void*)vm_addr, buf, size);
|
||||
|
||||
assert(sizeof(void*) == word_size);
|
||||
for (bytes_written = 0; bytes_written < size; bytes_written += remainder)
|
||||
{
|
||||
remainder = size - bytes_written;
|
||||
@ -86,12 +168,22 @@ DoWriteMemory(lldb::pid_t pid, unsigned word_size,
|
||||
if (remainder == word_size)
|
||||
{
|
||||
unsigned long data = 0;
|
||||
assert(sizeof(data) >= word_size);
|
||||
for (unsigned i = 0; i < word_size; ++i)
|
||||
data |= (unsigned long)src[i] << i*8;
|
||||
|
||||
if (ptrace(PTRACE_POKEDATA, pid, vm_addr, data))
|
||||
if (log && ProcessLinuxLog::AtTopNestLevel() &&
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_LONG) ||
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_SHORT) &&
|
||||
size <= LINUX_LOG_MEMORY_SHORT_BYTES)))
|
||||
log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
|
||||
(void*)vm_addr, *(unsigned long*)src, data);
|
||||
|
||||
if (PTRACE(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data))
|
||||
{
|
||||
error.SetErrorToErrno();
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_written;
|
||||
}
|
||||
}
|
||||
@ -100,18 +192,35 @@ DoWriteMemory(lldb::pid_t pid, unsigned word_size,
|
||||
unsigned char buff[8];
|
||||
if (DoReadMemory(pid, word_size, vm_addr,
|
||||
buff, word_size, error) != word_size)
|
||||
{
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
memcpy(buff, src, remainder);
|
||||
|
||||
if (DoWriteMemory(pid, word_size, vm_addr,
|
||||
buff, word_size, error) != word_size)
|
||||
{
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
if (log && ProcessLinuxLog::AtTopNestLevel() &&
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_LONG) ||
|
||||
(log->GetMask().Test(LINUX_LOG_MEMORY_DATA_SHORT) &&
|
||||
size <= LINUX_LOG_MEMORY_SHORT_BYTES)))
|
||||
log->Printf ("ProcessMonitor::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
|
||||
(void*)vm_addr, *(unsigned long*)src, *(unsigned long*)buff);
|
||||
}
|
||||
|
||||
vm_addr += word_size;
|
||||
src += word_size;
|
||||
}
|
||||
if (log)
|
||||
ProcessLinuxLog::DecNestLevel();
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
@ -216,6 +325,7 @@ WriteOperation::Execute(ProcessMonitor *monitor)
|
||||
m_result = DoWriteMemory(pid, word_size, m_addr, m_buff, m_size, m_error);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @class ReadRegOperation
|
||||
/// @brief Implements ProcessMonitor::ReadRegisterValue.
|
||||
@ -238,11 +348,11 @@ void
|
||||
ReadRegOperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
lldb::pid_t pid = monitor->GetPID();
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_REGISTERS));
|
||||
|
||||
// Set errno to zero so that we can detect a failed peek.
|
||||
errno = 0;
|
||||
uint32_t data = ptrace(PTRACE_PEEKUSER, pid, m_offset, NULL);
|
||||
|
||||
uint32_t data = PTRACE(PTRACE_PEEKUSER, pid, (void*)m_offset, NULL);
|
||||
if (data == -1UL && errno)
|
||||
m_result = false;
|
||||
else
|
||||
@ -250,6 +360,9 @@ ReadRegOperation::Execute(ProcessMonitor *monitor)
|
||||
m_value = data;
|
||||
m_result = true;
|
||||
}
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() reg %s: 0x%x", __FUNCTION__,
|
||||
LinuxThread::GetRegisterNameFromOffset(m_offset), data);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -273,9 +386,22 @@ private:
|
||||
void
|
||||
WriteRegOperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
void* buf;
|
||||
lldb::pid_t pid = monitor->GetPID();
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_REGISTERS));
|
||||
|
||||
if (ptrace(PTRACE_POKEUSER, pid, m_offset, m_value.GetAsUInt64()))
|
||||
if (sizeof(void*) == sizeof(uint64_t))
|
||||
buf = (void*) m_value.GetAsUInt64();
|
||||
else
|
||||
{
|
||||
assert(sizeof(void*) == sizeof(uint32_t));
|
||||
buf = (void*) m_value.GetAsUInt32();
|
||||
}
|
||||
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() reg %s: %p", __FUNCTION__,
|
||||
LinuxThread::GetRegisterNameFromOffset(m_offset), buf);
|
||||
if (PTRACE(PTRACE_POKEUSER, pid, (void*)m_offset, buf))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -301,7 +427,7 @@ private:
|
||||
void
|
||||
ReadGPROperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_GETREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
if (PTRACE(PTRACE_GETREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -327,7 +453,7 @@ private:
|
||||
void
|
||||
ReadFPROperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_GETFPREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
if (PTRACE(PTRACE_GETFPREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -353,7 +479,7 @@ private:
|
||||
void
|
||||
WriteGPROperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_SETREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
if (PTRACE(PTRACE_SETREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -379,7 +505,7 @@ private:
|
||||
void
|
||||
WriteFPROperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_SETFPREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
if (PTRACE(PTRACE_SETFPREGS, monitor->GetPID(), NULL, m_buf) < 0)
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -410,7 +536,7 @@ ResumeOperation::Execute(ProcessMonitor *monitor)
|
||||
if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
data = m_signo;
|
||||
|
||||
if (ptrace(PTRACE_CONT, m_tid, NULL, data))
|
||||
if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -441,7 +567,7 @@ SingleStepOperation::Execute(ProcessMonitor *monitor)
|
||||
if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
data = m_signo;
|
||||
|
||||
if (ptrace(PTRACE_SINGLESTEP, m_tid, NULL, data))
|
||||
if (PTRACE(PTRACE_SINGLESTEP, m_tid, NULL, (void*)data))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -467,7 +593,7 @@ private:
|
||||
void
|
||||
SiginfoOperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_GETSIGINFO, m_tid, NULL, m_info))
|
||||
if (PTRACE(PTRACE_GETSIGINFO, m_tid, NULL, m_info))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -493,7 +619,7 @@ private:
|
||||
void
|
||||
EventMessageOperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
if (ptrace(PTRACE_GETEVENTMSG, m_tid, NULL, m_message))
|
||||
if (PTRACE(PTRACE_GETEVENTMSG, m_tid, NULL, m_message))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -518,7 +644,7 @@ KillOperation::Execute(ProcessMonitor *monitor)
|
||||
{
|
||||
lldb::pid_t pid = monitor->GetPID();
|
||||
|
||||
if (ptrace(PTRACE_KILL, pid, NULL, NULL))
|
||||
if (PTRACE(PTRACE_KILL, pid, NULL, NULL))
|
||||
m_result = false;
|
||||
else
|
||||
m_result = true;
|
||||
@ -756,6 +882,7 @@ ProcessMonitor::Launch(LaunchArgs *args)
|
||||
lldb::pid_t pid;
|
||||
|
||||
lldb::ThreadSP inferior;
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
|
||||
|
||||
// Propagate the environment if one is not supplied.
|
||||
if (envp == NULL || envp[0] == NULL)
|
||||
@ -789,7 +916,7 @@ ProcessMonitor::Launch(LaunchArgs *args)
|
||||
if (pid == 0)
|
||||
{
|
||||
// Trace this process.
|
||||
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0)
|
||||
if (PTRACE(PTRACE_TRACEME, 0, NULL, NULL) < 0)
|
||||
exit(ePtraceFailed);
|
||||
|
||||
// Do not inherit setgid powers.
|
||||
@ -861,7 +988,7 @@ ProcessMonitor::Launch(LaunchArgs *args)
|
||||
|
||||
// Have the child raise an event on exit. This is used to keep the child in
|
||||
// limbo until it is destroyed.
|
||||
if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
|
||||
if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)PTRACE_O_TRACEEXIT) < 0)
|
||||
{
|
||||
args->m_error.SetErrorToErrno();
|
||||
goto FINISH;
|
||||
@ -880,9 +1007,12 @@ ProcessMonitor::Launch(LaunchArgs *args)
|
||||
|
||||
// Update the process thread list with this new thread and mark it as
|
||||
// current.
|
||||
// FIXME: should we be letting UpdateThreadList handle this?
|
||||
// FIXME: by using pids instead of tids, we can only support one thread.
|
||||
inferior.reset(new LinuxThread(process, pid));
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() adding pid = %i", __FUNCTION__, pid);
|
||||
process.GetThreadList().AddThread(inferior);
|
||||
process.GetThreadList().SetSelectedThreadByID(pid);
|
||||
|
||||
// Let our process instance know the thread has stopped.
|
||||
process.SendMessage(ProcessMessage::Trace(pid));
|
||||
@ -943,6 +1073,7 @@ ProcessMonitor::Attach(AttachArgs *args)
|
||||
ProcessLinux &process = monitor->GetProcess();
|
||||
|
||||
lldb::ThreadSP inferior;
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
|
||||
|
||||
if (pid <= 1)
|
||||
{
|
||||
@ -952,7 +1083,7 @@ ProcessMonitor::Attach(AttachArgs *args)
|
||||
}
|
||||
|
||||
// Attach to the requested process.
|
||||
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
|
||||
if (PTRACE(PTRACE_ATTACH, pid, NULL, NULL) < 0)
|
||||
{
|
||||
args->m_error.SetErrorToErrno();
|
||||
goto FINISH;
|
||||
@ -968,6 +1099,8 @@ ProcessMonitor::Attach(AttachArgs *args)
|
||||
// Update the process thread list with the attached thread and
|
||||
// mark it as current.
|
||||
inferior.reset(new LinuxThread(process, pid));
|
||||
if (log)
|
||||
log->Printf ("ProcessMonitor::%s() adding tid = %i", __FUNCTION__, pid);
|
||||
process.GetThreadList().AddThread(inferior);
|
||||
process.GetThreadList().SetSelectedThreadByID(pid);
|
||||
|
||||
@ -987,6 +1120,7 @@ ProcessMonitor::MonitorCallback(void *callback_baton,
|
||||
ProcessMessage message;
|
||||
ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
|
||||
ProcessLinux *process = monitor->m_process;
|
||||
assert(process);
|
||||
bool stop_monitoring;
|
||||
siginfo_t info;
|
||||
|
||||
@ -1017,7 +1151,8 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
|
||||
{
|
||||
ProcessMessage message;
|
||||
|
||||
assert(info->si_signo == SIGTRAP && "Unexpected child signal!");
|
||||
assert(monitor);
|
||||
assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
|
||||
|
||||
switch (info->si_code)
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "lldb/Host/Endian.h"
|
||||
|
||||
#include "ProcessLinux.h"
|
||||
#include "ProcessLinuxLog.h"
|
||||
#include "ProcessMonitor.h"
|
||||
#include "RegisterContextLinux_i386.h"
|
||||
|
||||
@ -31,7 +32,6 @@ enum
|
||||
gpr_esp,
|
||||
gpr_ss,
|
||||
gpr_eflags,
|
||||
gpr_orig_ax,
|
||||
gpr_eip,
|
||||
gpr_cs,
|
||||
gpr_ds,
|
||||
@ -189,7 +189,6 @@ uint32_t g_gpr_regnums[k_num_gpr_registers] =
|
||||
gpr_esp,
|
||||
gpr_ss,
|
||||
gpr_eflags,
|
||||
gpr_orig_ax,
|
||||
gpr_eip,
|
||||
gpr_cs,
|
||||
gpr_ds,
|
||||
@ -330,12 +329,17 @@ g_register_infos[k_num_registers] =
|
||||
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
|
||||
#endif
|
||||
|
||||
static unsigned GetRegOffset(unsigned reg)
|
||||
{
|
||||
assert(reg < k_num_registers && "Invalid register number.");
|
||||
return g_register_infos[reg].byte_offset;
|
||||
}
|
||||
|
||||
#if 0 // These functions are currently not in use.
|
||||
static unsigned GetRegSize(unsigned reg)
|
||||
{
|
||||
assert(reg < k_num_registers && "Invalid register number.");
|
||||
@ -351,6 +355,7 @@ static bool IsFPR(unsigned reg)
|
||||
{
|
||||
return (k_first_fpr <= reg && reg <= k_last_fpr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
RegisterContextLinux_i386::RegisterContextLinux_i386(Thread &thread,
|
||||
@ -383,12 +388,14 @@ RegisterContextLinux_i386::InvalidateAllRegisters()
|
||||
size_t
|
||||
RegisterContextLinux_i386::GetRegisterCount()
|
||||
{
|
||||
assert(k_num_register_infos == k_num_registers);
|
||||
return k_num_registers;
|
||||
}
|
||||
|
||||
const RegisterInfo *
|
||||
RegisterContextLinux_i386::GetRegisterInfoAtIndex(uint32_t reg)
|
||||
{
|
||||
assert(k_num_register_infos == k_num_registers);
|
||||
if (reg < k_num_registers)
|
||||
return &g_register_infos[reg];
|
||||
else
|
||||
@ -410,6 +417,26 @@ RegisterContextLinux_i386::GetRegisterSet(uint32_t set)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RegisterContextLinux_i386::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg;
|
||||
for (reg = 0; reg < k_num_registers; reg++)
|
||||
{
|
||||
if (g_register_infos[reg].byte_offset == offset)
|
||||
break;
|
||||
}
|
||||
assert(reg < k_num_registers && "Invalid register offset.");
|
||||
return reg;
|
||||
}
|
||||
|
||||
const char *
|
||||
RegisterContextLinux_i386::GetRegisterName(unsigned reg)
|
||||
{
|
||||
assert(reg < k_num_registers && "Invalid register offset.");
|
||||
return g_register_infos[reg].name;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextLinux_i386::ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue &value)
|
||||
@ -588,11 +615,31 @@ RegisterContextLinux_i386::HardwareSingleStep(bool enable)
|
||||
return WriteRegisterFromUnsigned(gpr_eflags, eflags);
|
||||
}
|
||||
|
||||
void
|
||||
RegisterContextLinux_i386::LogGPR(const char *title)
|
||||
{
|
||||
LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_REGISTERS));
|
||||
if (log)
|
||||
{
|
||||
if (title)
|
||||
log->Printf ("%s", title);
|
||||
for (uint32_t i=0; i<k_num_gpr_registers; i++)
|
||||
{
|
||||
uint32_t reg = gpr_eax + i;
|
||||
log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&user.regs)[reg]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextLinux_i386::ReadGPR()
|
||||
{
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
return monitor.ReadGPR(&user.regs);
|
||||
bool result;
|
||||
|
||||
ProcessMonitor &monitor = GetMonitor();
|
||||
result = monitor.ReadGPR(&user.regs);
|
||||
LogGPR("RegisterContextLinux_i386::ReadGPR()");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "RegisterContextLinux.h"
|
||||
|
||||
class RegisterContextLinux_i386 : public RegisterContextLinux
|
||||
@ -42,6 +43,12 @@ public:
|
||||
const lldb_private::RegisterSet *
|
||||
GetRegisterSet(uint32_t set);
|
||||
|
||||
static unsigned
|
||||
GetRegisterIndexFromOffset(unsigned offset);
|
||||
|
||||
static const char *
|
||||
GetRegisterName(unsigned reg);
|
||||
|
||||
#if 0
|
||||
bool
|
||||
ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value);
|
||||
@ -153,6 +160,8 @@ private:
|
||||
|
||||
ProcessMonitor &GetMonitor();
|
||||
|
||||
void LogGPR(const char *title);
|
||||
|
||||
bool ReadGPR();
|
||||
bool ReadFPR();
|
||||
};
|
||||
|
||||
@ -405,6 +405,7 @@ static unsigned GetRegOffset(unsigned reg)
|
||||
return g_register_infos[reg].byte_offset;
|
||||
}
|
||||
|
||||
#if 0 // These functions are currently not being used.
|
||||
static unsigned GetRegSize(unsigned reg)
|
||||
{
|
||||
assert(reg < k_num_registers && "Invalid register number.");
|
||||
@ -420,6 +421,7 @@ static bool IsFPR(unsigned reg)
|
||||
{
|
||||
return (k_first_fpr <= reg && reg <= k_last_fpr);
|
||||
}
|
||||
#endif
|
||||
|
||||
RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread,
|
||||
uint32_t concrete_frame_idx)
|
||||
@ -478,6 +480,26 @@ RegisterContextLinux_x86_64::GetRegisterSet(uint32_t set)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned
|
||||
RegisterContextLinux_x86_64::GetRegisterIndexFromOffset(unsigned offset)
|
||||
{
|
||||
unsigned reg;
|
||||
for (reg = 0; reg < k_num_registers; reg++)
|
||||
{
|
||||
if (g_register_infos[reg].byte_offset == offset)
|
||||
break;
|
||||
}
|
||||
assert(reg < k_num_registers && "Invalid register offset.");
|
||||
return reg;
|
||||
}
|
||||
|
||||
const char *
|
||||
RegisterContextLinux_x86_64::GetRegisterName(unsigned reg)
|
||||
{
|
||||
assert(reg < k_num_registers && "Invalid register offset.");
|
||||
return g_register_infos[reg].name;
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue &value)
|
||||
|
||||
@ -41,6 +41,12 @@ public:
|
||||
const lldb_private::RegisterSet *
|
||||
GetRegisterSet(uint32_t set);
|
||||
|
||||
static unsigned
|
||||
GetRegisterIndexFromOffset(unsigned offset);
|
||||
|
||||
static const char *
|
||||
GetRegisterName(unsigned reg);
|
||||
|
||||
virtual bool
|
||||
ReadRegister(const lldb_private::RegisterInfo *reg_info,
|
||||
lldb_private::RegisterValue &value);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user