1 //===-- Reproducer.cpp ------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Utility/Reproducer.h" 11 12 #include "llvm/Support/FileSystem.h" 13 #include "llvm/Support/Threading.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 Reproducer &Reproducer::Instance() { 22 static Reproducer g_reproducer; 23 return g_reproducer; 24 } 25 26 const Generator *Reproducer::GetGenerator() const { 27 std::lock_guard<std::mutex> guard(m_mutex); 28 if (m_generator) 29 return &(*m_generator); 30 return nullptr; 31 } 32 33 const Loader *Reproducer::GetLoader() const { 34 std::lock_guard<std::mutex> guard(m_mutex); 35 if (m_loader) 36 return &(*m_loader); 37 return nullptr; 38 } 39 40 Generator *Reproducer::GetGenerator() { 41 std::lock_guard<std::mutex> guard(m_mutex); 42 if (m_generator) 43 return &(*m_generator); 44 return nullptr; 45 } 46 47 Loader *Reproducer::GetLoader() { 48 std::lock_guard<std::mutex> guard(m_mutex); 49 if (m_loader) 50 return &(*m_loader); 51 return nullptr; 52 } 53 54 llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) { 55 std::lock_guard<std::mutex> guard(m_mutex); 56 57 if (root && m_loader) 58 return make_error<StringError>( 59 "cannot generate a reproducer when replay one", 60 inconvertibleErrorCode()); 61 62 if (root) 63 m_generator.emplace(*root); 64 else 65 m_generator.reset(); 66 67 return Error::success(); 68 } 69 70 llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) { 71 std::lock_guard<std::mutex> guard(m_mutex); 72 73 if (root && m_generator) 74 return make_error<StringError>( 75 "cannot replay a reproducer when generating one", 76 inconvertibleErrorCode()); 77 78 if (root) { 79 m_loader.emplace(*root); 80 if (auto e = m_loader->LoadIndex()) 81 return e; 82 } else { 83 m_loader.reset(); 84 } 85 86 return Error::success(); 87 } 88 89 FileSpec Reproducer::GetReproducerPath() const { 90 if (auto g = GetGenerator()) 91 return g->GetRoot(); 92 if (auto l = GetLoader()) 93 return l->GetRoot(); 94 return {}; 95 } 96 97 Generator::Generator(const FileSpec &root) : m_root(root), m_done(false) {} 98 99 Generator::~Generator() {} 100 101 ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) { 102 std::lock_guard<std::mutex> lock(m_providers_mutex); 103 std::pair<const void *, std::unique_ptr<ProviderBase>> key_value( 104 provider->DynamicClassID(), std::move(provider)); 105 auto e = m_providers.insert(std::move(key_value)); 106 return e.first->getSecond().get(); 107 } 108 109 void Generator::Keep() { 110 assert(!m_done); 111 m_done = true; 112 113 for (auto &provider : m_providers) 114 provider.second->Keep(); 115 116 AddProvidersToIndex(); 117 } 118 119 void Generator::Discard() { 120 assert(!m_done); 121 m_done = true; 122 123 for (auto &provider : m_providers) 124 provider.second->Discard(); 125 126 llvm::sys::fs::remove_directories(m_root.GetPath()); 127 } 128 129 const FileSpec &Generator::GetRoot() const { return m_root; } 130 131 void Generator::AddProvidersToIndex() { 132 FileSpec index = m_root; 133 index.AppendPathComponent("index.yaml"); 134 135 std::error_code EC; 136 auto strm = llvm::make_unique<raw_fd_ostream>(index.GetPath(), EC, 137 sys::fs::OpenFlags::F_None); 138 yaml::Output yout(*strm); 139 140 for (auto &provider : m_providers) { 141 auto &provider_info = provider.second->GetInfo(); 142 yout << const_cast<ProviderInfo &>(provider_info); 143 } 144 } 145 146 Loader::Loader(const FileSpec &root) : m_root(root), m_loaded(false) {} 147 148 llvm::Error Loader::LoadIndex() { 149 if (m_loaded) 150 return llvm::Error::success(); 151 152 FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml"); 153 154 auto error_or_file = MemoryBuffer::getFile(index.GetPath()); 155 if (auto err = error_or_file.getError()) 156 return errorCodeToError(err); 157 158 std::vector<ProviderInfo> provider_info; 159 yaml::Input yin((*error_or_file)->getBuffer()); 160 yin >> provider_info; 161 162 if (auto err = yin.error()) 163 return errorCodeToError(err); 164 165 for (auto &info : provider_info) 166 m_provider_info[info.name] = info; 167 168 m_loaded = true; 169 170 return llvm::Error::success(); 171 } 172 173 llvm::Optional<ProviderInfo> Loader::GetProviderInfo(StringRef name) { 174 assert(m_loaded); 175 176 auto it = m_provider_info.find(name); 177 if (it == m_provider_info.end()) 178 return llvm::None; 179 180 return it->second; 181 } 182 183 void ProviderBase::anchor() {} 184 char ProviderBase::ID = 0; 185