1 //===-- Reproducer.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Utility/Reproducer.h"
11 #include "lldb/Utility/LLDBAssert.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Threading.h"
15 #include "llvm/Support/raw_ostream.h"
17 using namespace lldb_private;
18 using namespace lldb_private::repro;
20 using namespace llvm::yaml;
22 Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
24 llvm::Error Reproducer::Initialize(ReproducerMode mode,
25 llvm::Optional<FileSpec> root) {
26 lldbassert(!InstanceImpl() && "Already initialized.");
27 InstanceImpl().emplace();
30 case ReproducerMode::Capture: {
32 SmallString<128> repro_dir;
33 auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
35 return make_error<StringError>(
36 "unable to create unique reproducer directory", ec);
37 root.emplace(repro_dir);
39 auto ec = sys::fs::create_directory(root->GetPath());
41 return make_error<StringError>("unable to create reproducer directory",
44 return Instance().SetCapture(root);
46 case ReproducerMode::Replay:
47 return Instance().SetReplay(root);
48 case ReproducerMode::Off:
52 return Error::success();
55 void Reproducer::Terminate() {
56 lldbassert(InstanceImpl() && "Already terminated.");
57 InstanceImpl().reset();
60 Optional<Reproducer> &Reproducer::InstanceImpl() {
61 static Optional<Reproducer> g_reproducer;
65 const Generator *Reproducer::GetGenerator() const {
66 std::lock_guard<std::mutex> guard(m_mutex);
68 return &(*m_generator);
72 const Loader *Reproducer::GetLoader() const {
73 std::lock_guard<std::mutex> guard(m_mutex);
79 Generator *Reproducer::GetGenerator() {
80 std::lock_guard<std::mutex> guard(m_mutex);
82 return &(*m_generator);
86 Loader *Reproducer::GetLoader() {
87 std::lock_guard<std::mutex> guard(m_mutex);
93 llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
94 std::lock_guard<std::mutex> guard(m_mutex);
97 return make_error<StringError>(
98 "cannot generate a reproducer when replay one",
99 inconvertibleErrorCode());
103 return Error::success();
106 m_generator.emplace(*root);
107 return Error::success();
110 llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) {
111 std::lock_guard<std::mutex> guard(m_mutex);
113 if (root && m_generator)
114 return make_error<StringError>(
115 "cannot replay a reproducer when generating one",
116 inconvertibleErrorCode());
120 return Error::success();
123 m_loader.emplace(*root);
124 if (auto e = m_loader->LoadIndex())
127 return Error::success();
130 FileSpec Reproducer::GetReproducerPath() const {
131 if (auto g = GetGenerator())
133 if (auto l = GetLoader())
138 Generator::Generator(const FileSpec &root) : m_root(root), m_done(false) {}
140 Generator::~Generator() {}
142 ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) {
143 std::lock_guard<std::mutex> lock(m_providers_mutex);
144 std::pair<const void *, std::unique_ptr<ProviderBase>> key_value(
145 provider->DynamicClassID(), std::move(provider));
146 auto e = m_providers.insert(std::move(key_value));
147 return e.first->getSecond().get();
150 void Generator::Keep() {
154 for (auto &provider : m_providers)
155 provider.second->Keep();
157 AddProvidersToIndex();
160 void Generator::Discard() {
164 for (auto &provider : m_providers)
165 provider.second->Discard();
167 llvm::sys::fs::remove_directories(m_root.GetPath());
170 const FileSpec &Generator::GetRoot() const { return m_root; }
172 void Generator::AddProvidersToIndex() {
173 FileSpec index = m_root;
174 index.AppendPathComponent("index.yaml");
177 auto strm = llvm::make_unique<raw_fd_ostream>(index.GetPath(), EC,
178 sys::fs::OpenFlags::F_None);
179 yaml::Output yout(*strm);
181 for (auto &provider : m_providers) {
182 auto &provider_info = provider.second->GetInfo();
183 yout << const_cast<ProviderInfo &>(provider_info);
187 Loader::Loader(const FileSpec &root) : m_root(root), m_loaded(false) {}
189 llvm::Error Loader::LoadIndex() {
191 return llvm::Error::success();
193 FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml");
195 auto error_or_file = MemoryBuffer::getFile(index.GetPath());
196 if (auto err = error_or_file.getError())
197 return make_error<StringError>("unable to load reproducer index", err);
199 std::vector<ProviderInfo> provider_info;
200 yaml::Input yin((*error_or_file)->getBuffer());
201 yin >> provider_info;
203 if (auto err = yin.error())
204 return make_error<StringError>("unable to read reproducer index", err);
206 for (auto &info : provider_info)
207 m_provider_info[info.name] = info;
211 return llvm::Error::success();
214 llvm::Optional<ProviderInfo> Loader::GetProviderInfo(StringRef name) {
217 auto it = m_provider_info.find(name);
218 if (it == m_provider_info.end())
224 void ProviderBase::anchor() {}
225 char ProviderBase::ID = 0;