diff options
author | emaste <emaste@FreeBSD.org> | 2014-11-26 16:48:12 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2014-11-26 16:48:12 +0000 |
commit | 0147dda7de9580d13778ecb4c9e92b83b7a63911 (patch) | |
tree | b16dc95f693ed59342b6141cd3fd9f59a6cd7e7e /contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp | |
parent | bfd4c39c61ae9b29542625bb12b6f7f4b1f8c727 (diff) | |
parent | 01ee1789d6aa7294e5966a97f8d29387f6f81699 (diff) | |
download | FreeBSD-src-0147dda7de9580d13778ecb4c9e92b83b7a63911.zip FreeBSD-src-0147dda7de9580d13778ecb4c9e92b83b7a63911.tar.gz |
Update LLDB snapshot to upstream r216948 (git 50f7fe44)
This is approximately "LLDB 3.5" although with a little bit of skew,
and will go along with the Clang 3.5 import.
Sponsored by: DARPA, AFRL
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp new file mode 100644 index 0000000..b7a7726 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -0,0 +1,412 @@ +//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeProcessProtocol.h" + +#include "lldb/lldb-enumerations.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/State.h" +#include "lldb/Target/NativeRegisterContext.h" + +#include "NativeThreadProtocol.h" +#include "SoftwareBreakpoint.h" + +using namespace lldb; +using namespace lldb_private; + +// ----------------------------------------------------------------------------- +// NativeProcessProtocol Members +// ----------------------------------------------------------------------------- + +NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) : + m_pid (pid), + m_threads (), + m_current_thread_id (LLDB_INVALID_THREAD_ID), + m_threads_mutex (Mutex::eMutexTypeRecursive), + m_state (lldb::eStateInvalid), + m_state_mutex (Mutex::eMutexTypeRecursive), + m_exit_type (eExitTypeInvalid), + m_exit_status (0), + m_exit_description (), + m_delegates_mutex (Mutex::eMutexTypeRecursive), + m_delegates (), + m_breakpoint_list (), + m_terminal_fd (-1), + m_stop_id (0) +{ +} + +lldb_private::Error +NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) +{ + // Default: not implemented. + return Error ("not implemented"); +} + +bool +NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description) +{ + if (m_state == lldb::eStateExited) + { + *exit_type = m_exit_type; + *status = m_exit_status; + exit_description = m_exit_description; + return true; + } + + *status = 0; + return false; +} + +bool +NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange) +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called", + __FUNCTION__, + exit_type, + status, + exit_description ? exit_description : "nullptr", + bNotifyStateChange ? "true" : "false"); + + // Exit status already set + if (m_state == lldb::eStateExited) + { + if (log) + log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status); + return false; + } + + m_state = lldb::eStateExited; + + m_exit_type = exit_type; + m_exit_status = status; + if (exit_description && exit_description[0]) + m_exit_description = exit_description; + else + m_exit_description.clear(); + + if (bNotifyStateChange) + SynchronouslyNotifyProcessStateChanged (lldb::eStateExited); + + return true; +} + +NativeThreadProtocolSP +NativeProcessProtocol::GetThreadAtIndex (uint32_t idx) +{ + Mutex::Locker locker (m_threads_mutex); + if (idx < m_threads.size ()) + return m_threads[idx]; + return NativeThreadProtocolSP (); +} + +NativeThreadProtocolSP +NativeProcessProtocol::GetThreadByID (lldb::tid_t tid) +{ + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + if (thread_sp->GetID() == tid) + return thread_sp; + } + return NativeThreadProtocolSP (); +} + +bool +NativeProcessProtocol::IsAlive () const +{ + return m_state != eStateDetached + && m_state != eStateExited + && m_state != eStateInvalid + && m_state != eStateUnloaded; +} + +bool +NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const +{ + ArchSpec process_arch; + if (!GetArchitecture (process_arch)) + return false; + byte_order = process_arch.GetByteOrder (); + return true; +} + +uint32_t +NativeProcessProtocol::GetMaxWatchpoints () const +{ + // This default implementation will return the number of + // *hardware* breakpoints available. MacOSX and other OS + // implementations that support software breakpoints will want to + // override this correctly for their implementation. + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + // get any thread + NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0)); + if (!thread_sp) + { + if (log) + log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__); + return 0; + } + + NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ()); + if (!reg_ctx_sp) + { + if (log) + log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__); + return 0; + } + + return reg_ctx_sp->NumSupportedHardwareWatchpoints (); +} + +Error +NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) +{ + // This default implementation assumes setting the watchpoint for + // the process will require setting the watchpoint for each of the + // threads. Furthermore, it will track watchpoints set for the + // process and will add them to each thread that is attached to + // via the (FIXME implement) OnThreadAttached () method. + + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + // FIXME save the watchpoint on the set of process watchpoint vars + // so we can add them to a thread each time a new thread is registered. + + // Update the thread list + UpdateThreads (); + + // Keep track of the threads we successfully set the watchpoint + // for. If one of the thread watchpoint setting operations fails, + // back off and remove the watchpoint for all the threads that + // were successfully set so we get back to a consistent state. + std::vector<NativeThreadProtocolSP> watchpoint_established_threads; + + // Tell each thread to set a watchpoint. In the event that + // hardware watchpoints are requested but the SetWatchpoint fails, + // try to set a software watchpoint as a fallback. It's + // conceivable that if there are more threads than hardware + // watchpoints available, some of the threads will fail to set + // hardware watchpoints while software ones may be available. + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + assert (thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware); + if (thread_error.Fail () && hardware) + { + // Try software watchpoints since we failed on hardware watchpoint setting + // and we may have just run out of hardware watchpoints. + thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false); + if (thread_error.Success ()) + { + if (log) + log->Warning ("hardware watchpoint requested but software watchpoint set"); + } + } + + if (thread_error.Success ()) + { + // Remember that we set this watchpoint successfully in + // case we need to clear it later. + watchpoint_established_threads.push_back (thread_sp); + } + else + { + // Unset the watchpoint for each thread we successfully + // set so that we get back to a consistent state of "not + // set" for the watchpoint. + for (auto unwatch_thread_sp : watchpoint_established_threads) + { + Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr); + if (remove_error.Fail () && log) + { + log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s", + __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ()); + } + } + + return thread_error; + } + } + return Error (); +} + +Error +NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) +{ + // FIXME remove the watchpoint on the set of process watchpoint vars + // so we can add them to a thread each time a new thread is registered. + + // Update the thread list + UpdateThreads (); + + Error overall_error; + + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + assert (thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + const Error thread_error = thread_sp->RemoveWatchpoint (addr); + if (thread_error.Fail ()) + { + // Keep track of the first thread error if any threads + // fail. We want to try to remove the watchpoint from + // every thread, though, even if one or more have errors. + if (!overall_error.Fail ()) + overall_error = thread_error; + } + } + return overall_error; +} + +bool +NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate) +{ + Mutex::Locker locker (m_delegates_mutex); + if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ()) + return false; + + m_delegates.push_back (&native_delegate); + native_delegate.InitializeDelegate (this); + return true; +} + +bool +NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate) +{ + Mutex::Locker locker (m_delegates_mutex); + + const auto initial_size = m_delegates.size (); + m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ()); + + // We removed the delegate if the count of delegates shrank after + // removing all copies of the given native_delegate from the vector. + return m_delegates.size () < initial_size; +} + +void +NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state) +{ + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + Mutex::Locker locker (m_delegates_mutex); + for (auto native_delegate: m_delegates) + native_delegate->ProcessStateChanged (this, state); + + if (log) + { + if (!m_delegates.empty ()) + { + log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64, + __FUNCTION__, lldb_private::StateAsCString (state), GetID ()); + } + else + { + log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates", + __FUNCTION__, lldb_private::StateAsCString (state), GetID ()); + } + } +} + +void +NativeProcessProtocol::NotifyDidExec () +{ + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__); + + { + Mutex::Locker locker (m_delegates_mutex); + for (auto native_delegate: m_delegates) + native_delegate->DidExec (this); + } +} + + +Error +NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + return m_breakpoint_list.AddRef (addr, size_hint, false, + [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error + { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); }); +} + +Error +NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.DecRef (addr); +} + +Error +NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.EnableBreakpoint (addr); +} + +Error +NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.DisableBreakpoint (addr); +} + +lldb::StateType +NativeProcessProtocol::GetState () const +{ + Mutex::Locker locker (m_state_mutex); + return m_state; +} + +void +NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) +{ + Mutex::Locker locker (m_state_mutex); + m_state = state; + + if (StateIsStoppedState (state, false)) + { + ++m_stop_id; + + // Give process a chance to do any stop id bump processing, such as + // clearing cached data that is invalidated each time the process runs. + // Note if/when we support some threads running, we'll end up needing + // to manage this per thread and per process. + DoStopIDBumped (m_stop_id); + } + + // Optionally notify delegates of the state change. + if (notify_delegates) + SynchronouslyNotifyProcessStateChanged (state); +} + +uint32_t NativeProcessProtocol::GetStopID () const +{ + Mutex::Locker locker (m_state_mutex); + return m_stop_id; +} + +void +NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */) +{ + // Default implementation does nothing. +} |