Skip to content

Commit 5a27b99

Browse files
committed
[lldb] Show progress events in the command line driver
This patch adds support for showing progress events when using lldb on the command line. It spawns a separate thread that listens for progress events and prints them to the debugger's output stream. It's nothing fancy (yet), for now it just prints the progress message. If we know the total number of items being processed, we prefix the message with something like [1/100], similar to ninja's output. This patch doesn't use any fancy terminal manipulation: it uses a simple carriage return (\r) to bring the cursor to the front of the line and vt100 escape codes to clear the (rest) of the line. Differential revision: https://reviews.llvm.org/D120972
1 parent bfab18d commit 5a27b99

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
329329

330330
bool SetUseColor(bool use_color);
331331

332+
bool GetShowProgress() const;
333+
332334
bool GetUseAutosuggestion() const;
333335

334336
llvm::StringRef GetAutosuggestionAnsiPrefix() const;
@@ -439,6 +441,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
439441
uint64_t completed, uint64_t total,
440442
llvm::Optional<lldb::user_id_t> debugger_id);
441443

444+
void PrintProgress(const Debugger::ProgressEventData &data);
445+
442446
bool StartEventHandlerThread();
443447

444448
void StopEventHandlerThread();
@@ -466,6 +470,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
466470

467471
void HandleThreadEvent(const lldb::EventSP &event_sp);
468472

473+
void HandleProgressEvent(const lldb::EventSP &event_sp);
474+
469475
// Ensures two threads don't attempt to flush process output in parallel.
470476
std::mutex m_output_flush_mutex;
471477
void FlushProcessOutput(Process &process, bool flush_stdout,
@@ -514,6 +520,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
514520
IOHandlerStack m_io_handler_stack;
515521
std::recursive_mutex m_io_handler_synchronous_mutex;
516522

523+
llvm::Optional<uint64_t> m_current_event_id;
524+
517525
llvm::StringMap<std::weak_ptr<llvm::raw_ostream>> m_log_streams;
518526
std::shared_ptr<llvm::raw_ostream> m_log_callback_stream_sp;
519527
ConstString m_instance_name;

lldb/source/Core/CoreProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ let Definition = "debugger" in {
131131
Global,
132132
DefaultTrue,
133133
Desc<"Whether to use Ansi color codes or not.">;
134+
def ShowProgress: Property<"show-progress", "Boolean">,
135+
Global,
136+
DefaultTrue,
137+
Desc<"Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.">;
134138
def UseSourceCache: Property<"use-source-cache", "Boolean">,
135139
Global,
136140
DefaultTrue,

lldb/source/Core/Debugger.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,12 @@ bool Debugger::SetUseColor(bool b) {
378378
return ret;
379379
}
380380

381+
bool Debugger::GetShowProgress() const {
382+
const uint32_t idx = ePropertyShowProgress;
383+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
384+
nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
385+
}
386+
381387
bool Debugger::GetUseAutosuggestion() const {
382388
const uint32_t idx = ePropertyShowAutosuggestion;
383389
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -1615,6 +1621,11 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
16151621
CommandInterpreter::eBroadcastBitAsynchronousOutputData |
16161622
CommandInterpreter::eBroadcastBitAsynchronousErrorData);
16171623

1624+
if (!m_broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitProgress)) {
1625+
listener_sp->StartListeningForEvents(&m_broadcaster,
1626+
Debugger::eBroadcastBitProgress);
1627+
}
1628+
16181629
// Let the thread that spawned us know that we have started up and that we
16191630
// are now listening to all required events so no events get missed
16201631
m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
@@ -1664,6 +1675,9 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
16641675
}
16651676
}
16661677
}
1678+
} else if (broadcaster == &m_broadcaster) {
1679+
if (event_type & Debugger::eBroadcastBitProgress)
1680+
HandleProgressEvent(event_sp);
16671681
}
16681682
}
16691683

@@ -1729,6 +1743,61 @@ lldb::thread_result_t Debugger::IOHandlerThread() {
17291743
return {};
17301744
}
17311745

1746+
void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
1747+
auto *data =
1748+
Debugger::ProgressEventData::GetEventDataFromEvent(event_sp.get());
1749+
if (!data)
1750+
return;
1751+
1752+
// Do some bookkeeping for the current event, regardless of whether we're
1753+
// going to show the progress.
1754+
const uint64_t id = data->GetID();
1755+
if (m_current_event_id) {
1756+
if (id != *m_current_event_id)
1757+
return;
1758+
if (data->GetCompleted())
1759+
m_current_event_id.reset();
1760+
} else {
1761+
m_current_event_id = id;
1762+
}
1763+
1764+
// Decide whether we actually are going to show the progress. This decision
1765+
// can change between iterations so check it inside the loop.
1766+
if (!GetShowProgress())
1767+
return;
1768+
1769+
// Determine whether the current output file is an interactive terminal with
1770+
// color support. We assume that if we support ANSI escape codes we support
1771+
// vt100 escape codes.
1772+
File &output = GetOutputFile();
1773+
if (!output.GetIsInteractive() || !output.GetIsTerminalWithColors())
1774+
return;
1775+
1776+
if (data->GetCompleted()) {
1777+
// Clear the current line.
1778+
output.Printf("\33[2K\r");
1779+
return;
1780+
}
1781+
1782+
// Print over previous line, if any.
1783+
output.Printf("\r");
1784+
1785+
// Print the progress message.
1786+
std::string message = data->GetMessage();
1787+
if (data->GetTotal() != UINT64_MAX) {
1788+
output.Printf("[%llu/%llu] %s...", data->GetCompleted(), data->GetTotal(),
1789+
message.c_str());
1790+
} else {
1791+
output.Printf("%s...", message.c_str());
1792+
}
1793+
1794+
// Clear until the end of the line.
1795+
output.Printf("\x1B[K");
1796+
1797+
// Flush the output.
1798+
output.Flush();
1799+
}
1800+
17321801
bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); }
17331802

17341803
bool Debugger::StartIOHandlerThread() {

lldb/source/Symbol/LocateSymbolFile.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "lldb/Core/ModuleList.h"
1212
#include "lldb/Core/ModuleSpec.h"
13+
#include "lldb/Core/Progress.h"
1314
#include "lldb/Host/FileSystem.h"
1415
#include "lldb/Symbol/ObjectFile.h"
1516
#include "lldb/Utility/ArchSpec.h"
@@ -262,6 +263,10 @@ Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec,
262263
FileSystem::Instance().Exists(symbol_file_spec))
263264
return symbol_file_spec;
264265

266+
Progress progress(llvm::formatv(
267+
"Locating external symbol file for {0}",
268+
module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")));
269+
265270
FileSpecList debug_file_search_paths = default_search_paths;
266271

267272
// Add module directory.

0 commit comments

Comments
 (0)