diff options
-rw-r--r-- | lldb/include/lldb/API/SBProcess.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Target/Process.h | 3 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBProcess.i | 3 | ||||
-rw-r--r-- | lldb/source/API/SBProcess.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectProcess.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Target/Process.cpp | 291 | ||||
-rw-r--r-- | lldb/source/Target/TargetList.cpp | 2 | ||||
-rw-r--r-- | lldb/tools/driver/Driver.cpp | 7 | ||||
-rw-r--r-- | lldb/tools/driver/IOChannel.cpp | 10 |
10 files changed, 207 insertions, 125 deletions
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h index c0d77bec2ee..e1814eebfa5 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -156,6 +156,9 @@ public: lldb::SBError Signal (int signal); + void + SendAsyncInterrupt(); + size_t ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error); diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 265303ebeab..8a1b4c51083 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2388,6 +2388,9 @@ public: uint32_t num_frames, uint32_t num_frames_with_source); + void + SendAsyncInterrupt (); + protected: void diff --git a/lldb/scripts/Python/interface/SBProcess.i b/lldb/scripts/Python/interface/SBProcess.i index 018e2c20c44..1adc238c469 100644 --- a/lldb/scripts/Python/interface/SBProcess.i +++ b/lldb/scripts/Python/interface/SBProcess.i @@ -206,6 +206,9 @@ public: lldb::SBError Signal (int signal); + void + SendAsyncInterrupt(); + %feature("autodoc", " Reads memory from the current process's address space and removes any traps that may have been inserted into the memory. It returns the byte diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index 801daa4bfc5..129f887108d 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -718,6 +718,16 @@ SBProcess::Signal (int signo) return sb_error; } +void +SBProcess::SendAsyncInterrupt () +{ + ProcessSP process_sp(GetSP()); + if (process_sp) + { + process_sp->SendAsyncInterrupt (); + } +} + SBThread SBProcess::GetThreadByID (tid_t tid) { diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index f45e926adc6..97ed205a1b0 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -566,6 +566,7 @@ protected: else { result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); + process->Destroy(); result.SetStatus (eReturnStatusFailed); return false; } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 15f513d272a..35994bcb2d7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1868,7 +1868,7 @@ ProcessGDBRemote::DoDestroy () { if (log) log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); - exit_string.assign ("killing while attaching."); + exit_string.assign ("killed or interrupted while attaching."); } } else diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 062b061c391..993d9809250 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -835,7 +835,8 @@ Process::Process(Target &target, Listener &listener) : eBroadcastBitSTDERR); m_private_state_listener.StartListeningForEvents(&m_private_state_broadcaster, - eBroadcastBitStateChanged); + eBroadcastBitStateChanged | + eBroadcastBitInterrupt); m_private_state_listener.StartListeningForEvents(&m_private_state_control_broadcaster, eBroadcastInternalStateControlStop | @@ -1027,7 +1028,7 @@ Process::HijackProcessEvents (Listener *listener) { if (listener != NULL) { - return HijackBroadcaster(listener, eBroadcastBitStateChanged); + return HijackBroadcaster(listener, eBroadcastBitStateChanged | eBroadcastBitInterrupt); } else return false; @@ -1044,7 +1045,7 @@ Process::HijackPrivateProcessEvents (Listener *listener) { if (listener != NULL) { - return m_private_state_broadcaster.HijackBroadcaster(listener, eBroadcastBitStateChanged); + return m_private_state_broadcaster.HijackBroadcaster(listener, eBroadcastBitStateChanged | eBroadcastBitInterrupt); } else return false; @@ -1067,9 +1068,14 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp) StateType state = eStateInvalid; if (m_listener.WaitForEventForBroadcasterWithType (timeout, this, - eBroadcastBitStateChanged, + eBroadcastBitStateChanged | eBroadcastBitInterrupt, event_sp)) - state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + { + if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) + state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + else if (log) + log->Printf ("Process::%s got no event or was interrupted.", __FUNCTION__); + } if (log) log->Printf ("Process::%s (timeout = %p, event_sp) => %s", @@ -1118,9 +1124,10 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev StateType state = eStateInvalid; if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout, &m_private_state_broadcaster, - eBroadcastBitStateChanged, + eBroadcastBitStateChanged | eBroadcastBitInterrupt, event_sp)) - state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) + state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); // This is a bit of a hack, but when we wait here we could very well return // to the command-line, and that could disable the log, which would render the @@ -3292,6 +3299,15 @@ Process::ControlPrivateStateThread (uint32_t signal) } void +Process::SendAsyncInterrupt () +{ + if (PrivateStateThreadIsValid()) + m_private_state_broadcaster.BroadcastEvent (Process::eBroadcastBitInterrupt, NULL); + else + BroadcastEvent (Process::eBroadcastBitInterrupt, NULL); +} + +void Process::HandlePrivateEvent (EventSP &event_sp) { LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -3410,7 +3426,22 @@ Process::RunPrivateStateThread () m_private_state_control_wait.SetValue (true, eBroadcastAlways); continue; } - + else if (event_sp->GetType() == eBroadcastBitInterrupt) + { + if (m_public_state.GetValue() == eStateAttaching) + { + if (log) + log->Printf ("Process::%s (arg = %p, pid = %llu) woke up with an interrupt while attaching - forwarding interrupt.", __FUNCTION__, this, GetID()); + BroadcastEvent (eBroadcastBitInterrupt, NULL); + } + else + { + if (log) + log->Printf ("Process::%s (arg = %p, pid = %llu) woke up with an interrupt - Halting.", __FUNCTION__, this, GetID()); + Halt(); + } + continue; + } const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); @@ -4215,72 +4246,85 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, if (event_sp.get()) { bool keep_going = false; - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - if (log) - log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state)); - - switch (stop_state) + if (event_sp->GetType() == eBroadcastBitInterrupt) + { + Halt(); + keep_going = false; + return_value = eExecutionInterrupted; + errors.Printf ("Execution halted by user interrupt."); + if (log) + log->Printf ("Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting."); + } + else { - case lldb::eStateStopped: + stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state)); + + switch (stop_state) { - // Yay, we're done. Now make sure that our thread plan actually completed. - ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id); - if (!thread_sp) + case lldb::eStateStopped: { - // Ooh, our thread has vanished. Unlikely that this was successful execution... - if (log) - log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id); - return_value = eExecutionInterrupted; - } - else - { - StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); - StopReason stop_reason = eStopReasonInvalid; - if (stop_info_sp) - stop_reason = stop_info_sp->GetStopReason(); - if (stop_reason == eStopReasonPlanComplete) + // Yay, we're done. Now make sure that our thread plan actually completed. + ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id); + if (!thread_sp) { + // Ooh, our thread has vanished. Unlikely that this was successful execution... if (log) - log->PutCString ("Process::RunThreadPlan(): execution completed successfully."); - // Now mark this plan as private so it doesn't get reported as the stop reason - // after this point. - if (thread_plan_sp) - thread_plan_sp->SetPrivate (orig_plan_private); - return_value = eExecutionCompleted; + log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id); + return_value = eExecutionInterrupted; } else { - if (log) - log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete."); - - return_value = eExecutionInterrupted; + StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); + StopReason stop_reason = eStopReasonInvalid; + if (stop_info_sp) + stop_reason = stop_info_sp->GetStopReason(); + if (stop_reason == eStopReasonPlanComplete) + { + if (log) + log->PutCString ("Process::RunThreadPlan(): execution completed successfully."); + // Now mark this plan as private so it doesn't get reported as the stop reason + // after this point. + if (thread_plan_sp) + thread_plan_sp->SetPrivate (orig_plan_private); + return_value = eExecutionCompleted; + } + else + { + if (log) + log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete."); + + return_value = eExecutionInterrupted; + } } - } - } - break; + } + break; - case lldb::eStateCrashed: - if (log) - log->PutCString ("Process::RunThreadPlan(): execution crashed."); - return_value = eExecutionInterrupted; - break; + case lldb::eStateCrashed: + if (log) + log->PutCString ("Process::RunThreadPlan(): execution crashed."); + return_value = eExecutionInterrupted; + break; - case lldb::eStateRunning: - do_resume = false; - keep_going = true; - break; + case lldb::eStateRunning: + do_resume = false; + keep_going = true; + break; - default: - if (log) - log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state)); - - if (stop_state == eStateExited) - event_to_broadcast_sp = event_sp; - - errors.Printf ("Execution stopped with unexpected state."); - return_value = eExecutionInterrupted; - break; + default: + if (log) + log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state)); + + if (stop_state == eStateExited) + event_to_broadcast_sp = event_sp; + + errors.Printf ("Execution stopped with unexpected state."); + return_value = eExecutionInterrupted; + break; + } } + if (keep_going) continue; else @@ -4499,83 +4543,92 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, do { - const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get()); - - if (!event_data) + if (!event_sp) { - event_explanation = "<no event data>"; + event_explanation = "<no event>"; break; } - - Process *process = event_data->GetProcessSP().get(); - - if (!process) + else if (event_sp->GetType() == eBroadcastBitInterrupt) { - event_explanation = "<no process>"; + event_explanation = "<user interrupt>"; break; } - - ThreadList &thread_list = process->GetThreadList(); - - uint32_t num_threads = thread_list.GetSize(); - uint32_t thread_index; - - ts.Printf("<%u threads> ", num_threads); - - for (thread_index = 0; - thread_index < num_threads; - ++thread_index) + else { - Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); + const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get()); + + if (!event_data) + { + event_explanation = "<no event data>"; + break; + } - if (!thread) + Process *process = event_data->GetProcessSP().get(); + + if (!process) { - ts.Printf("<?> "); - continue; + event_explanation = "<no process>"; + break; } - ts.Printf("<0x%4.4llx ", thread->GetID()); - RegisterContext *register_context = thread->GetRegisterContext().get(); + ThreadList &thread_list = process->GetThreadList(); - if (register_context) - ts.Printf("[ip 0x%llx] ", register_context->GetPC()); - else - ts.Printf("[ip unknown] "); + uint32_t num_threads = thread_list.GetSize(); + uint32_t thread_index; - lldb::StopInfoSP stop_info_sp = thread->GetStopInfo(); - if (stop_info_sp) + ts.Printf("<%u threads> ", num_threads); + + for (thread_index = 0; + thread_index < num_threads; + ++thread_index) { - const char *stop_desc = stop_info_sp->GetDescription(); - if (stop_desc) - ts.PutCString (stop_desc); + Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); + + if (!thread) + { + ts.Printf("<?> "); + continue; + } + + ts.Printf("<0x%4.4llx ", thread->GetID()); + RegisterContext *register_context = thread->GetRegisterContext().get(); + + if (register_context) + ts.Printf("[ip 0x%llx] ", register_context->GetPC()); + else + ts.Printf("[ip unknown] "); + + lldb::StopInfoSP stop_info_sp = thread->GetStopInfo(); + if (stop_info_sp) + { + const char *stop_desc = stop_info_sp->GetDescription(); + if (stop_desc) + ts.PutCString (stop_desc); + } + ts.Printf(">"); } - ts.Printf(">"); + + event_explanation = ts.GetData(); } - - event_explanation = ts.GetData(); } while (0); - if (log) - { - if (event_explanation) - log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation); - else - log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData()); - } - - if (discard_on_error && thread_plan_sp) - { - if (log) - log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get()); - thread->DiscardThreadPlansUpToPlan (thread_plan_sp); - thread_plan_sp->SetPrivate (orig_plan_private); - } + if (event_explanation) + log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation); else - { - if (log) - log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get()); - - } + log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData()); + } + + if (discard_on_error && thread_plan_sp) + { + if (log) + log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get()); + thread->DiscardThreadPlansUpToPlan (thread_plan_sp); + thread_plan_sp->SetPrivate (orig_plan_private); + } + else + { + if (log) + log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get()); } } else if (return_value == eExecutionSetupError) diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 34abd43e0a6..dae859d77fa 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -349,7 +349,7 @@ TargetList::SendAsyncInterrupt (lldb::pid_t pid) Process* process = target_sp->GetProcessSP().get(); if (process) { - process->BroadcastEvent (Process::eBroadcastBitInterrupt, NULL); + process->SendAsyncInterrupt(); ++num_async_interrupts_sent; } } diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index ab69b24b947..9926149f3f9 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -1080,11 +1080,12 @@ Driver::EditLineInputReaderCallback case eInputReaderInterrupt: if (driver->m_io_channel_ap.get() != NULL) { - SBProcess process = driver->GetDebugger().GetSelectedTarget().GetProcess(); + SBProcess process(driver->GetDebugger().GetSelectedTarget().GetProcess()); if (!driver->m_io_channel_ap->EditLineHasCharacters() - && process.IsValid() && process.GetState() == lldb::eStateRunning) + && process.IsValid() + && (process.GetState() == lldb::eStateRunning || process.GetState() == lldb::eStateAttaching)) { - process.Stop(); + process.SendAsyncInterrupt (); } else { diff --git a/lldb/tools/driver/IOChannel.cpp b/lldb/tools/driver/IOChannel.cpp index a553ff67fb6..b6d4224a790 100644 --- a/lldb/tools/driver/IOChannel.cpp +++ b/lldb/tools/driver/IOChannel.cpp @@ -55,7 +55,15 @@ IOChannel::EditLineHasCharacters () { const LineInfo *line_info = el_line(m_edit_line); if (line_info) - return line_info->cursor != line_info->buffer; + { + // Sometimes we get called after the user has submitted the line, but before editline has + // cleared the buffer. In that case the cursor will be pointing at the newline. That's + // equivalent to having no characters on the line, since it has already been submitted. + if (*line_info->cursor == '\n') + return false; + else + return line_info->cursor != line_info->buffer; + } else return false; } |