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