diff options
-rw-r--r-- | lldb/include/lldb/Target/Thread.h | 13 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 109 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h | 1 | ||||
-rw-r--r-- | lldb/source/Target/Process.cpp | 5 |
4 files changed, 121 insertions, 7 deletions
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index cdd66c0199e..966fd707b0f 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -775,6 +775,13 @@ public: { return m_destroy_called; } + + // When you implement this method, make sure you don't overwrite the m_actual_stop_info if it claims to be + // valid. The stop info may be a "checkpointed and restored" stop info, so if it is still around it is right + // even if you have not calculated this yourself, or if it disagrees with what you might have calculated. + virtual lldb::StopInfoSP + GetPrivateStopReason () = 0; + protected: friend class ThreadPlan; @@ -796,12 +803,6 @@ protected: ThreadPlan *GetPreviousPlan (ThreadPlan *plan); - // When you implement this method, make sure you don't overwrite the m_actual_stop_info if it claims to be - // valid. The stop info may be a "checkpointed and restored" stop info, so if it is still around it is right - // even if you have not calculated this yourself, or if it disagrees with what you might have calculated. - virtual lldb::StopInfoSP - GetPrivateStopReason () = 0; - typedef std::vector<lldb::ThreadPlanSP> plan_stack; void diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index e48c058d7ab..7479d1e7d4c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -47,6 +47,7 @@ // Project includes #include "lldb/Host/Host.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Utility/StringExtractorGDBRemote.h" #include "GDBRemoteRegisterContext.h" #include "ProcessGDBRemote.h" @@ -175,7 +176,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_max_memory_size (512), m_addr_to_mmap_size (), m_thread_create_bp_sp (), - m_waiting_for_attach (false) + m_waiting_for_attach (false), + m_destroy_tried_resuming (false) { m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); @@ -1689,6 +1691,7 @@ ProcessGDBRemote::DoDetach() return error; } + Error ProcessGDBRemote::DoDestroy () { @@ -1697,6 +1700,110 @@ ProcessGDBRemote::DoDestroy () if (log) log->Printf ("ProcessGDBRemote::DoDestroy()"); + // There is a bug in older iOS debugservers where they don't shut down the process + // they are debugging properly. If the process is sitting at a breakpoint or an exception, + // this can cause problems with restarting. So we check to see if any of our threads are stopped + // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN + // destroy it again. + // + // Note, we don't have a good way to test the version of debugserver, but I happen to know that + // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of + // the debugservers with this bug are equal. There really should be a better way to test this! + // + // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and + // get called here to destroy again and we're still at a breakpoint or exception, then we should + // just do the straight-forward kill. + // + // And of course, if we weren't able to stop the process by the time we get here, it isn't + // necessary (or helpful) to do any of this. + + if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning) + { + PlatformSP platform_sp = GetTarget().GetPlatform(); + + // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. + if (platform_sp + && platform_sp->GetName() + && strcmp (platform_sp->GetName(), PlatformRemoteiOS::GetShortPluginNameStatic()) == 0) + { + if (m_destroy_tried_resuming) + { + if (log) + log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again."); + } + else + { + // At present, the plans are discarded and the breakpoints disabled Process::Destroy, + // but we really need it to happen here and it doesn't matter if we do it twice. + m_thread_list.DiscardThreadPlans(); + DisableAllBreakpointSites(); + + bool stop_looks_like_crash = false; + ThreadList &threads = GetThreadList(); + + { + Mutex::Locker(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) + { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopReason(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason == eStopReasonBreakpoint + || reason == eStopReasonException) + { + if (log) + log->Printf ("ProcessGDBRemote::DoDestroy() - thread: %lld stopped with reason: %s.", + thread_sp->GetID(), + stop_info_sp->GetDescription()); + stop_looks_like_crash = true; + break; + } + } + } + + if (stop_looks_like_crash) + { + if (log) + log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill."); + m_destroy_tried_resuming = true; + + // If we are going to run again before killing, it would be good to suspend all the threads + // before resuming so they won't get into more trouble. Sadly, for the threads stopped with + // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do + // have to run the risk of letting those threads proceed a bit. + + { + Mutex::Locker(threads.GetMutex()); + + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; i++) + { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + StopInfoSP stop_info_sp = thread_sp->GetPrivateStopReason(); + StopReason reason = eStopReasonInvalid; + if (stop_info_sp) + reason = stop_info_sp->GetStopReason(); + if (reason != eStopReasonBreakpoint + && reason != eStopReasonException) + { + if (log) + log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: %lld before running.", + thread_sp->GetID()); + thread_sp->SetResumeState(eStateSuspended); + } + } + } + Resume (); + return Destroy(); + } + } + } + } + // Interrupt if our inferior is running... int exit_status = SIGABRT; std::string exit_string; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 9e21ded18e0..04d6ff2e7a8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -321,6 +321,7 @@ protected: MMapMap m_addr_to_mmap_size; lldb::BreakpointSP m_thread_create_bp_sp; bool m_waiting_for_attach; + bool m_destroy_tried_resuming; bool StartAsyncThread (); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index dabad32f220..e44daf6ece7 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1621,6 +1621,11 @@ void Process::DisableAllBreakpointSites () { m_breakpoint_site_list.SetEnabledForAll (false); + size_t num_sites = m_breakpoint_site_list.GetSize(); + for (size_t i = 0; i < num_sites; i++) + { + DisableBreakpoint (m_breakpoint_site_list.GetByIndex(i).get()); + } } Error |