[Lldb-commits] [PATCH] fixes for Linux
dawn at burble.org
dawn at burble.org
Mon Oct 17 10:36:09 PDT 2011
Seems I forgot the patch? Doh!
On Fri, Oct 14, 2011 at 07:58:53PM -0700, dawn at burble.org wrote:
> This patch fixes debugging of single threaded apps on Linux.
> It also adds some asserts and additional logging support.
>
> Thanks in advance,
> -Dawn
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
-------------- next part --------------
Index: source/Plugins/Process/Linux/ProcessLinux.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessLinux.cpp (revision 142029)
+++ source/Plugins/Process/Linux/ProcessLinux.cpp (working copy)
@@ -119,7 +119,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
Index: source/Plugins/Process/Linux/ProcessLinuxLog.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessLinuxLog.cpp (revision 142029)
+++ source/Plugins/Process/Linux/ProcessLinuxLog.cpp (working copy)
@@ -69,6 +69,8 @@
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 @@
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 @@
" 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 @@
va_end (args);
}
}
+
+int ProcessLinuxLog::m_nestinglevel;
Index: source/Plugins/Process/Linux/ProcessLinux.h
===================================================================
--- source/Plugins/Process/Linux/ProcessLinux.h (revision 142029)
+++ source/Plugins/Process/Linux/ProcessLinux.h (working copy)
@@ -177,7 +177,8 @@
/// 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();
Index: source/Plugins/Process/Linux/ProcessLinuxLog.h
===================================================================
--- source/Plugins/Process/Linux/ProcessLinuxLog.h (revision 142029)
+++ source/Plugins/Process/Linux/ProcessLinuxLog.h (working copy)
@@ -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 @@
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_
Index: source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp
===================================================================
--- source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp (revision 142029)
+++ source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp (working copy)
@@ -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 @@
gpr_esp,
gpr_ss,
gpr_eflags,
- gpr_orig_ax,
gpr_eip,
gpr_cs,
gpr_ds,
@@ -189,7 +189,6 @@
gpr_esp,
gpr_ss,
gpr_eflags,
- gpr_orig_ax,
gpr_eip,
gpr_cs,
gpr_ds,
@@ -330,12 +329,17 @@
};
+#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 @@
{
return (k_first_fpr <= reg && reg <= k_last_fpr);
}
+#endif
RegisterContextLinux_i386::RegisterContextLinux_i386(Thread &thread,
@@ -383,12 +388,14 @@
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 @@
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 @@
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
Index: source/Plugins/Process/Linux/ProcessMessage.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessMessage.cpp (revision 142029)
+++ source/Plugins/Process/Linux/ProcessMessage.cpp (working copy)
@@ -89,3 +89,157 @@
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);
+}
Index: source/Plugins/Process/Linux/ProcessMonitor.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessMonitor.cpp (revision 142029)
+++ source/Plugins/Process/Linux/ProcessMonitor.cpp (working copy)
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
m_result = DoWriteMemory(pid, word_size, m_addr, m_buff, m_size, m_error);
}
+
//------------------------------------------------------------------------------
/// @class ReadRegOperation
/// @brief Implements ProcessMonitor::ReadRegisterValue.
@@ -238,11 +348,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
ProcessLinux &process = monitor->GetProcess();
lldb::ThreadSP inferior;
+ LogSP log (ProcessLinuxLog::GetLogIfAllCategoriesSet (LINUX_LOG_PROCESS));
if (pid <= 1)
{
@@ -952,7 +1083,7 @@
}
// 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 @@
// 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 @@
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 @@
{
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)
{
Index: source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp
===================================================================
--- source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp (revision 142029)
+++ source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp (working copy)
@@ -405,6 +405,7 @@
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 @@
{
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 @@
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)
Index: source/Plugins/Process/Linux/LinuxThread.cpp
===================================================================
--- source/Plugins/Process/Linux/LinuxThread.cpp (revision 142029)
+++ source/Plugins/Process/Linux/LinuxThread.cpp (working copy)
@@ -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 @@
: 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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));
+}
+
Index: source/Plugins/Process/Linux/RegisterContextLinux_i386.h
===================================================================
--- source/Plugins/Process/Linux/RegisterContextLinux_i386.h (revision 142029)
+++ source/Plugins/Process/Linux/RegisterContextLinux_i386.h (working copy)
@@ -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 @@
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 @@
ProcessMonitor &GetMonitor();
+ void LogGPR(const char *title);
+
bool ReadGPR();
bool ReadFPR();
};
Index: source/Plugins/Process/Linux/ProcessMessage.h
===================================================================
--- source/Plugins/Process/Linux/ProcessMessage.h (revision 142029)
+++ source/Plugins/Process/Linux/ProcessMessage.h (working copy)
@@ -140,6 +140,18 @@
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)
Index: source/Plugins/Process/Linux/LinuxThread.h
===================================================================
--- source/Plugins/Process/Linux/LinuxThread.h (revision 142029)
+++ source/Plugins/Process/Linux/LinuxThread.h (working copy)
@@ -48,6 +48,20 @@
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.
//
bool Resume();
Index: source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h
===================================================================
--- source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h (revision 142029)
+++ source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h (working copy)
@@ -41,6 +41,12 @@
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);
More information about the lldb-commits
mailing list