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