void SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result) { result.Clear(); if (command_line && IsValid()) { m_opaque_ptr->ResolveCommand(command_line, result.ref()); } else { result->AppendError( "SBCommandInterpreter or the command line is not valid"); result->SetStatus(eReturnStatusFailed); } }
void SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory (SBCommandReturnObject &result) { result.Clear(); if (m_opaque_ptr) { m_opaque_ptr->SourceInitFile (true, result.ref()); } else { result->AppendError ("SBCommandInterpreter is not valid"); result->SetStatus (eReturnStatusFailed); } }
void Driver::ExecuteInitialCommands (bool before_file) { size_t num_commands; std::vector<std::pair<bool, std::string> > *command_set; if (before_file) command_set = &(m_option_data.m_initial_commands); else command_set = &(m_option_data.m_after_file_commands); num_commands = command_set->size(); SBCommandReturnObject result; bool old_async = GetDebugger().GetAsync(); GetDebugger().SetAsync(false); for (size_t idx = 0; idx < num_commands; idx++) { bool is_file = (*command_set)[idx].first; const char *command = (*command_set)[idx].second.c_str(); char command_string[PATH_MAX * 2]; const bool dump_stream_only_if_no_immediate = true; const char *executed_command = command; if (is_file) { ::snprintf (command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command); executed_command = command_string; } m_debugger.GetCommandInterpreter().HandleCommand (executed_command, result, false); if (!m_option_data.m_source_quietly || result.Succeeded() == false) { const size_t output_size = result.GetOutputSize(); if (output_size > 0) { const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate); if (cstr) printf ("%s", cstr); } const size_t error_size = result.GetErrorSize(); if (error_size > 0) { const char *cstr = result.GetError(dump_stream_only_if_no_immediate); if (cstr) printf ("%s", cstr); } } if (result.Succeeded() == false) { const char *type = before_file ? "before file" : "after_file"; if (is_file) ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command); else ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command); break; } result.Clear(); } GetDebugger().SetAsync(old_async); }
lldb::ReturnStatus SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history) { result.Clear(); if (m_opaque_ptr) { m_opaque_ptr->HandleCommand (command_line, add_to_history, result.ref()); } else { result->AppendError ("SBCommandInterpreter is not valid"); result->SetStatus (eReturnStatusFailed); } return result.GetStatus(); }
//++ ------------------------------------------------------------------------------------ // Details: This function allows *this driver to call on another driver to perform work // should this driver not be able to handle the client data input. // SetDriverToFallThruTo() specifies the fall through to driver. // Check the error message if the function returns a failure. // Type: Overridden. // Args: vCmd - (R) Command instruction to interpret. // vwErrMsg - (W) Error description on command failing. // Return: MIstatus::success - Command succeeded. // MIstatus::failure - Command failed. // Throws: None. //-- bool Driver::DoFallThruToAnotherDriver( const CMIUtilString & vCmd, CMIUtilString & vwErrMsg ) { bool bOk = MIstatus::success; vwErrMsg.empty(); // ToDo: Implement do work on other driver after this driver said "Give up you try" // This may nto be required if the feature to 'fall through' is not required SBCommandReturnObject returnObj = lldb::SBCommandReturnObject(); SBCommandInterpreter cmdIntrp = m_debugger.GetCommandInterpreter(); const lldb::ReturnStatus cmdResult = cmdIntrp.HandleCommand( vCmd.c_str(), returnObj ); MIunused( cmdResult ); if( returnObj.Succeeded() == false ) { bOk = MIstatus::failure; vwErrMsg = returnObj.GetError(); } return bOk; }
lldb::ReturnStatus SBCommandInterpreter::HandleCommand( const char *command_line, SBExecutionContext &override_context, SBCommandReturnObject &result, bool add_to_history) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); if (log) log->Printf("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", " "SBCommandReturnObject(%p), add_to_history=%i)", static_cast<void *>(m_opaque_ptr), command_line, static_cast<void *>(result.get()), add_to_history); ExecutionContext ctx, *ctx_ptr; if (override_context.get()) { ctx = override_context.get()->Lock(true); ctx_ptr = &ctx; } else ctx_ptr = nullptr; result.Clear(); if (command_line && IsValid()) { result.ref().SetInteractive(false); m_opaque_ptr->HandleCommand(command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref(), ctx_ptr); } else { result->AppendError( "SBCommandInterpreter or the command line is not valid"); result->SetStatus(eReturnStatusFailed); } // We need to get the value again, in case the command disabled the log! log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API); if (log) { SBStream sstr; result.GetDescription(sstr); log->Printf("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", " "SBCommandReturnObject(%p): %s, add_to_history=%i) => %i", static_cast<void *>(m_opaque_ptr), command_line, static_cast<void *>(result.get()), sstr.GetData(), add_to_history, result.GetStatus()); } return result.GetStatus(); }
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 SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory( SBCommandReturnObject &result) { result.Clear(); if (IsValid()) { TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget()); std::unique_lock<std::recursive_mutex> lock; if (target_sp) lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex()); m_opaque_ptr->SourceInitFile(true, result.ref()); } else { result->AppendError("SBCommandInterpreter is not valid"); result->SetStatus(eReturnStatusFailed); } Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); if (log) log->Printf( "SBCommandInterpreter(%p)::SourceInitFileInCurrentWorkingDirectory " "(&SBCommandReturnObject(%p))", static_cast<void *>(m_opaque_ptr), static_cast<void *>(result.get())); }
void SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory (SBCommandReturnObject &result) { result.Clear(); if (m_opaque_ptr) { TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget()); Mutex::Locker api_locker; if (target_sp) api_locker.Lock(target_sp->GetAPIMutex()); m_opaque_ptr->SourceInitFile (true, result.ref()); } else { result->AppendError ("SBCommandInterpreter is not valid"); result->SetStatus (eReturnStatusFailed); } LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) log->Printf ("SBCommandInterpreter(%p)::SourceInitFileInCurrentWorkingDirectory (&SBCommandReturnObject(%p))", m_opaque_ptr, result.get()); }
void SBDebugger::HandleCommand (const char *command) { if (m_opaque_sp) { TargetSP target_sp (m_opaque_sp->GetSelectedTarget()); Mutex::Locker api_locker; if (target_sp) api_locker.Lock(target_sp->GetAPIMutex()); SBCommandInterpreter sb_interpreter(GetCommandInterpreter ()); SBCommandReturnObject result; sb_interpreter.HandleCommand (command, result, false); if (GetErrorFileHandle() != NULL) result.PutError (GetErrorFileHandle()); if (GetOutputFileHandle() != NULL) result.PutOutput (GetOutputFileHandle()); if (m_opaque_sp->GetAsyncExecution() == false) { SBProcess process(GetCommandInterpreter().GetProcess ()); ProcessSP process_sp (process.GetSP()); if (process_sp) { EventSP event_sp; Listener &lldb_listener = m_opaque_sp->GetListener(); while (lldb_listener.GetNextEventForBroadcaster (process_sp.get(), event_sp)) { SBEvent event(event_sp); HandleProcessEvent (process, event, GetOutputFileHandle(), GetErrorFileHandle()); } } } } }
void SBProcess::AppendEventStateReport (const SBEvent &event, SBCommandReturnObject &result) { if (m_opaque_sp) { const StateType event_state = SBProcess::GetStateFromEvent (event); char message[1024]; ::snprintf (message, sizeof (message), "Process %d %s\n", m_opaque_sp->GetID(), SBDebugger::StateAsCString (event_state)); result.AppendMessage (message); } }
lldb::ReturnStatus SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history) { LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p), add_to_history=%i)", m_opaque_ptr, command_line, result.get(), add_to_history); result.Clear(); if (command_line && m_opaque_ptr) { TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget()); Mutex::Locker api_locker; if (target_sp) api_locker.Lock(target_sp->GetAPIMutex()); m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref()); } else { result->AppendError ("SBCommandInterpreter or the command line is not valid"); result->SetStatus (eReturnStatusFailed); } // We need to get the value again, in case the command disabled the log! log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API); if (log) { SBStream sstr; result.GetDescription (sstr); log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p): %s, add_to_history=%i) => %i", m_opaque_ptr, command_line, result.get(), sstr.GetData(), add_to_history, result.GetStatus()); } return result.GetStatus(); }
void Driver::MainLoop () { if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; atexit (reset_stdin_termios); } ::setbuf (stdin, NULL); ::setbuf (stdout, NULL); m_debugger.SetErrorFileHandle (stderr, false); m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet... m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) m_debugger.SetTerminalWidth (window_size.ws_col); } SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); // Before we handle any options from the command line, we parse the // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); if (GetDebugMode()) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); } // Now we handle options we got from the command line SBStream commands_stream; // First source in the commands specified to be run before the file arguments are processed. WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream); const size_t num_args = m_option_data.m_args.size(); if (num_args > 0) { char arch_name[64]; if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) commands_stream.Printf("target create --arch=%s %s", arch_name, EscapeString(m_option_data.m_args[0]).c_str()); else commands_stream.Printf("target create %s", EscapeString(m_option_data.m_args[0]).c_str()); if (!m_option_data.m_core_file.empty()) { commands_stream.Printf(" --core %s", EscapeString(m_option_data.m_core_file).c_str()); } commands_stream.Printf("\n"); if (num_args > 1) { commands_stream.Printf ("settings set -- target.run-args "); for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) commands_stream.Printf(" %s", EscapeString(m_option_data.m_args[arg_idx]).c_str()); commands_stream.Printf("\n"); } } else if (!m_option_data.m_core_file.empty()) { commands_stream.Printf("target create --core %s\n", EscapeString(m_option_data.m_core_file).c_str()); } else if (!m_option_data.m_process_name.empty()) { commands_stream.Printf ("process attach --name %s", EscapeString(m_option_data.m_process_name).c_str()); if (m_option_data.m_wait_for) commands_stream.Printf(" --waitfor"); commands_stream.Printf("\n"); } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) { commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid); } WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); } bool handle_events = true; bool spawn_thread = false; if (m_option_data.m_repl) { const char *repl_options = NULL; if (!m_option_data.m_repl_options.empty()) repl_options = m_option_data.m_repl_options.c_str(); SBError error (m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options)); if (error.Fail()) { const char *error_cstr = error.GetCString(); if (error_cstr && error_cstr[0]) fprintf (stderr, "error: %s\n", error_cstr); else fprintf (stderr, "error: %u\n", error.GetError()); } } else { // Check if we have any data in the commands stream, and if so, save it to a temp file // so we can then run the command interpreter using the file contents. const char *commands_data = commands_stream.GetData(); const size_t commands_size = commands_stream.GetSize(); // The command file might have requested that we quit, this variable will track that. bool quit_requested = false; bool stopped_for_crash = false; if (commands_data && commands_size) { int initial_commands_fds[2]; bool success = true; FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds); if (commands_file) { m_debugger.SetInputFileHandle (commands_file, true); // Set the debugger into Sync mode when running the command file. Otherwise command files // that run the target won't run in a sensible way. bool old_async = m_debugger.GetAsync(); m_debugger.SetAsync(false); int num_errors; SBCommandInterpreterRunOptions options; options.SetStopOnError (true); if (m_option_data.m_batch) options.SetStopOnCrash (true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested, stopped_for_crash); if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) { int crash_command_fds[2]; SBStream crash_commands_stream; WriteCommandsForSourcing (eCommandPlacementAfterCrash, crash_commands_stream); const char *crash_commands_data = crash_commands_stream.GetData(); const size_t crash_commands_size = crash_commands_stream.GetSize(); commands_file = PrepareCommandsForSourcing (crash_commands_data, crash_commands_size, crash_command_fds); if (commands_file) { bool local_quit_requested; bool local_stopped_for_crash; m_debugger.SetInputFileHandle (commands_file, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, local_quit_requested, local_stopped_for_crash); if (local_quit_requested) quit_requested = true; } } m_debugger.SetAsync(old_async); } else success = false; // Close any pipes that we still have ownership of CleanupAfterCommandSourcing(initial_commands_fds); // Something went wrong with command pipe if (!success) { exit(1); } } // Now set the input file handle to STDIN and run the command // interpreter again in interactive mode and let the debugger // take ownership of stdin bool go_interactive = true; if (quit_requested) go_interactive = false; else if (m_option_data.m_batch && !stopped_for_crash) go_interactive = false; if (go_interactive) { m_debugger.SetInputFileHandle (stdin, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread); } } reset_stdin_termios(); fclose (stdin); SBDebugger::Destroy (m_debugger); }
void Driver::MainLoop () { if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; atexit (reset_stdin_termios); } ::setbuf (stdin, NULL); ::setbuf (stdout, NULL); m_debugger.SetErrorFileHandle (stderr, false); m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, true); m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) m_debugger.SetTerminalWidth (window_size.ws_col); } SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); // Before we handle any options from the command line, we parse the // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); if (GetDebugMode()) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); } // Now we handle options we got from the command line // First source in the commands specified to be run before the file arguments are processed. ExecuteInitialCommands(true); // Was there a core file specified? std::string core_file_spec(""); if (!m_option_data.m_core_file.empty()) core_file_spec.append("--core ").append(m_option_data.m_core_file); char command_string[PATH_MAX * 2]; const size_t num_args = m_option_data.m_args.size(); if (num_args > 0) { char arch_name[64]; if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) ::snprintf (command_string, sizeof (command_string), "target create --arch=%s %s \"%s\"", arch_name, core_file_spec.c_str(), m_option_data.m_args[0].c_str()); else ::snprintf (command_string, sizeof(command_string), "target create %s \"%s\"", core_file_spec.c_str(), m_option_data.m_args[0].c_str()); m_debugger.HandleCommand (command_string); if (num_args > 1) { m_debugger.HandleCommand ("settings clear target.run-args"); char arg_cstr[1024]; for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) { ::snprintf (arg_cstr, sizeof(arg_cstr), "settings append target.run-args \"%s\"", m_option_data.m_args[arg_idx].c_str()); m_debugger.HandleCommand (arg_cstr); } } } else if (!core_file_spec.empty()) { ::snprintf (command_string, sizeof(command_string), "target create %s", core_file_spec.c_str()); m_debugger.HandleCommand (command_string);; } else if (!m_option_data.m_process_name.empty()) { ::snprintf (command_string, sizeof(command_string), "process attach --name '%s'%s", m_option_data.m_process_name.c_str(), m_option_data.m_wait_for ? " --waitfor" : ""); m_debugger.HandleCommand (command_string); } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) { ::snprintf (command_string, sizeof(command_string), "process attach --pid %" PRIu64, m_option_data.m_process_pid); m_debugger.HandleCommand (command_string); } ExecuteInitialCommands(false); // Now that all option parsing is done, we try and parse the .lldbinit // file in the current working directory sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); } bool handle_events = true; bool spawn_thread = false; m_debugger.RunCommandInterpreter(handle_events, spawn_thread); reset_stdin_termios(); fclose (stdin); SBDebugger::Destroy (m_debugger); }
void Driver::MainLoop () { if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; atexit (reset_stdin_termios); } ::setbuf (stdin, NULL); ::setbuf (stdout, NULL); m_debugger.SetErrorFileHandle (stderr, false); m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, false); // Don't take ownership of STDIN yet... m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) m_debugger.SetTerminalWidth (window_size.ws_col); } SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); // Before we handle any options from the command line, we parse the // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); if (GetDebugMode()) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); } // Now we handle options we got from the command line SBStream commands_stream; // First source in the commands specified to be run before the file arguments are processed. WriteInitialCommands(true, commands_stream); const size_t num_args = m_option_data.m_args.size(); if (num_args > 0) { char arch_name[64]; if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) commands_stream.Printf("target create --arch=%s \"%s\"", arch_name, m_option_data.m_args[0].c_str()); else commands_stream.Printf("target create \"%s\"", m_option_data.m_args[0].c_str()); if (!m_option_data.m_core_file.empty()) { commands_stream.Printf(" --core \"%s\"", m_option_data.m_core_file.c_str()); } commands_stream.Printf("\n"); if (num_args > 1) { commands_stream.Printf ("settings set -- target.run-args "); for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) { const char *arg_cstr = m_option_data.m_args[arg_idx].c_str(); if (strchr(arg_cstr, '"') == NULL) commands_stream.Printf(" \"%s\"", arg_cstr); else commands_stream.Printf(" '%s'", arg_cstr); } commands_stream.Printf("\n"); } } else if (!m_option_data.m_core_file.empty()) { commands_stream.Printf("target create --core \"%s\"\n", m_option_data.m_core_file.c_str()); } else if (!m_option_data.m_process_name.empty()) { commands_stream.Printf ("process attach --name \"%s\"", m_option_data.m_process_name.c_str()); if (m_option_data.m_wait_for) commands_stream.Printf(" --waitfor"); commands_stream.Printf("\n"); } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) { commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid); } WriteInitialCommands(false, commands_stream); // Now that all option parsing is done, we try and parse the .lldbinit // file in the current working directory sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); } bool handle_events = true; bool spawn_thread = false; // Check if we have any data in the commands stream, and if so, save it to a temp file // so we can then run the command interpreter using the file contents. const char *commands_data = commands_stream.GetData(); const size_t commands_size = commands_stream.GetSize(); // The command file might have requested that we quit, this variable will track that. bool quit_requested = false; if (commands_data && commands_size) { enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE bool success = true; int fds[2] = { -1, -1 }; int err = 0; #ifdef _WIN32 err = _pipe(fds, commands_size, O_BINARY); #else err = pipe(fds); #endif if (err == 0) { ssize_t nrwr = write(fds[WRITE], commands_data, commands_size); if (nrwr < 0) { fprintf(stderr, "error: write(%i, %p, %zd) failed (errno = %i) " "when trying to open LLDB commands pipe\n", fds[WRITE], commands_data, commands_size, errno); success = false; } else if (static_cast<size_t>(nrwr) == commands_size) { // Close the write end of the pipe so when we give the read end to // the debugger/command interpreter it will exit when it consumes all // of the data #ifdef _WIN32 _close(fds[WRITE]); fds[WRITE] = -1; #else close(fds[WRITE]); fds[WRITE] = -1; #endif // Now open the read file descriptor in a FILE * that we can give to // the debugger as an input handle FILE *commands_file = fdopen(fds[READ], "r"); if (commands_file) { fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor // Hand ownership if the FILE * over to the debugger for "commands_file". m_debugger.SetInputFileHandle (commands_file, true); // Set the debugger into Sync mode when running the command file. Otherwise command files // that run the target won't run in a sensible way. bool old_async = m_debugger.GetAsync(); m_debugger.SetAsync(false); int num_errors; SBCommandInterpreterRunOptions options; options.SetStopOnError (true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread, options, num_errors, quit_requested); m_debugger.SetAsync(old_async); } else { fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when " "trying to open LLDB commands pipe\n", fds[READ], errno); success = false; } } else { assert(!"partial writes not handled"); success = false; } } else { fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n"); success = false; } // Close any pipes that we still have ownership of if ( fds[WRITE] != -1) { #ifdef _WIN32 _close(fds[WRITE]); fds[WRITE] = -1; #else close(fds[WRITE]); fds[WRITE] = -1; #endif } if ( fds[READ] != -1) { #ifdef _WIN32 _close(fds[READ]); fds[READ] = -1; #else close(fds[READ]); fds[READ] = -1; #endif } // Something went wrong with command pipe if (!success) { exit(1); } } // Now set the input file handle to STDIN and run the command // interpreter again in interactive mode and let the debugger // take ownership of stdin if (!quit_requested) { m_debugger.SetInputFileHandle (stdin, true); m_debugger.RunCommandInterpreter(handle_events, spawn_thread); } reset_stdin_termios(); fclose (stdin); SBDebugger::Destroy (m_debugger); }
void Driver::Initialize() { m_debugger = SBDebugger::Create(false, LogOutput, 0); // We want to be able to handle CTRL+D in the terminal to have it terminate // certain input m_debugger.SetCloseInputOnEOF (false); InitializePseudoTerminal(); m_debugger.SetErrorFileHandle (stderr, false); m_debugger.SetOutputFileHandle (stdout, false); m_debugger.SetInputFileHandle (stdin, true); m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); InitializeEditLineIO(); SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); m_interpreter = &sb_interpreter; SBListener listener(m_debugger.GetListener()); listener.StartListeningForEventClass(m_debugger, SBTarget::GetBroadcasterClassName(), SBTarget::eBroadcastBitBreakpointChanged); if (!listener.IsValid()) return; listener.StartListeningForEvents (*m_io_channel_ap, IOChannel::eBroadcastBitHasUserInput | IOChannel::eBroadcastBitUserInterrupt | IOChannel::eBroadcastBitThreadShouldExit | IOChannel::eBroadcastBitThreadDidStart | IOChannel::eBroadcastBitThreadDidExit); if (!m_io_channel_ap->Start ()) return; iochannel_thread_exited = false; listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(), SBCommandInterpreter::eBroadcastBitQuitCommandReceived | SBCommandInterpreter::eBroadcastBitAsynchronousOutputData | SBCommandInterpreter::eBroadcastBitAsynchronousErrorData); // Before we handle any options from the command line, we parse the // .lldbinit file in the user's home directory. SBCommandReturnObject result; sb_interpreter.SourceInitFileInHomeDirectory(result); if (GetDebugMode()) { result.PutError (m_debugger.GetErrorFileHandle()); result.PutOutput (m_debugger.GetOutputFileHandle()); } HandleCommandLine(result); // Now that all option parsing is done, we try and parse the .lldbinit // file in the current working directory sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); if (GetDebugMode()) { result.PutError(m_debugger.GetErrorFileHandle()); result.PutOutput(m_debugger.GetOutputFileHandle()); } SBEvent event; // Make sure the IO channel is started up before we try to tell it we // are ready for input listener.WaitForEventForBroadcasterWithType (UINT32_MAX, *m_io_channel_ap, IOChannel::eBroadcastBitThreadDidStart, event); // If we were asked to attach, then do that here: // I'm going to use the command string rather than directly // calling the API's because then I don't have to recode the // event handling here. if (!m_option_data.m_process_name.empty() || m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID) { AttachToProcess(); } ReadyForCommand (); }
// 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; } } }