Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lldb/include/lldb/Core/BugReporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===----------------------------------------------------------------------===//
//
// 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_CORE_BUGREPORTER_H
#define LLDB_CORE_BUGREPORTER_H

#include "lldb/Core/Diagnostics.h"
#include "lldb/Core/PluginInterface.h"

#include "llvm/Support/Error.h"

namespace lldb_private {

/// A pluggable destination for a diagnostics bundle.
/// CreateBugReporterInstance() returns the first registered reporter, so
/// downstream registers ahead of the no-op fallback to take over.
class BugReporter : public PluginInterface {
public:
virtual llvm::Error File(const Diagnostics::Report &report) = 0;
};

} // namespace lldb_private

#endif // LLDB_CORE_BUGREPORTER_H
8 changes: 6 additions & 2 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <vector>

#include "lldb/Core/DebuggerEvents.h"
#include "lldb/Core/Diagnostics.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/SourceManager.h"
Expand All @@ -31,7 +32,6 @@
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Diagnostics.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
Expand Down Expand Up @@ -278,6 +278,11 @@ class Debugger : public std::enable_shared_from_this<Debugger>,

void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);

/// Copy this debugger's file-backed log files into the given directory, for
/// inclusion in a diagnostics bundle. Returns the names of the files that
/// were copied. Best-effort: files that cannot be copied are skipped.
std::vector<std::string> CopyLogFilesToDirectory(const FileSpec &dir);

Status SetPropertyValue(const ExecutionContext *exe_ctx,
VarSetOperationType op, llvm::StringRef property_path,
llvm::StringRef value) override;
Expand Down Expand Up @@ -816,7 +821,6 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
lldb::ListenerSP m_forward_listener_sp;
llvm::once_flag m_clear_once;
lldb::TargetSP m_dummy_target_sp;
Diagnostics::CallbackID m_diagnostics_callback_id;

/// Bookkeeping for command line progress events.
/// @{
Expand Down
154 changes: 154 additions & 0 deletions lldb/include/lldb/Core/Diagnostics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//===-- 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_CORE_DIAGNOSTICS_H
#define LLDB_CORE_DIAGNOSTICS_H

#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Log.h"
#include "llvm/Support/Error.h"

#include <functional>
#include <mutex>
#include <optional>
#include <string>
#include <vector>

namespace llvm {
namespace json {
class Value;
} // namespace json
} // namespace llvm

namespace lldb_private {

class Debugger;
class ExecutionContext;

/// Diagnostics maintain an always-on, in-memory log of recent diagnostic
/// messages that can be written out to help investigate bugs and troubleshoot
/// issues.
class Diagnostics {
public:
Diagnostics();
~Diagnostics();

/// The bundle directory and the files written into it, recorded as each one
/// is created so a file that could not be written is simply absent.
struct Attachments {
std::string directory;
std::vector<std::string> files;
};

/// The state a triager needs to make sense of a bug report. The full payload
/// is written into the bundle directory. These scalars are carried in the
/// terminal output and the report body rather than as redundant files. More
/// fields are expected to accrue over time.
struct Report {
std::string version;
std::string os;
std::string invocation;
Attachments attachments;
};

/// Write the in-memory diagnostic log into the given directory.
llvm::Error Create(const FileSpec &dir);

/// Collect a full diagnostics bundle into \p dir and return its report.
///
/// Writes the always-on log, the debugger's file-backed logs, statistics,
/// and a snapshot of the commands a triager runs first. Collection is
/// best-effort: a failure to produce one artifact never aborts the rest, so
/// a partial bundle is always better than none.
llvm::Expected<Report> Collect(Debugger &debugger,
const ExecutionContext &exe_ctx,
const FileSpec &dir);

/// Write the diagnostic log into a directory and print a message to the given
/// output stream.
/// @{
bool Dump(llvm::raw_ostream &stream);
bool Dump(llvm::raw_ostream &stream, const FileSpec &dir);
/// @}

/// Record a diagnostic message into the always-on, in-memory log.
void Record(llvm::StringRef message);

/// Supplies an artifact's contents on demand. Subsystems register a provider
/// so Core need not depend on them. Each runs when a bundle is collected.
using ArtifactProvider = std::function<std::string()>;
using ArtifactProviderID = uint64_t;

/// Register \p provider to contribute file \p name. Returns an id for
/// RemoveArtifactProvider. Thread-safe.
ArtifactProviderID AddArtifactProvider(std::string name,
ArtifactProvider provider);

/// Unregister a provider. Thread-safe.
void RemoveArtifactProvider(ArtifactProviderID id);

static Diagnostics &Instance();

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

/// Create a unique diagnostic directory.
static llvm::Expected<FileSpec> CreateUniqueDirectory();

private:
static std::optional<Diagnostics> &InstanceImpl();

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

/// Collect the individual parts of the bundle into \p dir, appending the name
/// of each file to \p files as it is written.
/// @{
void CollectLogs(Debugger &debugger, const FileSpec &dir,
std::vector<std::string> &files);
static void CollectStatistics(Debugger &debugger,
const ExecutionContext &exe_ctx,
const FileSpec &dir,
std::vector<std::string> &files);
static void CollectCommands(Debugger &debugger,
const ExecutionContext &exe_ctx,
const FileSpec &dir,
std::vector<std::string> &files);
void CollectArtifactProviders(const FileSpec &dir,
std::vector<std::string> &files);
/// @}

/// Scalars carried in the report rather than written as files.
/// @{
static std::string GetHostDescription(const ExecutionContext &exe_ctx);
static std::string GetInvocation();
/// @}

RotatingLogHandler m_log_handler;

struct ArtifactProviderEntry {
ArtifactProviderID id;
std::string name;
ArtifactProvider provider;
};

/// Registered artifact providers, guarded by the mutex.
/// @{
ArtifactProviderID m_next_artifact_provider_id = 0;
std::vector<ArtifactProviderEntry> m_artifact_providers;
std::mutex m_artifact_providers_mutex;
/// @}
};

/// Render a diagnostics report as JSON, for `diagnostics dump`'s terminal
/// output.
llvm::json::Value toJSON(const Diagnostics::Report &report);

} // namespace lldb_private

#endif
12 changes: 12 additions & 0 deletions lldb/include/lldb/Core/PluginManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ class PluginManager {
static std::unique_ptr<Architecture>
CreateArchitectureInstance(const ArchSpec &arch);

// BugReporter
static void RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
BugReporterCreateInstance create_callback);

static void UnregisterPlugin(BugReporterCreateInstance create_callback);

static std::unique_ptr<BugReporter>
CreateBugReporterInstance(llvm::StringRef name = {});

// Disassembler
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
DisassemblerCreateInstance create_callback);
Expand Down Expand Up @@ -719,6 +728,9 @@ class PluginManager {
static std::vector<RegisteredPluginInfo> GetArchitecturePluginInfo();
static bool SetArchitecturePluginEnabled(llvm::StringRef name, bool enable);

static std::vector<RegisteredPluginInfo> GetBugReporterPluginInfo();
static bool SetBugReporterPluginEnabled(llvm::StringRef name, bool enable);

static std::vector<RegisteredPluginInfo> GetDisassemblerPluginInfo();
static bool SetDisassemblerPluginEnabled(llvm::StringRef name, bool enable);

Expand Down
7 changes: 7 additions & 0 deletions lldb/include/lldb/Host/Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,15 @@ class Host {
const FileSpec &file_spec,
uint32_t line_no);

/// Open a URL with the host's default handler (Launch Services on macOS,
/// xdg-open on other Unix). Returns an error if opening fails or the platform
/// has no implementation (e.g. Windows).
static llvm::Error OpenURL(llvm::StringRef url);

/// Percent-encode a string for use in a URL query component, per RFC 3986
/// (alphanumerics and "-_.~" are kept literal; everything else becomes %HH).
static std::string URLEncode(llvm::StringRef str);

/// Check if we're running in an interactive graphical session.
///
/// \return
Expand Down
86 changes: 0 additions & 86 deletions lldb/include/lldb/Utility/Diagnostics.h

This file was deleted.

1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class BreakpointSite;
class BroadcastEventSpec;
class Broadcaster;
class BroadcasterManager;
class BugReporter;
class CXXSyntheticChildren;
struct CacheSignature;
class CallFrameInfo;
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-private-interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef lldb::ABISP (*ABICreateInstance)(lldb::ProcessSP process_sp,
const ArchSpec &arch);
typedef std::unique_ptr<Architecture> (*ArchitectureCreateInstance)(
const ArchSpec &arch);
typedef std::unique_ptr<BugReporter> (*BugReporterCreateInstance)();
typedef lldb::DisassemblerSP (*DisassemblerCreateInstance)(
const ArchSpec &arch, const char *flavor, const char *cpu,
const char *features);
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/API/SBDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "lldb/Core/Debugger.h"
#include "lldb/Core/DebuggerEvents.h"
#include "lldb/Core/Diagnostics.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Progress.h"
#include "lldb/Core/StructuredDataImpl.h"
Expand All @@ -51,7 +52,6 @@
#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
Loading