Skip to content

Commit

Permalink
[lldb] Emit diagnostic events in the diagnostic dump
Browse files Browse the repository at this point in the history
Connect the diagnostic events with the diagnostic infrastructure.

 - Emit existing diagnostic events (warnings and errors) to the
   diagnostic log.
 - Introduce a new diagnostic event (info) that's used exclusively for
   diagnostic logging and does not get broadcast.

Differential revision: https://reviews.llvm.org/D136648
  • Loading branch information
JDevlieghere committed Oct 31, 2022
1 parent 0d01300 commit 8aed0ce
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 3 deletions.
20 changes: 20 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Expand Up @@ -425,6 +425,26 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
llvm::Optional<lldb::user_id_t> debugger_id = llvm::None,
std::once_flag *once = nullptr);

/// Report info events.
///
/// Unlike warning and error events, info events are not broadcast but are
/// logged for diagnostic purposes.
///
/// \param[in] message
/// The info message to be reported.
///
/// \param [in] debugger_id
/// If this optional parameter has a value, it indicates this diagnostic is
/// associated with a unique debugger instance.
///
/// \param [in] once
/// If a pointer is passed to a std::once_flag, then it will be used to
/// ensure the given info is only logged once.
static void
ReportInfo(std::string message,
llvm::Optional<lldb::user_id_t> debugger_id = llvm::None,
std::once_flag *once = nullptr);

static void ReportSymbolChange(const ModuleSpec &module_spec);

protected:
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/Core/DebuggerEvents.h
Expand Up @@ -52,6 +52,7 @@ class ProgressEventData : public EventData {
class DiagnosticEventData : public EventData {
public:
enum class Type {
Info,
Warning,
Error,
};
Expand Down
8 changes: 8 additions & 0 deletions lldb/include/lldb/Utility/Diagnostics.h
Expand Up @@ -39,11 +39,15 @@ class Diagnostics {
bool Dump(llvm::raw_ostream &stream, const FileSpec &dir);
/// @}

void Report(llvm::StringRef message);

using Callback = std::function<llvm::Error(const FileSpec &)>;

void AddCallback(Callback callback);

static Diagnostics &Instance();

static bool Enabled();
static void Initialize();
static void Terminate();

Expand All @@ -53,6 +57,10 @@ class Diagnostics {
private:
static llvm::Optional<Diagnostics> &InstanceImpl();

llvm::Error DumpDiangosticsLog(const FileSpec &dir) const;

RotatingLogHandler m_log_handler;

llvm::SmallVector<Callback, 4> m_callbacks;
std::mutex m_callbacks_mutex;
};
Expand Down
19 changes: 19 additions & 0 deletions lldb/source/Core/Debugger.cpp
Expand Up @@ -1311,6 +1311,9 @@ static void PrivateReportDiagnostic(Debugger &debugger,
bool debugger_specific) {
uint32_t event_type = 0;
switch (type) {
case DiagnosticEventData::Type::Info:
assert(false && "DiagnosticEventData::Type::Info should not be broadcast");
return;
case DiagnosticEventData::Type::Warning:
event_type = Debugger::eBroadcastBitWarning;
break;
Expand Down Expand Up @@ -1339,6 +1342,15 @@ void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type,
llvm::Optional<lldb::user_id_t> debugger_id,
std::once_flag *once) {
auto ReportDiagnosticLambda = [&]() {
// The diagnostic subsystem is optional but we still want to broadcast
// events when it's disabled.
if (Diagnostics::Enabled())
Diagnostics::Instance().Report(message);

// We don't broadcast info events.
if (type == DiagnosticEventData::Type::Info)
return;

// Check if this diagnostic is for a specific debugger.
if (debugger_id) {
// It is debugger specific, grab it and deliver the event if the debugger
Expand Down Expand Up @@ -1377,6 +1389,13 @@ void Debugger::ReportError(std::string message,
debugger_id, once);
}

void Debugger::ReportInfo(std::string message,
llvm::Optional<lldb::user_id_t> debugger_id,
std::once_flag *once) {
ReportDiagnosticImpl(DiagnosticEventData::Type::Info, std::move(message),
debugger_id, once);
}

void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Core/DebuggerEvents.cpp
Expand Up @@ -51,6 +51,8 @@ ProgressEventData::GetEventDataFromEvent(const Event *event_ptr) {

llvm::StringRef DiagnosticEventData::GetPrefix() const {
switch (m_type) {
case Type::Info:
return "info";
case Type::Warning:
return "warning";
case Type::Error:
Expand Down
27 changes: 24 additions & 3 deletions lldb/source/Utility/Diagnostics.cpp
Expand Up @@ -17,6 +17,8 @@ using namespace lldb_private;
using namespace lldb;
using namespace llvm;

static constexpr size_t g_num_log_messages = 100;

void Diagnostics::Initialize() {
lldbassert(!InstanceImpl() && "Already initialized.");
InstanceImpl().emplace();
Expand All @@ -27,14 +29,16 @@ void Diagnostics::Terminate() {
InstanceImpl().reset();
}

bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }

Optional<Diagnostics> &Diagnostics::InstanceImpl() {
static Optional<Diagnostics> g_diagnostics;
return g_diagnostics;
}

Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); }

Diagnostics::Diagnostics() {}
Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {}

Diagnostics::~Diagnostics() {}

Expand All @@ -58,8 +62,7 @@ bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {
stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";
stream << "Please include the directory content when filing a bug report\n";

Error error = Create(dir);
if (error) {
if (Error error = Create(dir)) {
stream << toString(std::move(error)) << '\n';
return false;
}
Expand All @@ -77,9 +80,27 @@ llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {
}

Error Diagnostics::Create(const FileSpec &dir) {
if (Error err = DumpDiangosticsLog(dir))
return err;

for (Callback c : m_callbacks) {
if (Error err = c(dir))
return err;
}

return Error::success();
}

llvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const {
FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log");
std::error_code ec;
llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None);
if (ec)
return errorCodeToError(ec);
m_log_handler.Dump(stream);
return Error::success();
}

void Diagnostics::Report(llvm::StringRef message) {
m_log_handler.Emit(message);
}
33 changes: 33 additions & 0 deletions lldb/test/Shell/Diagnostics/TestDiagnosticsLog.test
@@ -0,0 +1,33 @@
# RUN: yaml2obj %s -o %t
# RUN: mkdir -p %t.diags
# RUN: %lldb -c %t -o 'diagnostics dump -d %t.diags' 2> %t.stderr

# RUN: cat %t.stderr | FileCheck %s --check-prefix ERROR
# RUN: cat %t.diags/diagnostics.log | FileCheck %s --check-prefix ERROR

# ERROR: unable to retrieve process ID from minidump file, setting process ID to 1

--- !minidump
Streams:
- Type: ThreadList
Threads:
- Thread Id: 0x00003E81
Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Stack:
Start of Memory Range: 0x00007FFCEB34A000
Content: ''
- Type: ModuleList
Modules:
- Base of Image: 0x0000000000400000
Size of Image: 0x00017000
Module Name: 'a.out'
CodeView Record: ''
- Type: SystemInfo
Processor Arch: AMD64
Platform ID: Linux
CSD Version: 'Linux 3.13'
CPU:
Vendor ID: GenuineIntel
Version Info: 0x00000000
Feature Info: 0x00000000
...

0 comments on commit 8aed0ce

Please sign in to comment.