180814287SRaphael Isemann //===-- Reproducer.cpp ----------------------------------------------------===//
29e046f02SJonas Devlieghere //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69e046f02SJonas Devlieghere //
79e046f02SJonas Devlieghere //===----------------------------------------------------------------------===//
89e046f02SJonas Devlieghere 
99e046f02SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
1015eacd74SJonas Devlieghere #include "lldb/Utility/LLDBAssert.h"
11bb894b97SJonas Devlieghere #include "lldb/Utility/ReproducerProvider.h"
12c82beabaSJonas Devlieghere #include "lldb/Utility/Timer.h"
139e046f02SJonas Devlieghere 
149e046f02SJonas Devlieghere #include "llvm/Support/FileSystem.h"
159e046f02SJonas Devlieghere #include "llvm/Support/Threading.h"
169e046f02SJonas Devlieghere #include "llvm/Support/raw_ostream.h"
179e046f02SJonas Devlieghere 
189e046f02SJonas Devlieghere using namespace lldb_private;
199e046f02SJonas Devlieghere using namespace lldb_private::repro;
209e046f02SJonas Devlieghere using namespace llvm;
219e046f02SJonas Devlieghere using namespace llvm::yaml;
229e046f02SJonas Devlieghere 
Instance()2315eacd74SJonas Devlieghere Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
2415eacd74SJonas Devlieghere 
Initialize(ReproducerMode mode,llvm::Optional<FileSpec> root)2515eacd74SJonas Devlieghere llvm::Error Reproducer::Initialize(ReproducerMode mode,
2615eacd74SJonas Devlieghere                                    llvm::Optional<FileSpec> root) {
2715eacd74SJonas Devlieghere   lldbassert(!InstanceImpl() && "Already initialized.");
2815eacd74SJonas Devlieghere   InstanceImpl().emplace();
2915eacd74SJonas Devlieghere 
3015eacd74SJonas Devlieghere   switch (mode) {
3115eacd74SJonas Devlieghere   case ReproducerMode::Capture: {
3215eacd74SJonas Devlieghere     if (!root) {
3315eacd74SJonas Devlieghere       SmallString<128> repro_dir;
3415eacd74SJonas Devlieghere       auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
3515eacd74SJonas Devlieghere       if (ec)
3615eacd74SJonas Devlieghere         return make_error<StringError>(
3715eacd74SJonas Devlieghere             "unable to create unique reproducer directory", ec);
3815eacd74SJonas Devlieghere       root.emplace(repro_dir);
3915eacd74SJonas Devlieghere     } else {
40c2820bf2SJonas Devlieghere       auto ec = sys::fs::create_directory(root->GetPath());
4115eacd74SJonas Devlieghere       if (ec)
4215eacd74SJonas Devlieghere         return make_error<StringError>("unable to create reproducer directory",
4315eacd74SJonas Devlieghere                                        ec);
4415eacd74SJonas Devlieghere     }
4515eacd74SJonas Devlieghere     return Instance().SetCapture(root);
4615eacd74SJonas Devlieghere   } break;
4715eacd74SJonas Devlieghere   case ReproducerMode::Off:
4815eacd74SJonas Devlieghere     break;
4915eacd74SJonas Devlieghere   };
5015eacd74SJonas Devlieghere 
5115eacd74SJonas Devlieghere   return Error::success();
5215eacd74SJonas Devlieghere }
5315eacd74SJonas Devlieghere 
Initialize()5452122069SJonas Devlieghere void Reproducer::Initialize() {
5552122069SJonas Devlieghere   llvm::cantFail(Initialize(repro::ReproducerMode::Off, llvm::None));
5652122069SJonas Devlieghere }
5752122069SJonas Devlieghere 
Initialized()58936c6242SJonas Devlieghere bool Reproducer::Initialized() { return InstanceImpl().operator bool(); }
59936c6242SJonas Devlieghere 
Terminate()6015eacd74SJonas Devlieghere void Reproducer::Terminate() {
6115eacd74SJonas Devlieghere   lldbassert(InstanceImpl() && "Already terminated.");
6215eacd74SJonas Devlieghere   InstanceImpl().reset();
6315eacd74SJonas Devlieghere }
6415eacd74SJonas Devlieghere 
InstanceImpl()6515eacd74SJonas Devlieghere Optional<Reproducer> &Reproducer::InstanceImpl() {
6615eacd74SJonas Devlieghere   static Optional<Reproducer> g_reproducer;
679e046f02SJonas Devlieghere   return g_reproducer;
689e046f02SJonas Devlieghere }
699e046f02SJonas Devlieghere 
GetGenerator() const709e046f02SJonas Devlieghere const Generator *Reproducer::GetGenerator() const {
719e046f02SJonas Devlieghere   std::lock_guard<std::mutex> guard(m_mutex);
7268ed93d2SJonas Devlieghere   if (m_generator)
7368ed93d2SJonas Devlieghere     return &(*m_generator);
749e046f02SJonas Devlieghere   return nullptr;
759e046f02SJonas Devlieghere }
769e046f02SJonas Devlieghere 
GetLoader() const779e046f02SJonas Devlieghere const Loader *Reproducer::GetLoader() const {
789e046f02SJonas Devlieghere   std::lock_guard<std::mutex> guard(m_mutex);
7968ed93d2SJonas Devlieghere   if (m_loader)
8068ed93d2SJonas Devlieghere     return &(*m_loader);
819e046f02SJonas Devlieghere   return nullptr;
829e046f02SJonas Devlieghere }
839e046f02SJonas Devlieghere 
GetGenerator()849e046f02SJonas Devlieghere Generator *Reproducer::GetGenerator() {
859e046f02SJonas Devlieghere   std::lock_guard<std::mutex> guard(m_mutex);
8668ed93d2SJonas Devlieghere   if (m_generator)
8768ed93d2SJonas Devlieghere     return &(*m_generator);
889e046f02SJonas Devlieghere   return nullptr;
899e046f02SJonas Devlieghere }
909e046f02SJonas Devlieghere 
GetLoader()919e046f02SJonas Devlieghere Loader *Reproducer::GetLoader() {
929e046f02SJonas Devlieghere   std::lock_guard<std::mutex> guard(m_mutex);
9368ed93d2SJonas Devlieghere   if (m_loader)
9468ed93d2SJonas Devlieghere     return &(*m_loader);
959e046f02SJonas Devlieghere   return nullptr;
969e046f02SJonas Devlieghere }
979e046f02SJonas Devlieghere 
SetCapture(llvm::Optional<FileSpec> root)9868ed93d2SJonas Devlieghere llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
999e046f02SJonas Devlieghere   std::lock_guard<std::mutex> guard(m_mutex);
1009e046f02SJonas Devlieghere 
10168ed93d2SJonas Devlieghere   if (root && m_loader)
1029e046f02SJonas Devlieghere     return make_error<StringError>(
1039e046f02SJonas Devlieghere         "cannot generate a reproducer when replay one",
1049e046f02SJonas Devlieghere         inconvertibleErrorCode());
1059e046f02SJonas Devlieghere 
10615eacd74SJonas Devlieghere   if (!root) {
10768ed93d2SJonas Devlieghere     m_generator.reset();
10815eacd74SJonas Devlieghere     return Error::success();
10915eacd74SJonas Devlieghere   }
1109e046f02SJonas Devlieghere 
11115eacd74SJonas Devlieghere   m_generator.emplace(*root);
1129e046f02SJonas Devlieghere   return Error::success();
1139e046f02SJonas Devlieghere }
1149e046f02SJonas Devlieghere 
GetReproducerPath() const1159e046f02SJonas Devlieghere FileSpec Reproducer::GetReproducerPath() const {
1169e046f02SJonas Devlieghere   if (auto g = GetGenerator())
11768ed93d2SJonas Devlieghere     return g->GetRoot();
11868ed93d2SJonas Devlieghere   if (auto l = GetLoader())
11968ed93d2SJonas Devlieghere     return l->GetRoot();
1209e046f02SJonas Devlieghere   return {};
1219e046f02SJonas Devlieghere }
1229e046f02SJonas Devlieghere 
MakeAbsolute(const FileSpec & file_spec)1230d5fc822SJonas Devlieghere static FileSpec MakeAbsolute(const FileSpec &file_spec) {
124cdec5979SJonas Devlieghere   SmallString<128> path;
125cdec5979SJonas Devlieghere   file_spec.GetPath(path, false);
126cdec5979SJonas Devlieghere   llvm::sys::fs::make_absolute(path);
127cdec5979SJonas Devlieghere   return FileSpec(path, file_spec.GetPathStyle());
128cdec5979SJonas Devlieghere }
129cdec5979SJonas Devlieghere 
Generator(FileSpec root)1307ba28644SJonas Devlieghere Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) {
13127ef81cdSJonas Devlieghere   GetOrCreate<repro::WorkingDirectoryProvider>();
13273af341bSJonas Devlieghere   GetOrCreate<repro::HomeDirectoryProvider>();
13327ef81cdSJonas Devlieghere }
1349e046f02SJonas Devlieghere 
~Generator()1357ba28644SJonas Devlieghere Generator::~Generator() {
136066e817bSJonas Devlieghere   if (!m_done) {
13773811d32SJonas Devlieghere     if (m_auto_generate) {
138066e817bSJonas Devlieghere       Keep();
13973811d32SJonas Devlieghere     } else {
1407ba28644SJonas Devlieghere       Discard();
1417ba28644SJonas Devlieghere     }
142066e817bSJonas Devlieghere   }
14373811d32SJonas Devlieghere }
1449e046f02SJonas Devlieghere 
Register(std::unique_ptr<ProviderBase> provider)14568ed93d2SJonas Devlieghere ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) {
1469e046f02SJonas Devlieghere   std::lock_guard<std::mutex> lock(m_providers_mutex);
14768ed93d2SJonas Devlieghere   std::pair<const void *, std::unique_ptr<ProviderBase>> key_value(
14868ed93d2SJonas Devlieghere       provider->DynamicClassID(), std::move(provider));
14968ed93d2SJonas Devlieghere   auto e = m_providers.insert(std::move(key_value));
15068ed93d2SJonas Devlieghere   return e.first->getSecond().get();
1519e046f02SJonas Devlieghere }
1529e046f02SJonas Devlieghere 
Keep()1539e046f02SJonas Devlieghere void Generator::Keep() {
154c82beabaSJonas Devlieghere   LLDB_SCOPED_TIMER();
1559e046f02SJonas Devlieghere   assert(!m_done);
1569e046f02SJonas Devlieghere   m_done = true;
1579e046f02SJonas Devlieghere 
1589e046f02SJonas Devlieghere   for (auto &provider : m_providers)
15968ed93d2SJonas Devlieghere     provider.second->Keep();
16068ed93d2SJonas Devlieghere 
16168ed93d2SJonas Devlieghere   AddProvidersToIndex();
1629e046f02SJonas Devlieghere }
1639e046f02SJonas Devlieghere 
Discard()1649e046f02SJonas Devlieghere void Generator::Discard() {
165c82beabaSJonas Devlieghere   LLDB_SCOPED_TIMER();
1669e046f02SJonas Devlieghere   assert(!m_done);
1679e046f02SJonas Devlieghere   m_done = true;
1689e046f02SJonas Devlieghere 
1699e046f02SJonas Devlieghere   for (auto &provider : m_providers)
17068ed93d2SJonas Devlieghere     provider.second->Discard();
1719e046f02SJonas Devlieghere 
17268ed93d2SJonas Devlieghere   llvm::sys::fs::remove_directories(m_root.GetPath());
1739e046f02SJonas Devlieghere }
1749e046f02SJonas Devlieghere 
SetAutoGenerate(bool b)175066e817bSJonas Devlieghere void Generator::SetAutoGenerate(bool b) { m_auto_generate = b; }
176066e817bSJonas Devlieghere 
IsAutoGenerate() const177982a77b6SJonas Devlieghere bool Generator::IsAutoGenerate() const { return m_auto_generate; }
178982a77b6SJonas Devlieghere 
GetRoot() const17968ed93d2SJonas Devlieghere const FileSpec &Generator::GetRoot() const { return m_root; }
1809e046f02SJonas Devlieghere 
AddProvidersToIndex()18168ed93d2SJonas Devlieghere void Generator::AddProvidersToIndex() {
18268ed93d2SJonas Devlieghere   FileSpec index = m_root;
1839e046f02SJonas Devlieghere   index.AppendPathComponent("index.yaml");
1849e046f02SJonas Devlieghere 
1859e046f02SJonas Devlieghere   std::error_code EC;
186a8f3ae7cSJonas Devlieghere   auto strm = std::make_unique<raw_fd_ostream>(index.GetPath(), EC,
187d9b948b6SFangrui Song                                                sys::fs::OpenFlags::OF_None);
1889e046f02SJonas Devlieghere   yaml::Output yout(*strm);
18968ed93d2SJonas Devlieghere 
190e912cc51SJonas Devlieghere   std::vector<std::string> files;
191e912cc51SJonas Devlieghere   files.reserve(m_providers.size());
19268ed93d2SJonas Devlieghere   for (auto &provider : m_providers) {
193e912cc51SJonas Devlieghere     files.emplace_back(provider.second->GetFile());
1949e046f02SJonas Devlieghere   }
195e912cc51SJonas Devlieghere 
196e912cc51SJonas Devlieghere   yout << files;
19768ed93d2SJonas Devlieghere }
1989e046f02SJonas Devlieghere 
Loader(FileSpec root,bool passive)199950a8aa1SJonas Devlieghere Loader::Loader(FileSpec root, bool passive)
200*fa126069SJonas Devlieghere     : m_root(MakeAbsolute(std::move(root))), m_loaded(false) {}
2019e046f02SJonas Devlieghere 
LoadIndex()20268ed93d2SJonas Devlieghere llvm::Error Loader::LoadIndex() {
2039e046f02SJonas Devlieghere   if (m_loaded)
2049e046f02SJonas Devlieghere     return llvm::Error::success();
2059e046f02SJonas Devlieghere 
20668ed93d2SJonas Devlieghere   FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml");
2079e046f02SJonas Devlieghere 
2089e046f02SJonas Devlieghere   auto error_or_file = MemoryBuffer::getFile(index.GetPath());
2099e046f02SJonas Devlieghere   if (auto err = error_or_file.getError())
21015eacd74SJonas Devlieghere     return make_error<StringError>("unable to load reproducer index", err);
2119e046f02SJonas Devlieghere 
2129e046f02SJonas Devlieghere   yaml::Input yin((*error_or_file)->getBuffer());
213e912cc51SJonas Devlieghere   yin >> m_files;
2149e046f02SJonas Devlieghere   if (auto err = yin.error())
21515eacd74SJonas Devlieghere     return make_error<StringError>("unable to read reproducer index", err);
2169e046f02SJonas Devlieghere 
217e912cc51SJonas Devlieghere   // Sort files to speed up search.
218e912cc51SJonas Devlieghere   llvm::sort(m_files);
2199e046f02SJonas Devlieghere 
220e912cc51SJonas Devlieghere   // Remember that we've loaded the index.
2219e046f02SJonas Devlieghere   m_loaded = true;
2229e046f02SJonas Devlieghere 
2239e046f02SJonas Devlieghere   return llvm::Error::success();
2249e046f02SJonas Devlieghere }
2259e046f02SJonas Devlieghere 
HasFile(StringRef file)226e912cc51SJonas Devlieghere bool Loader::HasFile(StringRef file) {
2279e046f02SJonas Devlieghere   assert(m_loaded);
228e912cc51SJonas Devlieghere   auto it = std::lower_bound(m_files.begin(), m_files.end(), file.str());
229e912cc51SJonas Devlieghere   return (it != m_files.end()) && (*it == file);
2309e046f02SJonas Devlieghere }
231