void SBDebugger::RunCommandInterpreter (bool auto_handle_events, bool spawn_thread, SBCommandInterpreterRunOptions &options, int &num_errors, bool &quit_requested, bool &stopped_for_crash) { if (m_opaque_sp) { CommandInterpreter &interp = m_opaque_sp->GetCommandInterpreter(); interp.RunCommandInterpreter(auto_handle_events, spawn_thread, options.ref()); num_errors = interp.GetNumErrors(); quit_requested = interp.GetQuitRequested(); stopped_for_crash = interp.GetStoppedForCrash(); } }
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, 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); }