diff options
Diffstat (limited to 'lldb/source')
8 files changed, 170 insertions, 93 deletions
diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 40cddf3699d..84b8bff9a26 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -26,6 +26,7 @@ #include "lldb/Expression/ClangFunction.h" #include "lldb/Symbol/Type.h" #include "lldb/Core/DataExtractor.h" +#include "lldb/Core/State.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -509,18 +510,25 @@ ClangFunction::ExecuteFunction ( if (call_plan_sp == NULL) return eExecutionSetupError; -//#define SINGLE_STEP_EXPRESSIONS - -#ifdef SINGLE_STEP_EXPRESSIONS - return eExecutionInterrupted; -#else call_plan_sp->SetPrivate(true); exe_ctx.thread->QueueThreadPlan(call_plan_sp, true); -#endif + + Listener listener("ClangFunction temporary listener"); + exe_ctx.process->HijackProcessEvents(&listener); + + Error resume_error = exe_ctx.process->Resume (); + if (!resume_error.Success()) + { + errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString()); + exe_ctx.process->RestoreProcessEvents(); + return eExecutionSetupError; + } // We need to call the function synchronously, so spin waiting for it to return. // If we get interrupted while executing, we're going to lose our context, and // won't be able to gather the result at this point. + // We set the timeout AFTER the resume, since the resume takes some time and we + // don't want to charge that to the timeout. TimeValue* timeout_ptr = NULL; TimeValue real_timeout; @@ -532,18 +540,7 @@ ClangFunction::ExecuteFunction ( timeout_ptr = &real_timeout; } - Listener listener("ClangFunction temporary listener"); - exe_ctx.process->HijackProcessEvents(&listener); - - Error resume_error = exe_ctx.process->Resume (); - if (!resume_error.Success()) - { - errors.Printf("Error resuming inferior: \"%s\".\n", resume_error.AsCString()); - return eExecutionSetupError; - } - lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - while (1) { lldb::EventSP event_sp; @@ -551,12 +548,11 @@ ClangFunction::ExecuteFunction ( // Now wait for the process to stop again: bool got_event = listener.WaitForEvent (timeout_ptr, event_sp); - if (!got_event && !call_plan_sp->IsPlanComplete()) + if (!got_event) { // Right now this is the only way to tell we've timed out... // We should interrupt the process here... // Not really sure what to do if Halt fails here... - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); if (log) if (try_all_threads) log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", @@ -568,45 +564,54 @@ ClangFunction::ExecuteFunction ( if (exe_ctx.process->Halt().Success()) { timeout_ptr = NULL; - - got_event = listener.WaitForEvent (timeout_ptr, event_sp); - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - - if (stop_state == lldb::eStateInvalid) - { - errors.Printf ("Got an invalid stop state after halt."); - } - else if (stop_state != lldb::eStateStopped) - { - StreamString s; - event_sp->Dump (&s); + if (log) + log->Printf ("Halt succeeded."); - errors.Printf("Didn't get a stopped event after Halting the target, got: \"%s\"", s.GetData()); - } + // Between the time that we got the timeout and the time we halted, but target + // might have actually completed the plan. If so, we're done. Note, I call WFE here with a short + // timeout to + got_event = listener.WaitForEvent(NULL, event_sp); - if (try_all_threads) + if (got_event) { - // Between the time that we got the timeout and the time we halted, but target - // might have actually completed the plan. If so, we're done. + stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + { + log->Printf ("Stopped with event: %s", StateAsCString(stop_state)); + if (stop_state == lldb::eStateStopped && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get())) + log->Printf (" Event was the Halt interruption event."); + } + if (exe_ctx.thread->IsThreadPlanDone (call_plan_sp.get())) { + if (log) + log->Printf ("Even though we timed out, the call plan was done. Exiting wait loop."); return_value = eExecutionCompleted; break; } - - call_plan_ptr->SetStopOthers (false); - exe_ctx.process->Resume(); - continue; - } - else - { - exe_ctx.process->RestoreProcessEvents (); - return eExecutionInterrupted; + + if (try_all_threads) + { + + call_plan_ptr->SetStopOthers (false); + if (log) + log->Printf ("About to resume."); + + exe_ctx.process->Resume(); + continue; + } + else + { + exe_ctx.process->RestoreProcessEvents (); + return eExecutionInterrupted; + } } } } stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + log->Printf("Got event: %s.", StateAsCString(stop_state)); if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) continue; @@ -623,7 +628,6 @@ ClangFunction::ExecuteFunction ( } else { - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); if (log) { StreamString s; @@ -690,7 +694,6 @@ ClangFunction::ExecuteFunction ( event_explanation = ts.GetData(); } while (0); - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); if (log) log->Printf("Execution interrupted: %s %s", s.GetData(), event_explanation); } diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp index d20077fb5c6..259c08072a1 100644 --- a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp +++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.cpp @@ -674,7 +674,7 @@ ProcessMacOSX::RefreshStateAfterStop () } Error -ProcessMacOSX::DoHalt () +ProcessMacOSX::DoHalt (bool &caused_stop) { return Signal (SIGSTOP); } @@ -718,8 +718,10 @@ ProcessMacOSX::DoSIGSTOP (bool clear_all_breakpoints) // Pause the Private State Thread so it doesn't intercept the events we need to wait for. PausePrivateStateThread(); - - m_thread_list.DiscardThreadPlans(); + // I don't think this is right. Halt should just stop the process, and then whoever called halt should + // arrange whatever they need to with the thread plans. + + //m_thread_list.DiscardThreadPlans(); // First jettison all the current thread plans, since we want to make sure it // really just stops. diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h index afbd9b3f1ae..92d2c9c1653 100644 --- a/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h +++ b/lldb/source/Plugins/Process/MacOSX-User/source/ProcessMacOSX.h @@ -144,7 +144,7 @@ public: DoResume (); virtual lldb_private::Error - DoHalt (); + DoHalt (bool &caused_stop); virtual lldb_private::Error WillDetach (); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 50a7aec4c17..ee03424e528 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -199,14 +199,14 @@ GDBRemoteCommunication::SendContinuePacketAndWaitForResponse log->Printf ("GDBRemoteCommunication::%s ()", __FUNCTION__); Mutex::Locker locker(m_sequence_mutex); - m_is_running.SetValue (true, eBroadcastNever); - // ScopedValueChanger<bool> restore_running_to_false (m_is_running, false); StateType state = eStateRunning; if (SendPacket(payload, packet_length) == 0) state = eStateInvalid; + m_is_running.SetValue (true, eBroadcastAlways); + while (state == eStateRunning) { log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS); @@ -856,3 +856,19 @@ GDBRemoteCommunication::DeallocateMemory (addr_t addr, uint32_t timeout_seconds) } return false; } + +bool +GDBRemoteCommunication::WaitForIsRunning (uint32_t timeout_sec) +{ + TimeValue timeout; + if (timeout_sec) + { + timeout = TimeValue::Now(); + timeout.OffsetWithSeconds (timeout_sec); + } + bool timed_out = false; + m_is_running.WaitForValueEqualTo (true, &timeout, &timed_out); + return timed_out; +} + + diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index e5560720f4c..ac49bf271f1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -203,6 +203,9 @@ public: } bool + WaitForIsRunning (uint32_t timeout_sec); + + bool GetHostInfo (uint32_t timeout_seconds); bool diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 52499ba173a..fcbd523699f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -895,9 +895,15 @@ ProcessGDBRemote::WillResume () Error ProcessGDBRemote::DoResume () { + Error error; ProcessGDBRemoteLog::LogIf (GDBR_LOG_PROCESS, "ProcessGDBRemote::Resume()"); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (m_continue_packet.GetData(), m_continue_packet.GetSize())); - return Error(); + const uint32_t timedout_sec = 1; + if (m_gdb_comm.WaitForIsRunning (timedout_sec)) + { + error.SetErrorString("Resume timed out."); + } + return error; } size_t @@ -1115,20 +1121,47 @@ ProcessGDBRemote::RefreshStateAfterStop () } Error -ProcessGDBRemote::DoHalt () +ProcessGDBRemote::DoHalt (bool &caused_stop) { Error error; + caused_stop = false; + if (m_gdb_comm.IsRunning()) { + PausePrivateStateThread(); bool timed_out = false; Mutex::Locker locker; - if (!m_gdb_comm.SendInterrupt (locker, 2, &timed_out)) + + if (m_gdb_comm.SendInterrupt (locker, 2, &timed_out)) + { + EventSP event_sp; + TimeValue timeout_time; + timeout_time = TimeValue::Now(); + timeout_time.OffsetWithSeconds(2); + + StateType state = WaitForStateChangedEventsPrivate (&timeout_time, event_sp); + + if (!StateIsStoppedState (state)) + { + LogSP log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("ProcessGDBRemote::DoHalt() failed to stop after sending interrupt"); + error.SetErrorString ("Did not get stopped event after interrupt succeeded."); + } + else + caused_stop = true; + } + else { if (timed_out) error.SetErrorString("timed out sending interrupt packet"); else error.SetErrorString("unknown error sending interrupt packet"); } + + // Resume the private state thread at this point. + ResumePrivateStateThread(); + } return error; } @@ -2082,6 +2115,9 @@ ProcessGDBRemote::AsyncThread (void *arg) if (listener.WaitForEvent (NULL, event_sp)) { const uint32_t event_type = event_sp->GetType(); + if (log) + log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type); + switch (event_type) { case eBroadcastBitAsyncContinue: diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index ae79c5a48bc..1e85e9918a7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -138,7 +138,7 @@ public: DoResume (); virtual lldb_private::Error - DoHalt (); + DoHalt (bool &caused_stop); virtual lldb_private::Error WillDetach (); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index ea6b200f318..749ae3ceb88 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1438,9 +1438,19 @@ Process::Halt () if (error.Success()) { - error = DoHalt(); + bool caused_stop; + error = DoHalt(caused_stop); if (error.Success()) + { DidHalt(); + if (caused_stop) + { + ProcessEventData *new_data = new ProcessEventData (GetTarget().GetProcessSP(), eStateStopped); + new_data->SetInterrupted(true); + BroadcastEvent (eBroadcastBitStateChanged, new_data); + } + } + } return error; } @@ -1591,9 +1601,14 @@ Process::ShouldBroadcastEvent (Event *event_ptr) // If we are going to stop, then we always broadcast the event. // If we aren't going to stop, let the thread plans decide if we're going to report this event. // If no thread has an opinion, we don't report it. - if (state != eStateInvalid) + if (ProcessEventData::GetInterruptedFromEvent (event_ptr)) + { + if (log) + log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s", event_ptr, StateAsCString(state)); + return true; + } + else { - RefreshStateAfterStop (); if (m_thread_list.ShouldStop (event_ptr) == false) @@ -1610,7 +1625,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr) } if (log) - log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process", event_ptr, StateAsCString(state)); + log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state)); Resume (); } else @@ -1785,7 +1800,13 @@ Process::RunPrivateStateThread () control_only = false; break; } + + log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); + if (log) + log->Printf ("Process::%s (arg = %p, pid = %i) got a control event: %d", __FUNCTION__, this, GetID(), event_sp->GetType()); + m_private_state_control_wait.SetValue (true, eBroadcastAlways); + continue; } @@ -1799,7 +1820,13 @@ Process::RunPrivateStateThread () if (internal_state == eStateInvalid || internal_state == eStateExited || internal_state == eStateDetached ) + { + log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); + if (log) + log->Printf ("Process::%s (arg = %p, pid = %i) about to exit with internal state %s...", __FUNCTION__, this, GetID(), StateAsCString(internal_state)); + break; + } } // Verify log is still enabled before attempting to write to it... @@ -1820,7 +1847,8 @@ Process::ProcessEventData::ProcessEventData () : m_process_sp (), m_state (eStateInvalid), m_restarted (false), - m_update_state (false) + m_update_state (false), + m_interrupted (false) { } @@ -1829,7 +1857,8 @@ Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateT m_process_sp (process_sp), m_state (state), m_restarted (false), - m_update_state (false) + m_update_state (false), + m_interrupted (false) { } @@ -1850,30 +1879,6 @@ Process::ProcessEventData::GetFlavor () const return ProcessEventData::GetFlavorString (); } -const ProcessSP & -Process::ProcessEventData::GetProcessSP () const -{ - return m_process_sp; -} - -StateType -Process::ProcessEventData::GetState () const -{ - return m_state; -} - -bool -Process::ProcessEventData::GetRestarted () const -{ - return m_restarted; -} - -void -Process::ProcessEventData::SetRestarted (bool new_value) -{ - m_restarted = new_value; -} - void Process::ProcessEventData::DoOnRemoval (Event *event_ptr) { @@ -1974,6 +1979,24 @@ Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value } bool +Process::ProcessEventData::GetInterruptedFromEvent (const Event *event_ptr) +{ + const ProcessEventData *data = GetEventDataFromEvent (event_ptr); + if (data == NULL) + return false; + else + return data->GetInterrupted (); +} + +void +Process::ProcessEventData::SetInterruptedInEvent (Event *event_ptr, bool new_value) +{ + ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); + if (data != NULL) + data->SetInterrupted(new_value); +} + +bool Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr) { ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); @@ -1985,12 +2008,6 @@ Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr) return false; } -void -Process::ProcessEventData::SetUpdateStateOnRemoval() -{ - m_update_state = true; -} - Target * Process::CalculateTarget () { |