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 void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) { 49 if (m_collector) 50 m_collector->addFile(dir); 51 } 52 53 void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) { 54 if (m_collector) 55 m_collector->addDirectory(dir); 56 } 57 58 void FileProvider::Keep() { 59 if (m_collector) { 60 FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); 61 m_collector->writeMapping(file.GetPath()); 62 } 63 } 64 65 llvm::Expected<std::unique_ptr<ProcessInfoRecorder>> 66 ProcessInfoRecorder::Create(const FileSpec &filename) { 67 std::error_code ec; 68 auto recorder = 69 std::make_unique<ProcessInfoRecorder>(std::move(filename), ec); 70 if (ec) 71 return llvm::errorCodeToError(ec); 72 return std::move(recorder); 73 } 74 75 void ProcessInfoProvider::Keep() { 76 std::vector<std::string> files; 77 for (auto &recorder : m_process_info_recorders) { 78 recorder->Stop(); 79 files.push_back(recorder->GetFilename().GetPath()); 80 } 81 82 FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); 83 std::error_code ec; 84 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); 85 if (ec) 86 return; 87 llvm::yaml::Output yout(os); 88 yout << files; 89 } 90 91 void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } 92 93 ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { 94 std::size_t i = m_process_info_recorders.size() + 1; 95 std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + 96 llvm::Twine(i) + llvm::Twine(".yaml")) 97 .str(); 98 auto recorder_or_error = ProcessInfoRecorder::Create( 99 GetRoot().CopyByAppendingPathComponent(filename)); 100 if (!recorder_or_error) { 101 llvm::consumeError(recorder_or_error.takeError()); 102 return nullptr; 103 } 104 105 m_process_info_recorders.push_back(std::move(*recorder_or_error)); 106 return m_process_info_recorders.back().get(); 107 } 108 109 void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { 110 if (!m_record) 111 return; 112 llvm::yaml::Output yout(m_os); 113 yout << const_cast<ProcessInstanceInfoList &>(process_infos); 114 m_os.flush(); 115 } 116 117 void SymbolFileProvider::AddSymbolFile(const UUID *uuid, 118 const FileSpec &module_file, 119 const FileSpec &symbol_file) { 120 if (!uuid || (!module_file && !symbol_file)) 121 return; 122 m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(), 123 symbol_file.GetPath()); 124 } 125 126 void SymbolFileProvider::Keep() { 127 FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file); 128 std::error_code ec; 129 llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); 130 if (ec) 131 return; 132 133 // Remove duplicates. 134 llvm::sort(m_symbol_files); 135 m_symbol_files.erase( 136 std::unique(m_symbol_files.begin(), m_symbol_files.end()), 137 m_symbol_files.end()); 138 139 llvm::yaml::Output yout(os); 140 yout << m_symbol_files; 141 } 142 143 SymbolFileLoader::SymbolFileLoader(Loader *loader) { 144 if (!loader) 145 return; 146 147 FileSpec file = loader->GetFile<SymbolFileProvider::Info>(); 148 if (!file) 149 return; 150 151 auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); 152 if (auto err = error_or_file.getError()) 153 return; 154 155 llvm::yaml::Input yin((*error_or_file)->getBuffer()); 156 yin >> m_symbol_files; 157 } 158 159 std::pair<FileSpec, FileSpec> 160 SymbolFileLoader::GetPaths(const UUID *uuid) const { 161 if (!uuid) 162 return {}; 163 164 auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(), 165 SymbolFileProvider::Entry(uuid->GetAsString())); 166 if (it == m_symbol_files.end()) 167 return {}; 168 return std::make_pair<FileSpec, FileSpec>(FileSpec(it->module_path), 169 FileSpec(it->symbol_path)); 170 } 171 172 void ProviderBase::anchor() {} 173 char CommandProvider::ID = 0; 174 char FileProvider::ID = 0; 175 char ProviderBase::ID = 0; 176 char VersionProvider::ID = 0; 177 char WorkingDirectoryProvider::ID = 0; 178 char HomeDirectoryProvider::ID = 0; 179 char ProcessInfoProvider::ID = 0; 180 char SymbolFileProvider::ID = 0; 181 const char *CommandProvider::Info::file = "command-interpreter.yaml"; 182 const char *CommandProvider::Info::name = "command-interpreter"; 183 const char *FileProvider::Info::file = "files.yaml"; 184 const char *FileProvider::Info::name = "files"; 185 const char *VersionProvider::Info::file = "version.txt"; 186 const char *VersionProvider::Info::name = "version"; 187 const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; 188 const char *WorkingDirectoryProvider::Info::name = "cwd"; 189 const char *HomeDirectoryProvider::Info::file = "home.txt"; 190 const char *HomeDirectoryProvider::Info::name = "home"; 191 const char *ProcessInfoProvider::Info::file = "process-info.yaml"; 192 const char *ProcessInfoProvider::Info::name = "process-info"; 193 const char *SymbolFileProvider::Info::file = "symbol-files.yaml"; 194 const char *SymbolFileProvider::Info::name = "symbol-files"; 195