//===-- Reproducer.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/ProcessInfo.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" using namespace lldb_private; using namespace lldb_private::repro; using namespace llvm; using namespace llvm::yaml; llvm::Expected> DataRecorder::Create(const FileSpec &filename) { std::error_code ec; auto recorder = std::make_unique(std::move(filename), ec); if (ec) return llvm::errorCodeToError(ec); return std::move(recorder); } llvm::Expected> YamlRecorder::Create(const FileSpec &filename) { std::error_code ec; auto recorder = std::make_unique(std::move(filename), ec); if (ec) return llvm::errorCodeToError(ec); return std::move(recorder); } void VersionProvider::Keep() { FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code ec; llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); if (ec) return; os << m_version << "\n"; } FlushingFileCollector::FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path, std::error_code &ec) { auto clear = llvm::make_scope_exit([this]() { m_files_os.reset(); m_dirs_os.reset(); }); m_files_os.emplace(files_path, ec, llvm::sys::fs::OF_Append); if (ec) return; m_dirs_os.emplace(dirs_path, ec, llvm::sys::fs::OF_Append); if (ec) return; clear.release(); } void FlushingFileCollector::addFileImpl(StringRef file) { if (m_files_os) { *m_files_os << file << '\0'; m_files_os->flush(); } } llvm::vfs::directory_iterator FlushingFileCollector::addDirectoryImpl(const Twine &dir, IntrusiveRefCntPtr vfs, std::error_code &dir_ec) { if (m_dirs_os) { *m_dirs_os << dir << '\0'; m_dirs_os->flush(); } return vfs->dir_begin(dir, dir_ec); } void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) { if (m_collector) m_collector->addFile(dir); } void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) { if (m_collector) m_collector->addDirectory(dir); } llvm::Expected> ProcessInfoRecorder::Create(const FileSpec &filename) { std::error_code ec; auto recorder = std::make_unique(std::move(filename), ec); if (ec) return llvm::errorCodeToError(ec); return std::move(recorder); } void ProcessInfoProvider::Keep() { std::vector files; for (auto &recorder : m_process_info_recorders) { recorder->Stop(); files.push_back(recorder->GetFilename().GetPath()); } FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code ec; llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); if (ec) return; llvm::yaml::Output yout(os); yout << files; } void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { std::size_t i = m_process_info_recorders.size() + 1; std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + llvm::Twine(i) + llvm::Twine(".yaml")) .str(); auto recorder_or_error = ProcessInfoRecorder::Create( GetRoot().CopyByAppendingPathComponent(filename)); if (!recorder_or_error) { llvm::consumeError(recorder_or_error.takeError()); return nullptr; } m_process_info_recorders.push_back(std::move(*recorder_or_error)); return m_process_info_recorders.back().get(); } void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { if (!m_record) return; llvm::yaml::Output yout(m_os); yout << const_cast(process_infos); m_os.flush(); } void SymbolFileProvider::AddSymbolFile(const UUID *uuid, const FileSpec &module_file, const FileSpec &symbol_file) { if (!uuid || (!module_file && !symbol_file)) return; m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(), symbol_file.GetPath()); } void SymbolFileProvider::Keep() { FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code ec; llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); if (ec) return; // Remove duplicates. llvm::sort(m_symbol_files.begin(), m_symbol_files.end()); m_symbol_files.erase( std::unique(m_symbol_files.begin(), m_symbol_files.end()), m_symbol_files.end()); llvm::yaml::Output yout(os); yout << m_symbol_files; } SymbolFileLoader::SymbolFileLoader(Loader *loader) { if (!loader) return; FileSpec file = loader->GetFile(); if (!file) return; auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); if (auto err = error_or_file.getError()) return; llvm::yaml::Input yin((*error_or_file)->getBuffer()); yin >> m_symbol_files; } std::pair SymbolFileLoader::GetPaths(const UUID *uuid) const { if (!uuid) return {}; auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(), SymbolFileProvider::Entry(uuid->GetAsString())); if (it == m_symbol_files.end()) return {}; return std::make_pair(FileSpec(it->module_path), FileSpec(it->symbol_path)); } void ProviderBase::anchor() {} char CommandProvider::ID = 0; char FileProvider::ID = 0; char ProviderBase::ID = 0; char VersionProvider::ID = 0; char WorkingDirectoryProvider::ID = 0; char HomeDirectoryProvider::ID = 0; char ProcessInfoProvider::ID = 0; char SymbolFileProvider::ID = 0; const char *CommandProvider::Info::file = "command-interpreter.yaml"; const char *CommandProvider::Info::name = "command-interpreter"; const char *FileProvider::Info::file = "files.yaml"; const char *FileProvider::Info::name = "files"; const char *VersionProvider::Info::file = "version.txt"; const char *VersionProvider::Info::name = "version"; const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; const char *WorkingDirectoryProvider::Info::name = "cwd"; const char *HomeDirectoryProvider::Info::file = "home.txt"; const char *HomeDirectoryProvider::Info::name = "home"; const char *ProcessInfoProvider::Info::file = "process-info.yaml"; const char *ProcessInfoProvider::Info::name = "process-info"; const char *SymbolFileProvider::Info::file = "symbol-files.yaml"; const char *SymbolFileProvider::Info::name = "symbol-files";