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