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 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::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 (); }
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); }