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