1 //===-- Reproducer.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Utility/ReproducerProvider.h" 10 #include "lldb/Utility/ProcessInfo.h" 11 #include "llvm/ADT/ScopeExit.h" 12 #include "llvm/Support/FileSystem.h" 13 #include "llvm/Support/WithColor.h" 14 #include "llvm/Support/raw_ostream.h" 15 16 using namespace lldb_private; 17 using namespace lldb_private::repro; 18 using namespace llvm; 19 using namespace llvm::yaml; 20 21 llvm::Expected<std::unique_ptr<DataRecorder>> 22 DataRecorder::Create(const FileSpec &filename) { 23 std::error_code ec; 24 auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec); 25 if (ec) 26 return llvm::errorCodeToError(ec); 27 return std::move(recorder); 28 } 29 30 llvm::Expected<std::unique_ptr<YamlRecorder>> 31 YamlRecorder::Create(const FileSpec &filename) { 32 std::error_code ec; 33 auto recorder = std::make_unique<YamlRecorder>(std::move(filename), ec); 34 if (ec) 35 return llvm::errorCodeToError(ec); 36 return std::move(recorder); 37 } 38 39 void VersionProvider::Keep() { 40 FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); 41 std::error_code ec; 42 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); 43 if (ec) 44 return; 45 os << m_version << "\n"; 46 } 47 48 FlushingFileCollector::FlushingFileCollector(llvm::StringRef files_path, 49 llvm::StringRef dirs_path, 50 std::error_code &ec) { 51 auto clear = llvm::make_scope_exit([this]() { 52 m_files_os.reset(); 53 m_dirs_os.reset(); 54 }); 55 m_files_os.emplace(files_path, ec, llvm::sys::fs::OF_Append); 56 if (ec) 57 return; 58 m_dirs_os.emplace(dirs_path, ec, llvm::sys::fs::OF_Append); 59 if (ec) 60 return; 61 clear.release(); 62 } 63 64 void FlushingFileCollector::addFileImpl(StringRef file) { 65 if (m_files_os) { 66 *m_files_os << file << '\0'; 67 m_files_os->flush(); 68 } 69 } 70 71 llvm::vfs::directory_iterator 72 FlushingFileCollector::addDirectoryImpl(const Twine &dir, 73 IntrusiveRefCntPtr<vfs::FileSystem> vfs, 74 std::error_code &dir_ec) { 75 if (m_dirs_os) { 76 *m_dirs_os << dir << '\0'; 77 m_dirs_os->flush(); 78 } 79 return vfs->dir_begin(dir, dir_ec); 80 } 81 82 void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) { 83 if (m_collector) 84 m_collector->addFile(dir); 85 } 86 87 void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) { 88 if (m_collector) 89 m_collector->addDirectory(dir); 90 } 91 92 llvm::Expected<std::unique_ptr<ProcessInfoRecorder>> 93 ProcessInfoRecorder::Create(const FileSpec &filename) { 94 std::error_code ec; 95 auto recorder = 96 std::make_unique<ProcessInfoRecorder>(std::move(filename), ec); 97 if (ec) 98 return llvm::errorCodeToError(ec); 99 return std::move(recorder); 100 } 101 102 void ProcessInfoProvider::Keep() { 103 std::vector<std::string> files; 104 for (auto &recorder : m_process_info_recorders) { 105 recorder->Stop(); 106 files.push_back(recorder->GetFilename().GetPath()); 107 } 108 109 FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); 110 std::error_code ec; 111 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); 112 if (ec) 113 return; 114 llvm::yaml::Output yout(os); 115 yout << files; 116 } 117 118 void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } 119 120 ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { 121 std::size_t i = m_process_info_recorders.size() + 1; 122 std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + 123 llvm::Twine(i) + llvm::Twine(".yaml")) 124 .str(); 125 auto recorder_or_error = ProcessInfoRecorder::Create( 126 GetRoot().CopyByAppendingPathComponent(filename)); 127 if (!recorder_or_error) { 128 llvm::consumeError(recorder_or_error.takeError()); 129 return nullptr; 130 } 131 132 m_process_info_recorders.push_back(std::move(*recorder_or_error)); 133 return m_process_info_recorders.back().get(); 134 } 135 136 void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { 137 if (!m_record) 138 return; 139 llvm::yaml::Output yout(m_os); 140 yout << const_cast<ProcessInstanceInfoList &>(process_infos); 141 m_os.flush(); 142 } 143 144 void SymbolFileProvider::AddSymbolFile(const UUID *uuid, 145 const FileSpec &module_file, 146 const FileSpec &symbol_file) { 147 if (!uuid || (!module_file && !symbol_file)) 148 return; 149 m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(), 150 symbol_file.GetPath()); 151 } 152 153 void SymbolFileProvider::Keep() { 154 FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file); 155 std::error_code ec; 156 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); 157 if (ec) 158 return; 159 160 // Remove duplicates. 161 llvm::sort(m_symbol_files.begin(), m_symbol_files.end()); 162 m_symbol_files.erase( 163 std::unique(m_symbol_files.begin(), m_symbol_files.end()), 164 m_symbol_files.end()); 165 166 llvm::yaml::Output yout(os); 167 yout << m_symbol_files; 168 } 169 170 SymbolFileLoader::SymbolFileLoader(Loader *loader) { 171 if (!loader) 172 return; 173 174 FileSpec file = loader->GetFile<SymbolFileProvider::Info>(); 175 if (!file) 176 return; 177 178 auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); 179 if (auto err = error_or_file.getError()) 180 return; 181 182 llvm::yaml::Input yin((*error_or_file)->getBuffer()); 183 yin >> m_symbol_files; 184 } 185 186 std::pair<FileSpec, FileSpec> 187 SymbolFileLoader::GetPaths(const UUID *uuid) const { 188 if (!uuid) 189 return {}; 190 191 auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(), 192 SymbolFileProvider::Entry(uuid->GetAsString())); 193 if (it == m_symbol_files.end()) 194 return {}; 195 return std::make_pair<FileSpec, FileSpec>(FileSpec(it->module_path), 196 FileSpec(it->symbol_path)); 197 } 198 199 void ProviderBase::anchor() {} 200 char CommandProvider::ID = 0; 201 char FileProvider::ID = 0; 202 char ProviderBase::ID = 0; 203 char VersionProvider::ID = 0; 204 char WorkingDirectoryProvider::ID = 0; 205 char HomeDirectoryProvider::ID = 0; 206 char ProcessInfoProvider::ID = 0; 207 char SymbolFileProvider::ID = 0; 208 const char *CommandProvider::Info::file = "command-interpreter.yaml"; 209 const char *CommandProvider::Info::name = "command-interpreter"; 210 const char *FileProvider::Info::file = "files.yaml"; 211 const char *FileProvider::Info::name = "files"; 212 const char *VersionProvider::Info::file = "version.txt"; 213 const char *VersionProvider::Info::name = "version"; 214 const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; 215 const char *WorkingDirectoryProvider::Info::name = "cwd"; 216 const char *HomeDirectoryProvider::Info::file = "home.txt"; 217 const char *HomeDirectoryProvider::Info::name = "home"; 218 const char *ProcessInfoProvider::Info::file = "process-info.yaml"; 219 const char *ProcessInfoProvider::Info::name = "process-info"; 220 const char *SymbolFileProvider::Info::file = "symbol-files.yaml"; 221 const char *SymbolFileProvider::Info::name = "symbol-files"; 222