diff options
| author | Johnny Chen <johnny.chen@apple.com> | 2011-10-18 18:09:30 +0000 |
|---|---|---|
| committer | Johnny Chen <johnny.chen@apple.com> | 2011-10-18 18:09:30 +0000 |
| commit | 0d5f2d425aef5bc593c81be4d7573f3c19e050d3 (patch) | |
| tree | ad2e0e1bd007a0afa5f6b08db6c98c5a331a9232 | |
| parent | d1bc6da6575160887cd7e8e4b82016bc555ed792 (diff) | |
| download | bcm5719-llvm-0d5f2d425aef5bc593c81be4d7573f3c19e050d3.tar.gz bcm5719-llvm-0d5f2d425aef5bc593c81be4d7573f3c19e050d3.zip | |
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
13 files changed, 600 insertions, 31 deletions
diff --git a/lldb/source/Plugins/Process/Linux/LinuxThread.cpp b/lldb/source/Plugins/Process/Linux/LinuxThread.cpp index c6e0e553e44..7745cc9360f 100644 --- a/lldb/source/Plugins/Process/Linux/LinuxThread.cpp +++ b/lldb/source/Plugins/Process/Linux/LinuxThread.cpp @@ -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)); +} + diff --git a/lldb/source/Plugins/Process/Linux/LinuxThread.h b/lldb/source/Plugins/Process/Linux/LinuxThread.h index e7d23b840f9..f6253107d24 100644 --- a/lldb/source/Plugins/Process/Linux/LinuxThread.h +++ b/lldb/source/Plugins/Process/Linux/LinuxThread.h @@ -48,6 +48,20 @@ public: 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(); diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp index cffb1f6f43c..323b8631472 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -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()); + + // 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 0; + return new_thread_list.GetSize(false); } ByteOrder diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinux.h b/lldb/source/Plugins/Process/Linux/ProcessLinux.h index 713e8ba6095..1a984431cc7 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/ProcessLinux.h @@ -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(); diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.cpp b/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.cpp index e3bd6e85870..c07263e891c 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.cpp @@ -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; diff --git a/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.h b/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.h index e4e178455d8..0553df6d1e4 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.h +++ b/lldb/source/Plugins/Process/Linux/ProcessLinuxLog.h @@ -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_ diff --git a/lldb/source/Plugins/Process/Linux/ProcessMessage.cpp b/lldb/source/Plugins/Process/Linux/ProcessMessage.cpp index db7827d551d..ad3fc7f3629 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMessage.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessMessage.cpp @@ -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); +} diff --git a/lldb/source/Plugins/Process/Linux/ProcessMessage.h b/lldb/source/Plugins/Process/Linux/ProcessMessage.h index 5162d30825c..826567e582b 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMessage.h +++ b/lldb/source/Plugins/Process/Linux/ProcessMessage.h @@ -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) diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp index d708ae18362..ff1e024f94b 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -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 (sizeof(void*) == sizeof(uint64_t)) + buf = (void*) m_value.GetAsUInt64(); + else + { + assert(sizeof(void*) == sizeof(uint32_t)); + buf = (void*) m_value.GetAsUInt32(); + } - if (ptrace(PTRACE_POKEUSER, pid, m_offset, m_value.GetAsUInt64())) + 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) { diff --git a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp index cc669d53a16..20c3c73c589 100644 --- a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp +++ b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp @@ -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 diff --git a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.h b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.h index ef3a76b8e0a..718e831abb0 100644 --- a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.h +++ b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_i386.h @@ -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(); }; diff --git a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp index 51a2545ec1c..040c14eda51 100644 --- a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp @@ -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) diff --git a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h index 5ffef194b7e..def85f6840d 100644 --- a/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h @@ -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); |

