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