llvm-project/lldb/source/Core/DebuggerEvents.cpp
Jonas Devlieghere 129eb5bcab
[lldb] Add the ability to provide a message to a progress event update
Consider the following example as motivation. Say you have to load
symbols for 3 dynamic libraries: `libFoo`, `libBar` and `libBaz`.
Currently, there are two ways to report process for this operation:

 1. As 3 separate progress instances. In this case you create a progress
    instance with the message "Loading symbols: libFoo", "Loading
    symbols: libBar", and "Loading symbols: libBaz" respectively. Each
    progress event gets a unique ID and therefore cannot be correlated
    by the consumer.

 2. As 1 progress instance with 3 units of work. The title would be
    "Loading symbols" and you call Progress::Increment for each of the
    libraries. The 3 progress events share the same ID and can easily be
    correlated, however, in the current design, there's no way to
    include the name of the libraries.

The second approach is preferred when the amount of work is known in
advance, because determinate progress can be reported (i.e. x out of y
operations completed). An additional benefit is that the progress
consumer can decide to ignore certain progress updates by their ID if
they are deemed to noisy, which isn't trivial for the first approach due
to the use of different progress IDs.

This patch adds the ability to add a message (detail) to a progress
event update. For the example described above, progress can now be
displayed as shown:

  [1/3] Loading symbols: libFoo
  [2/3] Loading symbols: libBar
  [3/3] Loading symbols: libBaz

Differential revision: https://reviews.llvm.org/D143690
2023-02-12 11:17:58 -08:00

160 lines
5.4 KiB
C++

//===-- DebuggerEvents.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/DebuggerEvents.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "llvm/Support/WithColor.h"
using namespace lldb_private;
using namespace lldb;
template <typename T>
static const T *GetEventDataFromEventImpl(const Event *event_ptr) {
if (event_ptr)
if (const EventData *event_data = event_ptr->GetData())
if (event_data->GetFlavor() == T::GetFlavorString())
return static_cast<const T *>(event_ptr->GetData());
return nullptr;
}
ConstString ProgressEventData::GetFlavorString() {
static ConstString g_flavor("ProgressEventData");
return g_flavor;
}
ConstString ProgressEventData::GetFlavor() const {
return ProgressEventData::GetFlavorString();
}
void ProgressEventData::Dump(Stream *s) const {
s->Printf(" id = %" PRIu64 ", title = \"%s\"", m_id, m_title.c_str());
if (!m_details.empty())
s->Printf(", details = \"%s\"", m_details.c_str());
if (m_completed == 0 || m_completed == m_total)
s->Printf(", type = %s", m_completed == 0 ? "start" : "end");
else
s->PutCString(", type = update");
// If m_total is UINT64_MAX, there is no progress to report, just "start"
// and "end". If it isn't we will show the completed and total amounts.
if (m_total != UINT64_MAX)
s->Printf(", progress = %" PRIu64 " of %" PRIu64, m_completed, m_total);
}
const ProgressEventData *
ProgressEventData::GetEventDataFromEvent(const Event *event_ptr) {
return GetEventDataFromEventImpl<ProgressEventData>(event_ptr);
}
StructuredData::DictionarySP
ProgressEventData::GetAsStructuredData(const Event *event_ptr) {
const ProgressEventData *progress_data =
ProgressEventData::GetEventDataFromEvent(event_ptr);
if (!progress_data)
return {};
auto dictionary_sp = std::make_shared<StructuredData::Dictionary>();
dictionary_sp->AddStringItem("title", progress_data->GetTitle());
dictionary_sp->AddStringItem("details", progress_data->GetDetails());
dictionary_sp->AddStringItem("message", progress_data->GetMessage());
dictionary_sp->AddIntegerItem("progress_id", progress_data->GetID());
dictionary_sp->AddIntegerItem("completed", progress_data->GetCompleted());
dictionary_sp->AddIntegerItem("total", progress_data->GetTotal());
dictionary_sp->AddBooleanItem("debugger_specific",
progress_data->IsDebuggerSpecific());
return dictionary_sp;
}
llvm::StringRef DiagnosticEventData::GetPrefix() const {
switch (m_type) {
case Type::Info:
return "info";
case Type::Warning:
return "warning";
case Type::Error:
return "error";
}
llvm_unreachable("Fully covered switch above!");
}
void DiagnosticEventData::Dump(Stream *s) const {
llvm::HighlightColor color = m_type == Type::Warning
? llvm::HighlightColor::Warning
: llvm::HighlightColor::Error;
llvm::WithColor(s->AsRawOstream(), color, llvm::ColorMode::Enable)
<< GetPrefix();
*s << ": " << GetMessage() << '\n';
s->Flush();
}
ConstString DiagnosticEventData::GetFlavorString() {
static ConstString g_flavor("DiagnosticEventData");
return g_flavor;
}
ConstString DiagnosticEventData::GetFlavor() const {
return DiagnosticEventData::GetFlavorString();
}
const DiagnosticEventData *
DiagnosticEventData::GetEventDataFromEvent(const Event *event_ptr) {
return GetEventDataFromEventImpl<DiagnosticEventData>(event_ptr);
}
StructuredData::DictionarySP
DiagnosticEventData::GetAsStructuredData(const Event *event_ptr) {
const DiagnosticEventData *diagnostic_data =
DiagnosticEventData::GetEventDataFromEvent(event_ptr);
if (!diagnostic_data)
return {};
auto dictionary_sp = std::make_shared<StructuredData::Dictionary>();
dictionary_sp->AddStringItem("message", diagnostic_data->GetMessage());
dictionary_sp->AddStringItem("type", diagnostic_data->GetPrefix());
dictionary_sp->AddBooleanItem("debugger_specific",
diagnostic_data->IsDebuggerSpecific());
return dictionary_sp;
}
ConstString SymbolChangeEventData::GetFlavorString() {
static ConstString g_flavor("SymbolChangeEventData");
return g_flavor;
}
ConstString SymbolChangeEventData::GetFlavor() const {
return SymbolChangeEventData::GetFlavorString();
}
const SymbolChangeEventData *
SymbolChangeEventData::GetEventDataFromEvent(const Event *event_ptr) {
return GetEventDataFromEventImpl<SymbolChangeEventData>(event_ptr);
}
void SymbolChangeEventData::DoOnRemoval(Event *event_ptr) {
DebuggerSP debugger_sp(m_debugger_wp.lock());
if (!debugger_sp)
return;
for (TargetSP target_sp : debugger_sp->GetTargetList().Targets()) {
if (ModuleSP module_sp =
target_sp->GetImages().FindModule(m_module_spec.GetUUID())) {
{
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (!module_sp->GetSymbolFileFileSpec())
module_sp->SetSymbolFileFileSpec(m_module_spec.GetSymbolFileSpec());
}
ModuleList module_list;
module_list.Append(module_sp);
target_sp->SymbolsDidLoad(module_list);
}
}
}