xref: /freebsd-src/contrib/llvm-project/lldb/source/Utility/Diagnostics.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
Initialize()23bdd1243dSDimitry Andric void Diagnostics::Initialize() {
24bdd1243dSDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
25bdd1243dSDimitry Andric   InstanceImpl().emplace();
26bdd1243dSDimitry Andric }
27bdd1243dSDimitry Andric 
Terminate()28bdd1243dSDimitry Andric void Diagnostics::Terminate() {
29bdd1243dSDimitry Andric   lldbassert(InstanceImpl() && "Already terminated.");
30bdd1243dSDimitry Andric   InstanceImpl().reset();
31bdd1243dSDimitry Andric }
32bdd1243dSDimitry Andric 
Enabled()33bdd1243dSDimitry Andric bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }
34bdd1243dSDimitry Andric 
InstanceImpl()35bdd1243dSDimitry Andric std::optional<Diagnostics> &Diagnostics::InstanceImpl() {
36bdd1243dSDimitry Andric   static std::optional<Diagnostics> g_diagnostics;
37bdd1243dSDimitry Andric   return g_diagnostics;
38bdd1243dSDimitry Andric }
39bdd1243dSDimitry Andric 
Instance()40bdd1243dSDimitry Andric Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); }
41bdd1243dSDimitry Andric 
Diagnostics()42bdd1243dSDimitry Andric Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {}
43bdd1243dSDimitry Andric 
~Diagnostics()44bdd1243dSDimitry Andric Diagnostics::~Diagnostics() {}
45bdd1243dSDimitry Andric 
AddCallback(Callback callback)4606c3fb27SDimitry Andric Diagnostics::CallbackID Diagnostics::AddCallback(Callback callback) {
47bdd1243dSDimitry Andric   std::lock_guard<std::mutex> guard(m_callbacks_mutex);
4806c3fb27SDimitry Andric   CallbackID id = m_callback_id++;
4906c3fb27SDimitry Andric   m_callbacks.emplace_back(id, callback);
5006c3fb27SDimitry Andric   return id;
5106c3fb27SDimitry Andric }
5206c3fb27SDimitry Andric 
RemoveCallback(CallbackID id)5306c3fb27SDimitry Andric void Diagnostics::RemoveCallback(CallbackID id) {
5406c3fb27SDimitry Andric   std::lock_guard<std::mutex> guard(m_callbacks_mutex);
55*5f757f3fSDimitry Andric   llvm::erase_if(m_callbacks,
56*5f757f3fSDimitry Andric                  [id](const CallbackEntry &e) { return e.id == id; });
57bdd1243dSDimitry Andric }
58bdd1243dSDimitry Andric 
Dump(raw_ostream & stream)59bdd1243dSDimitry Andric bool Diagnostics::Dump(raw_ostream &stream) {
60bdd1243dSDimitry Andric   Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory();
61bdd1243dSDimitry Andric   if (!diagnostics_dir) {
62bdd1243dSDimitry Andric     stream << "unable to create diagnostic dir: "
63bdd1243dSDimitry Andric            << toString(diagnostics_dir.takeError()) << '\n';
64bdd1243dSDimitry Andric     return false;
65bdd1243dSDimitry Andric   }
66bdd1243dSDimitry Andric 
67bdd1243dSDimitry Andric   return Dump(stream, *diagnostics_dir);
68bdd1243dSDimitry Andric }
69bdd1243dSDimitry Andric 
Dump(raw_ostream & stream,const FileSpec & dir)70bdd1243dSDimitry Andric bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {
71bdd1243dSDimitry Andric   stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";
72bdd1243dSDimitry Andric   stream << "Please include the directory content when filing a bug report\n";
73bdd1243dSDimitry Andric 
74bdd1243dSDimitry Andric   if (Error error = Create(dir)) {
75bdd1243dSDimitry Andric     stream << toString(std::move(error)) << '\n';
76bdd1243dSDimitry Andric     return false;
77bdd1243dSDimitry Andric   }
78bdd1243dSDimitry Andric 
79bdd1243dSDimitry Andric   return true;
80bdd1243dSDimitry Andric }
81bdd1243dSDimitry Andric 
CreateUniqueDirectory()82bdd1243dSDimitry Andric llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {
83bdd1243dSDimitry Andric   SmallString<128> diagnostics_dir;
84bdd1243dSDimitry Andric   std::error_code ec =
85bdd1243dSDimitry Andric       sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);
86bdd1243dSDimitry Andric   if (ec)
87bdd1243dSDimitry Andric     return errorCodeToError(ec);
88bdd1243dSDimitry Andric   return FileSpec(diagnostics_dir.str());
89bdd1243dSDimitry Andric }
90bdd1243dSDimitry Andric 
Create(const FileSpec & dir)91bdd1243dSDimitry Andric Error Diagnostics::Create(const FileSpec &dir) {
92bdd1243dSDimitry Andric   if (Error err = DumpDiangosticsLog(dir))
93bdd1243dSDimitry Andric     return err;
94bdd1243dSDimitry Andric 
9506c3fb27SDimitry Andric   for (CallbackEntry e : m_callbacks) {
9606c3fb27SDimitry Andric     if (Error err = e.callback(dir))
97bdd1243dSDimitry Andric       return err;
98bdd1243dSDimitry Andric   }
99bdd1243dSDimitry Andric 
100bdd1243dSDimitry Andric   return Error::success();
101bdd1243dSDimitry Andric }
102bdd1243dSDimitry Andric 
DumpDiangosticsLog(const FileSpec & dir) const103bdd1243dSDimitry Andric llvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const {
104bdd1243dSDimitry Andric   FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log");
105bdd1243dSDimitry Andric   std::error_code ec;
106bdd1243dSDimitry Andric   llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None);
107bdd1243dSDimitry Andric   if (ec)
108bdd1243dSDimitry Andric     return errorCodeToError(ec);
109bdd1243dSDimitry Andric   m_log_handler.Dump(stream);
110bdd1243dSDimitry Andric   return Error::success();
111bdd1243dSDimitry Andric }
112bdd1243dSDimitry Andric 
Report(llvm::StringRef message)113bdd1243dSDimitry Andric void Diagnostics::Report(llvm::StringRef message) {
114bdd1243dSDimitry Andric   m_log_handler.Emit(message);
115bdd1243dSDimitry Andric }
116