xref: /openbsd-src/gnu/llvm/lldb/source/Utility/Diagnostics.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1*f6aab3d8Srobert //===-- Diagnostics.cpp ---------------------------------------------------===//
2*f6aab3d8Srobert //
3*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information.
5*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*f6aab3d8Srobert //
7*f6aab3d8Srobert //===----------------------------------------------------------------------===//
8*f6aab3d8Srobert 
9*f6aab3d8Srobert #include "lldb/Utility/Diagnostics.h"
10*f6aab3d8Srobert #include "lldb/Utility/LLDBAssert.h"
11*f6aab3d8Srobert 
12*f6aab3d8Srobert #include "llvm/Support/Error.h"
13*f6aab3d8Srobert #include "llvm/Support/FileSystem.h"
14*f6aab3d8Srobert #include "llvm/Support/raw_ostream.h"
15*f6aab3d8Srobert #include <optional>
16*f6aab3d8Srobert 
17*f6aab3d8Srobert using namespace lldb_private;
18*f6aab3d8Srobert using namespace lldb;
19*f6aab3d8Srobert using namespace llvm;
20*f6aab3d8Srobert 
21*f6aab3d8Srobert static constexpr size_t g_num_log_messages = 100;
22*f6aab3d8Srobert 
Initialize()23*f6aab3d8Srobert void Diagnostics::Initialize() {
24*f6aab3d8Srobert   lldbassert(!InstanceImpl() && "Already initialized.");
25*f6aab3d8Srobert   InstanceImpl().emplace();
26*f6aab3d8Srobert }
27*f6aab3d8Srobert 
Terminate()28*f6aab3d8Srobert void Diagnostics::Terminate() {
29*f6aab3d8Srobert   lldbassert(InstanceImpl() && "Already terminated.");
30*f6aab3d8Srobert   InstanceImpl().reset();
31*f6aab3d8Srobert }
32*f6aab3d8Srobert 
Enabled()33*f6aab3d8Srobert bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }
34*f6aab3d8Srobert 
InstanceImpl()35*f6aab3d8Srobert std::optional<Diagnostics> &Diagnostics::InstanceImpl() {
36*f6aab3d8Srobert   static std::optional<Diagnostics> g_diagnostics;
37*f6aab3d8Srobert   return g_diagnostics;
38*f6aab3d8Srobert }
39*f6aab3d8Srobert 
Instance()40*f6aab3d8Srobert Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); }
41*f6aab3d8Srobert 
Diagnostics()42*f6aab3d8Srobert Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {}
43*f6aab3d8Srobert 
~Diagnostics()44*f6aab3d8Srobert Diagnostics::~Diagnostics() {}
45*f6aab3d8Srobert 
AddCallback(Callback callback)46*f6aab3d8Srobert void Diagnostics::AddCallback(Callback callback) {
47*f6aab3d8Srobert   std::lock_guard<std::mutex> guard(m_callbacks_mutex);
48*f6aab3d8Srobert   m_callbacks.push_back(callback);
49*f6aab3d8Srobert }
50*f6aab3d8Srobert 
Dump(raw_ostream & stream)51*f6aab3d8Srobert bool Diagnostics::Dump(raw_ostream &stream) {
52*f6aab3d8Srobert   Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory();
53*f6aab3d8Srobert   if (!diagnostics_dir) {
54*f6aab3d8Srobert     stream << "unable to create diagnostic dir: "
55*f6aab3d8Srobert            << toString(diagnostics_dir.takeError()) << '\n';
56*f6aab3d8Srobert     return false;
57*f6aab3d8Srobert   }
58*f6aab3d8Srobert 
59*f6aab3d8Srobert   return Dump(stream, *diagnostics_dir);
60*f6aab3d8Srobert }
61*f6aab3d8Srobert 
Dump(raw_ostream & stream,const FileSpec & dir)62*f6aab3d8Srobert bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {
63*f6aab3d8Srobert   stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";
64*f6aab3d8Srobert   stream << "Please include the directory content when filing a bug report\n";
65*f6aab3d8Srobert 
66*f6aab3d8Srobert   if (Error error = Create(dir)) {
67*f6aab3d8Srobert     stream << toString(std::move(error)) << '\n';
68*f6aab3d8Srobert     return false;
69*f6aab3d8Srobert   }
70*f6aab3d8Srobert 
71*f6aab3d8Srobert   return true;
72*f6aab3d8Srobert }
73*f6aab3d8Srobert 
CreateUniqueDirectory()74*f6aab3d8Srobert llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {
75*f6aab3d8Srobert   SmallString<128> diagnostics_dir;
76*f6aab3d8Srobert   std::error_code ec =
77*f6aab3d8Srobert       sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
78*f6aab3d8Srobert   if (ec)
79*f6aab3d8Srobert     return errorCodeToError(ec);
80*f6aab3d8Srobert   return FileSpec(diagnostics_dir.str());
81*f6aab3d8Srobert }
82*f6aab3d8Srobert 
Create(const FileSpec & dir)83*f6aab3d8Srobert Error Diagnostics::Create(const FileSpec &dir) {
84*f6aab3d8Srobert   if (Error err = DumpDiangosticsLog(dir))
85*f6aab3d8Srobert     return err;
86*f6aab3d8Srobert 
87*f6aab3d8Srobert   for (Callback c : m_callbacks) {
88*f6aab3d8Srobert     if (Error err = c(dir))
89*f6aab3d8Srobert       return err;
90*f6aab3d8Srobert   }
91*f6aab3d8Srobert 
92*f6aab3d8Srobert   return Error::success();
93*f6aab3d8Srobert }
94*f6aab3d8Srobert 
DumpDiangosticsLog(const FileSpec & dir) const95*f6aab3d8Srobert llvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const {
96*f6aab3d8Srobert   FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log");
97*f6aab3d8Srobert   std::error_code ec;
98*f6aab3d8Srobert   llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None);
99*f6aab3d8Srobert   if (ec)
100*f6aab3d8Srobert     return errorCodeToError(ec);
101*f6aab3d8Srobert   m_log_handler.Dump(stream);
102*f6aab3d8Srobert   return Error::success();
103*f6aab3d8Srobert }
104*f6aab3d8Srobert 
Report(llvm::StringRef message)105*f6aab3d8Srobert void Diagnostics::Report(llvm::StringRef message) {
106*f6aab3d8Srobert   m_log_handler.Emit(message);
107*f6aab3d8Srobert }
108