bool Driver::HandleIOEvent (const SBEvent &event) { bool quit = false; const uint32_t event_type = event.GetType(); if (event_type & IOChannel::eBroadcastBitHasUserInput) { // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for // handling. const char *command_string = SBEvent::GetCStringFromEvent(event); if (command_string == NULL) command_string = ""; SBCommandReturnObject result; // We don't want the result to bypass the OutWrite function in IOChannel, as this can result in odd // output orderings and problems with the prompt. m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true); if (result.GetOutputSize() > 0) m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), NO_ASYNC); if (result.GetErrorSize() > 0) m_io_channel_ap->OutWrite (result.GetError(), result.GetErrorSize(), NO_ASYNC); // We are done getting and running our command, we can now clear the // m_waiting_for_command so we can get another one. m_waiting_for_command = false; // If our editline input reader is active, it means another input reader // got pushed onto the input reader and caused us to become deactivated. // When the input reader above us gets popped, we will get re-activated // and our prompt will refresh in our callback if (m_editline_reader.IsActive()) { ReadyForCommand (); } } else if (event_type & IOChannel::eBroadcastBitUserInterrupt) { // This is here to handle control-c interrupts from the user. It has not yet really been implemented. // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER //m_io_channel_ap->CancelInput(); // Anything else? Send Interrupt to process? } else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || (event_type & IOChannel::eBroadcastBitThreadDidExit)) { // If the IOChannel thread is trying to go away, then it is definitely // time to end the debugging session. quit = true; } return quit; }
void Driver::ProcessEvent(SBEvent& event) { if (!event.GetBroadcaster().IsValid()) return; uint32_t event_type = event.GetType(); if (event.BroadcasterMatchesRef (*m_io_channel_ap)) { if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || (event_type & IOChannel::eBroadcastBitThreadDidExit)) { SetIsDone(); if (event_type & IOChannel::eBroadcastBitThreadDidExit) iochannel_thread_exited = true; } else { if (HandleIOEvent (event)) SetIsDone(); } } else if (SBProcess::EventIsProcessEvent (event)) { HandleProcessEvent (event); } else if (SBBreakpoint::EventIsBreakpointEvent (event)) { HandleBreakpointEvent (event); } else if (event.BroadcasterMatchesRef (m_interpreter->GetBroadcaster())) { // TODO: deprecate the eBroadcastBitQuitCommandReceived event // now that we have SBCommandInterpreter::SetCommandOverrideCallback() // that can take over a command if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived) { SetIsDone(); } else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousErrorData) { const char *data = SBEvent::GetCStringFromEvent (event); m_io_channel_ap->ErrWrite (data, strlen(data), ASYNC); } else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousOutputData) { const char *data = SBEvent::GetCStringFromEvent (event); m_io_channel_ap->OutWrite (data, strlen(data), ASYNC); } } }
void SBDebugger::HandleProcessEvent (const SBProcess &process, const SBEvent &event, FILE *out, FILE *err) { if (!process.IsValid()) return; TargetSP target_sp (process.GetTarget().GetSP()); if (!target_sp) return; const uint32_t event_type = event.GetType(); char stdio_buffer[1024]; size_t len; Mutex::Locker api_locker (target_sp->GetAPIMutex()); if (event_type & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitStateChanged)) { // Drain stdout when we stop just in case we have any bytes while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0) if (out != NULL) ::fwrite (stdio_buffer, 1, len, out); } if (event_type & (Process::eBroadcastBitSTDERR | Process::eBroadcastBitStateChanged)) { // Drain stderr when we stop just in case we have any bytes while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0) if (err != NULL) ::fwrite (stdio_buffer, 1, len, err); } if (event_type & Process::eBroadcastBitStateChanged) { StateType event_state = SBProcess::GetStateFromEvent (event); if (event_state == eStateInvalid) return; bool is_stopped = StateIsStoppedState (event_state); if (!is_stopped) process.ReportEventState (event, out); } }
void IOChannel::Run () { SBListener listener("IOChannel::Run"); std::string new_line; SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster()); listener.StartListeningForEvents (interpreter_broadcaster, SBCommandInterpreter::eBroadcastBitResetPrompt | SBCommandInterpreter::eBroadcastBitThreadShouldExit | SBCommandInterpreter::eBroadcastBitQuitCommandReceived); listener.StartListeningForEvents (*this, IOChannel::eBroadcastBitThreadShouldExit); listener.StartListeningForEvents (*m_driver, Driver::eBroadcastBitReadyForInput | Driver::eBroadcastBitThreadShouldExit); // Let anyone know that the IO channel is up and listening and ready for events BroadcastEventByType (eBroadcastBitThreadDidStart); bool done = false; while (!done) { SBEvent event; listener.WaitForEvent (UINT32_MAX, event); if (!event.IsValid()) continue; const uint32_t event_type = event.GetType(); if (event.GetBroadcaster().IsValid()) { if (event.BroadcasterMatchesPtr (m_driver)) { if (event_type & Driver::eBroadcastBitReadyForInput) { std::string line; if (CommandQueueIsEmpty()) { if (LibeditGetInput(line) == false) { // EOF or some other file error occurred done = true; continue; } } else { GetCommandFromQueue (line); } // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN' // AND TAKE CARE OF THAT HERE. SBEvent line_event(IOChannel::eBroadcastBitHasUserInput, line.c_str(), line.size()); BroadcastEvent (line_event); } else if (event_type & Driver::eBroadcastBitThreadShouldExit) { done = true; break; } } else if (event.BroadcasterMatchesRef (interpreter_broadcaster)) { switch (event_type) { case SBCommandInterpreter::eBroadcastBitResetPrompt: { const char *new_prompt = SBEvent::GetCStringFromEvent (event); if (new_prompt) g_prompt_map[m_edit_line] = new_prompt; } break; case SBCommandInterpreter::eBroadcastBitThreadShouldExit: case SBCommandInterpreter::eBroadcastBitQuitCommandReceived: done = true; break; } } else if (event.BroadcasterMatchesPtr (this)) { if (event_type & IOChannel::eBroadcastBitThreadShouldExit) { done = true; break; } } } } BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit); m_driver = NULL; m_read_thread = NULL; }
// This function handles events that were broadcast by the process. void Driver::HandleProcessEvent (const SBEvent &event) { using namespace lldb; const uint32_t event_type = event.GetType(); if (event_type & SBProcess::eBroadcastBitSTDOUT) { // The process has stdout available, get it and write it out to the // appropriate place. GetProcessSTDOUT (); } else if (event_type & SBProcess::eBroadcastBitSTDERR) { // The process has stderr available, get it and write it out to the // appropriate place. GetProcessSTDERR (); } else if (event_type & SBProcess::eBroadcastBitStateChanged) { // Drain all stout and stderr so we don't see any output come after // we print our prompts GetProcessSTDOUT (); GetProcessSTDERR (); // Something changed in the process; get the event and report the process's current status and location to // the user. StateType event_state = SBProcess::GetStateFromEvent (event); if (event_state == eStateInvalid) return; SBProcess process (SBProcess::GetProcessFromEvent (event)); assert (process.IsValid()); switch (event_state) { case eStateInvalid: case eStateUnloaded: case eStateConnected: case eStateAttaching: case eStateLaunching: case eStateStepping: case eStateDetached: { char message[1024]; int message_len = ::snprintf (message, sizeof(message), "Process %llu %s\n", process.GetProcessID(), m_debugger.StateAsCString (event_state)); m_io_channel_ap->OutWrite(message, message_len, ASYNC); } break; case eStateRunning: // Don't be chatty when we run... break; case eStateExited: { SBCommandReturnObject result; m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); } break; case eStateStopped: case eStateCrashed: case eStateSuspended: // Make sure the program hasn't been auto-restarted: if (SBProcess::GetRestartedFromEvent (event)) { // FIXME: Do we want to report this, or would that just be annoyingly chatty? char message[1024]; int message_len = ::snprintf (message, sizeof(message), "Process %llu stopped and was programmatically restarted.\n", process.GetProcessID()); m_io_channel_ap->OutWrite(message, message_len, ASYNC); } else { if (GetDebugger().GetSelectedTarget() == process.GetTarget()) { SBCommandReturnObject result; UpdateSelectedThread (); m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); } else { SBStream out_stream; uint32_t target_idx = GetDebugger().GetIndexOfTarget(process.GetTarget()); if (target_idx != UINT32_MAX) out_stream.Printf ("Target %d: (", target_idx); else out_stream.Printf ("Target <unknown index>: ("); process.GetTarget().GetDescription (out_stream, eDescriptionLevelBrief); out_stream.Printf (") stopped.\n"); m_io_channel_ap->OutWrite (out_stream.GetData(), out_stream.GetSize(), ASYNC); } } break; } } }