Index: lldb/include/lldb/API/SBCommandInterpreterRunOptions.h =================================================================== --- lldb/include/lldb/API/SBCommandInterpreterRunOptions.h +++ lldb/include/lldb/API/SBCommandInterpreterRunOptions.h @@ -64,6 +64,10 @@ void SetAddToHistory(bool); + bool GetShowProgress() const; + + void SetShowProgress(bool); + bool GetAutoHandleEvents() const; void SetAutoHandleEvents(bool); Index: lldb/include/lldb/Core/Debugger.h =================================================================== --- lldb/include/lldb/Core/Debugger.h +++ lldb/include/lldb/Core/Debugger.h @@ -452,10 +452,16 @@ void JoinIOHandlerThread(); + bool StartProgressHandlerThread(); + + void StopProgressHandlerThread(); + lldb::thread_result_t IOHandlerThread(); lldb::thread_result_t DefaultEventHandler(); + lldb::thread_result_t ProgressHandlerThread(); + void HandleBreakpointEvent(const lldb::EventSP &event_sp); void HandleProcessEvent(const lldb::EventSP &event_sp); @@ -518,6 +524,7 @@ LoadedPluginsList m_loaded_plugins; HostThread m_event_handler_thread; HostThread m_io_handler_thread; + HostThread m_progress_handler_thread; Broadcaster m_sync_broadcaster; ///< Private debugger synchronization. Broadcaster m_broadcaster; ///< Public Debugger event broadcaster. lldb::ListenerSP m_forward_listener_sp; Index: lldb/include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/CommandInterpreter.h +++ lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -166,10 +166,14 @@ m_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo; } - bool GetAutoHandleEvents() const { - return DefaultToYes(m_auto_handle_events); + bool GetShowProgress() const { return DefaultToYes(m_show_progress); } + + void SetShowProgress(bool show_progress) { + m_show_progress = show_progress ? eLazyBoolYes : eLazyBoolNo; } + bool GetAutoHandleEvents() const { return DefaultToNo(m_auto_handle_events); } + void SetAutoHandleEvents(bool auto_handle_events) { m_auto_handle_events = auto_handle_events ? eLazyBoolYes : eLazyBoolNo; } @@ -188,6 +192,7 @@ LazyBool m_print_results = eLazyBoolCalculate; LazyBool m_print_errors = eLazyBoolCalculate; LazyBool m_add_to_history = eLazyBoolCalculate; + LazyBool m_show_progress; LazyBool m_auto_handle_events; LazyBool m_spawn_thread; Index: lldb/source/API/SBCommandInterpreterRunOptions.cpp =================================================================== --- lldb/source/API/SBCommandInterpreterRunOptions.cpp +++ lldb/source/API/SBCommandInterpreterRunOptions.cpp @@ -139,6 +139,18 @@ m_opaque_up->SetAddToHistory(add_to_history); } +bool SBCommandInterpreterRunOptions::GetShowProgress() const { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up->GetShowProgress(); +} + +void SBCommandInterpreterRunOptions::SetShowProgress(bool spawn_thread) { + LLDB_INSTRUMENT_VA(this, spawn_thread); + + m_opaque_up->SetShowProgress(spawn_thread); +} + bool SBCommandInterpreterRunOptions::GetAutoHandleEvents() const { LLDB_INSTRUMENT_VA(this); Index: lldb/source/Core/Debugger.cpp =================================================================== --- lldb/source/Core/Debugger.cpp +++ lldb/source/Core/Debugger.cpp @@ -1719,6 +1719,68 @@ return {}; } +lldb::thread_result_t Debugger::ProgressHandlerThread() { + // Only report progress for real terminals. + if (!GetOutputFile().GetIsRealTerminal()) + return {}; + + // Only report progress is nobody else is listening for it. + if (GetBroadcaster().EventTypeHasListeners(Debugger::eBroadcastBitProgress)) + return {}; + + ListenerSP listener_sp = Listener::MakeListener("lldb.progress.listener"); + listener_sp->StartListeningForEvents(&m_broadcaster, + Debugger::eBroadcastBitProgress); + + // Only handle one kind of event at the same time. Ignore events that come in + // in while the current event hasn't completed + llvm::Optional CurrentEventID; + + // Assume that the if the terminal supports colors (ANSI escape codes) it + // also supports vt100 escape codes. + const bool use_vt100_escapes = GetOutputFile().GetIsTerminalWithColors(); + + while (true) { + lldb::EventSP event_sp; + if (listener_sp->GetEvent(event_sp, llvm::None)) { + if (!event_sp) + continue; + if (auto *data = Debugger::ProgressEventData::GetEventDataFromEvent( + event_sp.get())) { + + uint64_t id = data->GetID(); + if (CurrentEventID) { + if (id != *CurrentEventID) + continue; + } else { + CurrentEventID = id; + } + + std::string message = data->GetMessage(); + if (data->GetTotal() != UINT64_MAX) { + GetOutputFile().Printf("[%llu/%llu] %s\r", data->GetCompleted(), + data->GetTotal(), message.c_str()); + } else { + GetOutputFile().Printf("%s\r", message.c_str()); + } + + if (data->GetCompleted()) { + CurrentEventID.reset(); + // Clear the current line. Use an escape character if supported, + // otherwise overwrite the line with a sequence of spaces. + if (use_vt100_escapes) { + GetOutputFile().Printf("\33[2K\r"); + } else { + std::string clear(GetTerminalWidth(), ' '); + GetOutputFile().Printf("%s\r", clear.c_str()); + } + } + } + } + } + return {}; +} + bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); } bool Debugger::StartIOHandlerThread() { @@ -1751,6 +1813,30 @@ } } +bool Debugger::StartProgressHandlerThread() { + if (!m_progress_handler_thread.IsJoinable()) { + llvm::Expected progress_handler_thread = + ThreadLauncher::LaunchThread( + "lldb.debugger.progress-handler", + [this] { return ProgressHandlerThread(); }, + 8 * 1024 * 1024); // Use larger 8MB stack for this thread + if (progress_handler_thread) { + m_progress_handler_thread = *progress_handler_thread; + } else { + LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}", + llvm::toString(progress_handler_thread.takeError())); + } + } + + return m_io_handler_thread.IsJoinable(); +} + +void Debugger::StopProgressHandlerThread() { + if (m_progress_handler_thread.IsJoinable()) { + m_progress_handler_thread.Join(nullptr); + } +} + Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { if (!prefer_dummy) { if (TargetSP target = m_target_list.GetSelectedTarget()) Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -3283,6 +3283,9 @@ CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter( CommandInterpreterRunOptions &options) { + if (options.GetShowProgress()) + m_debugger.StartProgressHandlerThread(); + // Always re-create the command interpreter when we run it in case any file // handles have changed. bool force_create = true; Index: lldb/source/Symbol/LocateSymbolFile.cpp =================================================================== --- lldb/source/Symbol/LocateSymbolFile.cpp +++ lldb/source/Symbol/LocateSymbolFile.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Progress.h" #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" @@ -257,6 +258,10 @@ FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + + Progress progress(llvm::formatv( + "Locating external symbol file for {0}", + module_spec.GetFileSpec().GetFilename().AsCString(""))); FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); if (symbol_file_spec.IsAbsolute() && FileSystem::Instance().Exists(symbol_file_spec)) Index: lldb/tools/driver/Driver.cpp =================================================================== --- lldb/tools/driver/Driver.cpp +++ lldb/tools/driver/Driver.cpp @@ -565,6 +565,7 @@ m_debugger.SetAsync(false); SBCommandInterpreterRunOptions options; + options.SetShowProgress(true); options.SetAutoHandleEvents(true); options.SetSpawnThread(false); options.SetStopOnError(true);