Skip to content

Commit

Permalink
[lldb] Add diagnostics
Browse files Browse the repository at this point in the history
Around this time last year, I said on the mailing list [1] that I wanted
to to transform the reproducers into something that resembles a
sysdiagnose on Apple platforms: a collection of files containing a
variety of information to help diagnose bugs or troubleshoot issues.

This patch adds that framework. Based on lessons learned from the
reproducers, I've intentionally tried to keep it small and simple.
Different parts of LLDB can register callbacks (this is necessary for
layering purposes) that will get called when the diagnostics should be
generated.

[1] https://lists.llvm.org/pipermail/lldb-dev/2021-September/017045.html

Differential revision: https://reviews.llvm.org/D134991
  • Loading branch information
JDevlieghere committed Oct 31, 2022
1 parent 1f8ac37 commit 84ea6b6
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lldb/include/lldb/API/SBDebugger.h
Expand Up @@ -94,6 +94,8 @@ class LLDB_API SBDebugger {

static void PrintStackTraceOnError();

static void PrintDiagnosticsOnError();

static void Terminate();

// Deprecated, use the one that takes a source_init_files bool.
Expand Down
56 changes: 56 additions & 0 deletions lldb/include/lldb/Utility/Diagnostics.h
@@ -0,0 +1,56 @@
//===-- Diagnostics.h -------------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_DIAGNOSTICS_H
#define LLDB_UTILITY_DIAGNOSTICS_H

#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Error.h"

#include <functional>
#include <mutex>
#include <vector>

namespace lldb_private {

/// Diagnostics are a collection of files to help investigate bugs and
/// troubleshoot issues. Any part of the debugger can register itself with the
/// help of a callback to emit one or more files into the diagnostic directory.
class Diagnostics {
public:
Diagnostics();
~Diagnostics();

/// Gather diagnostics in the given directory.
llvm::Error Create(const FileSpec &dir);

/// Gather diagnostics and print a message to the given output stream.
bool Dump(llvm::raw_ostream &stream);

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

void AddCallback(Callback callback);

static Diagnostics &Instance();
static void Initialize();
static void Terminate();

private:
static llvm::Optional<Diagnostics> &InstanceImpl();

llvm::SmallVector<Callback, 4> m_callbacks;
std::mutex m_callbacks_mutex;
};

} // namespace lldb_private

#endif
11 changes: 11 additions & 0 deletions lldb/source/API/SBDebugger.cpp
Expand Up @@ -51,6 +51,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Diagnostics.h"
#include "lldb/Utility/State.h"
#include "lldb/Version/Version.h"

Expand Down Expand Up @@ -218,6 +219,16 @@ void SBDebugger::PrintStackTraceOnError() {
llvm::sys::PrintStackTraceOnErrorSignal(executable);
}

static void DumpDiagnostics(void *cookie) {
Diagnostics::Instance().Dump(llvm::errs());
}

void SBDebugger::PrintDiagnosticsOnError() {
LLDB_INSTRUMENT();

llvm::sys::AddSignalHandler(&DumpDiagnostics, nullptr);
}

void SBDebugger::Terminate() {
LLDB_INSTRUMENT();

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Core/Debugger.cpp
Expand Up @@ -44,6 +44,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/Diagnostics.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Listener.h"
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Initialization/SystemInitializerCommon.cpp
Expand Up @@ -12,6 +12,8 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Socket.h"
#include "lldb/Target/Statistics.h"
#include "lldb/Utility/Diagnostics.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Timer.h"
#include "lldb/Version/Version.h"
Expand Down Expand Up @@ -63,6 +65,7 @@ llvm::Error SystemInitializerCommon::Initialize() {

InitializeLldbChannel();

Diagnostics::Initialize();
FileSystem::Initialize();
HostInfo::Initialize(m_shlib_dir_helper);

Expand Down Expand Up @@ -95,4 +98,5 @@ void SystemInitializerCommon::Terminate() {
HostInfo::Terminate();
Log::DisableAllLogChannels();
FileSystem::Terminate();
Diagnostics::Terminate();
}
1 change: 1 addition & 0 deletions lldb/source/Utility/CMakeLists.txt
Expand Up @@ -35,6 +35,7 @@ add_lldb_library(lldbUtility
DataBufferLLVM.cpp
DataEncoder.cpp
DataExtractor.cpp
Diagnostics.cpp
Environment.cpp
Event.cpp
FileSpec.cpp
Expand Down
74 changes: 74 additions & 0 deletions lldb/source/Utility/Diagnostics.cpp
@@ -0,0 +1,74 @@
//===-- Diagnostics.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/Utility/Diagnostics.h"
#include "lldb/Utility/LLDBAssert.h"

#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"

using namespace lldb_private;
using namespace lldb;
using namespace llvm;

void Diagnostics::Initialize() {
lldbassert(!InstanceImpl() && "Already initialized.");
InstanceImpl().emplace();
}

void Diagnostics::Terminate() {
lldbassert(InstanceImpl() && "Already terminated.");
InstanceImpl().reset();
}

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

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

Diagnostics::Diagnostics() {}

Diagnostics::~Diagnostics() {}

void Diagnostics::AddCallback(Callback callback) {
std::lock_guard<std::mutex> guard(m_callbacks_mutex);
m_callbacks.push_back(callback);
}

bool Diagnostics::Dump(raw_ostream &stream) {
SmallString<128> diagnostics_dir;
std::error_code ec =
sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
if (ec) {
stream << "unable to create diagnostic dir: "
<< toString(errorCodeToError(ec)) << '\n';
return false;
}

stream << "LLDB diagnostics written to " << diagnostics_dir << "\n";
stream << "Please include the directory content when filing a bug report\n";

Error error = Create(FileSpec(diagnostics_dir.str()));
if (error) {
stream << toString(std::move(error)) << '\n';
return false;
}

return true;
}

Error Diagnostics::Create(const FileSpec &dir) {
for (Callback c : m_callbacks) {
if (Error err = c(dir))
return err;
}
return Error::success();
}
4 changes: 4 additions & 0 deletions lldb/tools/driver/Driver.cpp
Expand Up @@ -788,6 +788,10 @@ int main(int argc, char const *argv[]) {
<< '\n';
return 1;
}

// Setup LLDB signal handlers once the debugger has been initialized.
SBDebugger::PrintDiagnosticsOnError();

SBHostOS::ThreadCreated("<lldb.driver.main-thread>");

signal(SIGINT, sigint_handler);
Expand Down

0 comments on commit 84ea6b6

Please sign in to comment.