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