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*f6aab3d8Srobertvoid Diagnostics::Initialize() { 24*f6aab3d8Srobert lldbassert(!InstanceImpl() && "Already initialized."); 25*f6aab3d8Srobert InstanceImpl().emplace(); 26*f6aab3d8Srobert } 27*f6aab3d8Srobert Terminate()28*f6aab3d8Srobertvoid Diagnostics::Terminate() { 29*f6aab3d8Srobert lldbassert(InstanceImpl() && "Already terminated."); 30*f6aab3d8Srobert InstanceImpl().reset(); 31*f6aab3d8Srobert } 32*f6aab3d8Srobert Enabled()33*f6aab3d8Srobertbool Diagnostics::Enabled() { return InstanceImpl().operator bool(); } 34*f6aab3d8Srobert InstanceImpl()35*f6aab3d8Srobertstd::optional<Diagnostics> &Diagnostics::InstanceImpl() { 36*f6aab3d8Srobert static std::optional<Diagnostics> g_diagnostics; 37*f6aab3d8Srobert return g_diagnostics; 38*f6aab3d8Srobert } 39*f6aab3d8Srobert Instance()40*f6aab3d8SrobertDiagnostics &Diagnostics::Instance() { return *InstanceImpl(); } 41*f6aab3d8Srobert Diagnostics()42*f6aab3d8SrobertDiagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {} 43*f6aab3d8Srobert ~Diagnostics()44*f6aab3d8SrobertDiagnostics::~Diagnostics() {} 45*f6aab3d8Srobert AddCallback(Callback callback)46*f6aab3d8Srobertvoid 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*f6aab3d8Srobertbool 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*f6aab3d8Srobertbool 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*f6aab3d8Srobertllvm::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*f6aab3d8SrobertError 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*f6aab3d8Srobertllvm::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*f6aab3d8Srobertvoid Diagnostics::Report(llvm::StringRef message) { 106*f6aab3d8Srobert m_log_handler.Emit(message); 107*f6aab3d8Srobert } 108