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 @@ -329,6 +329,8 @@ bool SetUseColor(bool use_color); + bool GetShowProgress() const; + bool GetUseAutosuggestion() const; bool GetUseSourceCache() const; @@ -435,6 +437,8 @@ uint64_t completed, uint64_t total, llvm::Optional debugger_id); + void PrintProgress(const Debugger::ProgressEventData &data); + bool StartEventHandlerThread(); void StopEventHandlerThread(); @@ -452,10 +456,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 +528,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/CoreProperties.td =================================================================== --- lldb/source/Core/CoreProperties.td +++ lldb/source/Core/CoreProperties.td @@ -131,6 +131,10 @@ Global, DefaultTrue, Desc<"Whether to use Ansi color codes or not.">; + def ShowProgress: Property<"show-progress", "Boolean">, + Global, + DefaultTrue, + Desc<"Whether to show progress or not.">; def UseSourceCache: Property<"use-source-cache", "Boolean">, Global, DefaultTrue, Index: lldb/source/Core/Debugger.cpp =================================================================== --- lldb/source/Core/Debugger.cpp +++ lldb/source/Core/Debugger.cpp @@ -378,6 +378,12 @@ return ret; } +bool Debugger::GetShowProgress() const { + const uint32_t idx = ePropertyShowProgress; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseAutosuggestion() const { const uint32_t idx = ePropertyShowAutosuggestion; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -1719,6 +1725,75 @@ return {}; } +lldb::thread_result_t Debugger::ProgressHandlerThread() { + // Only report progress if 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; + while (true) { + lldb::EventSP event_sp; + if (listener_sp->GetEvent(event_sp, llvm::None)) { + if (!event_sp) + continue; + + auto *data = + Debugger::ProgressEventData::GetEventDataFromEvent(event_sp.get()); + if (!data) + continue; + + // Do some bookkeeping for the current event, regardless of whether we're + // going to show the progress. + uint64_t id = data->GetID(); + if (CurrentEventID) { + if (id != *CurrentEventID) + continue; + if (data->GetCompleted()) + CurrentEventID.reset(); + } else { + CurrentEventID = id; + } + + // Decide whether we actually are going to show the progress. This + // decision can change between iterations so check it inside the loop. + File &output = GetOutputFile(); + if (!output.GetIsTerminalWithColors() || !GetShowProgress()) + continue; + + // If we're done, just clear the current line. + if (data->GetCompleted()) { + output.Printf("\33[2K\r"); + continue; + } + + // Print over previous line, if any. + output.Printf("\r"); + + // Print the progress message. + std::string message = data->GetMessage(); + if (data->GetTotal() != UINT64_MAX) { + output.Printf("[%llu/%llu] %s...", data->GetCompleted(), + data->GetTotal(), message.c_str()); + } else { + output.Printf("%s...", message.c_str()); + } + + // Clear until the end of the line. + output.Printf("\x1B[K"); + + // Flush the output. + output.Flush(); + } + } + return {}; +} + bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); } bool Debugger::StartIOHandlerThread() { @@ -1751,6 +1826,29 @@ } } +bool Debugger::StartProgressHandlerThread() { + if (!m_progress_handler_thread.IsJoinable()) { + llvm::Expected progress_handler_thread = + ThreadLauncher::LaunchThread("lldb.debugger.progress-handler", [this] { + return ProgressHandlerThread(); + }); + 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" @@ -262,6 +263,10 @@ FileSystem::Instance().Exists(symbol_file_spec)) return symbol_file_spec; + Progress progress(llvm::formatv( + "Locating external symbol file for {0}", + module_spec.GetFileSpec().GetFilename().AsCString(""))); + FileSpecList debug_file_search_paths = default_search_paths; // Add module directory. 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);