]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Utility/Reproducer.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Utility / Reproducer.cpp
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 #include "lldb/Utility/LLDBAssert.h"
12
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Threading.h"
15 #include "llvm/Support/raw_ostream.h"
16
17 using namespace lldb_private;
18 using namespace lldb_private::repro;
19 using namespace llvm;
20 using namespace llvm::yaml;
21
22 Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
23
24 llvm::Error Reproducer::Initialize(ReproducerMode mode,
25                                    llvm::Optional<FileSpec> root) {
26   lldbassert(!InstanceImpl() && "Already initialized.");
27   InstanceImpl().emplace();
28
29   switch (mode) {
30   case ReproducerMode::Capture: {
31     if (!root) {
32       SmallString<128> repro_dir;
33       auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
34       if (ec)
35         return make_error<StringError>(
36             "unable to create unique reproducer directory", ec);
37       root.emplace(repro_dir);
38     } else {
39       auto ec = sys::fs::create_directory(root->GetPath());
40       if (ec)
41         return make_error<StringError>("unable to create reproducer directory",
42                                        ec);
43     }
44     return Instance().SetCapture(root);
45   } break;
46   case ReproducerMode::Replay:
47     return Instance().SetReplay(root);
48   case ReproducerMode::Off:
49     break;
50   };
51
52   return Error::success();
53 }
54
55 void Reproducer::Terminate() {
56   lldbassert(InstanceImpl() && "Already terminated.");
57   InstanceImpl().reset();
58 }
59
60 Optional<Reproducer> &Reproducer::InstanceImpl() {
61   static Optional<Reproducer> g_reproducer;
62   return g_reproducer;
63 }
64
65 const Generator *Reproducer::GetGenerator() const {
66   std::lock_guard<std::mutex> guard(m_mutex);
67   if (m_generator)
68     return &(*m_generator);
69   return nullptr;
70 }
71
72 const Loader *Reproducer::GetLoader() const {
73   std::lock_guard<std::mutex> guard(m_mutex);
74   if (m_loader)
75     return &(*m_loader);
76   return nullptr;
77 }
78
79 Generator *Reproducer::GetGenerator() {
80   std::lock_guard<std::mutex> guard(m_mutex);
81   if (m_generator)
82     return &(*m_generator);
83   return nullptr;
84 }
85
86 Loader *Reproducer::GetLoader() {
87   std::lock_guard<std::mutex> guard(m_mutex);
88   if (m_loader)
89     return &(*m_loader);
90   return nullptr;
91 }
92
93 llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
94   std::lock_guard<std::mutex> guard(m_mutex);
95
96   if (root && m_loader)
97     return make_error<StringError>(
98         "cannot generate a reproducer when replay one",
99         inconvertibleErrorCode());
100
101   if (!root) {
102     m_generator.reset();
103     return Error::success();
104   }
105
106   m_generator.emplace(*root);
107   return Error::success();
108 }
109
110 llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) {
111   std::lock_guard<std::mutex> guard(m_mutex);
112
113   if (root && m_generator)
114     return make_error<StringError>(
115         "cannot replay a reproducer when generating one",
116         inconvertibleErrorCode());
117
118   if (!root) {
119     m_loader.reset();
120     return Error::success();
121   }
122
123   m_loader.emplace(*root);
124   if (auto e = m_loader->LoadIndex())
125     return e;
126
127   return Error::success();
128 }
129
130 FileSpec Reproducer::GetReproducerPath() const {
131   if (auto g = GetGenerator())
132     return g->GetRoot();
133   if (auto l = GetLoader())
134     return l->GetRoot();
135   return {};
136 }
137
138 Generator::Generator(const FileSpec &root) : m_root(root), m_done(false) {}
139
140 Generator::~Generator() {}
141
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();
148 }
149
150 void Generator::Keep() {
151   assert(!m_done);
152   m_done = true;
153
154   for (auto &provider : m_providers)
155     provider.second->Keep();
156
157   AddProvidersToIndex();
158 }
159
160 void Generator::Discard() {
161   assert(!m_done);
162   m_done = true;
163
164   for (auto &provider : m_providers)
165     provider.second->Discard();
166
167   llvm::sys::fs::remove_directories(m_root.GetPath());
168 }
169
170 const FileSpec &Generator::GetRoot() const { return m_root; }
171
172 void Generator::AddProvidersToIndex() {
173   FileSpec index = m_root;
174   index.AppendPathComponent("index.yaml");
175
176   std::error_code EC;
177   auto strm = llvm::make_unique<raw_fd_ostream>(index.GetPath(), EC,
178                                                 sys::fs::OpenFlags::F_None);
179   yaml::Output yout(*strm);
180
181   for (auto &provider : m_providers) {
182     auto &provider_info = provider.second->GetInfo();
183     yout << const_cast<ProviderInfo &>(provider_info);
184   }
185 }
186
187 Loader::Loader(const FileSpec &root) : m_root(root), m_loaded(false) {}
188
189 llvm::Error Loader::LoadIndex() {
190   if (m_loaded)
191     return llvm::Error::success();
192
193   FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml");
194
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);
198
199   std::vector<ProviderInfo> provider_info;
200   yaml::Input yin((*error_or_file)->getBuffer());
201   yin >> provider_info;
202
203   if (auto err = yin.error())
204     return make_error<StringError>("unable to read reproducer index", err);
205
206   for (auto &info : provider_info)
207     m_provider_info[info.name] = info;
208
209   m_loaded = true;
210
211   return llvm::Error::success();
212 }
213
214 llvm::Optional<ProviderInfo> Loader::GetProviderInfo(StringRef name) {
215   assert(m_loaded);
216
217   auto it = m_provider_info.find(name);
218   if (it == m_provider_info.end())
219     return llvm::None;
220
221   return it->second;
222 }
223
224 void ProviderBase::anchor() {}
225 char ProviderBase::ID = 0;