• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ADT/ScopeExit.h"
12 #include "llvm/Support/FileSystem.h"
13 #include "llvm/Support/WithColor.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 llvm::Expected<std::unique_ptr<DataRecorder>>
Create(const FileSpec & filename)22 DataRecorder::Create(const FileSpec &filename) {
23   std::error_code ec;
24   auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec);
25   if (ec)
26     return llvm::errorCodeToError(ec);
27   return std::move(recorder);
28 }
29 
30 llvm::Expected<std::unique_ptr<YamlRecorder>>
Create(const FileSpec & filename)31 YamlRecorder::Create(const FileSpec &filename) {
32   std::error_code ec;
33   auto recorder = std::make_unique<YamlRecorder>(std::move(filename), ec);
34   if (ec)
35     return llvm::errorCodeToError(ec);
36   return std::move(recorder);
37 }
38 
Keep()39 void VersionProvider::Keep() {
40   FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
41   std::error_code ec;
42   llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
43   if (ec)
44     return;
45   os << m_version << "\n";
46 }
47 
FlushingFileCollector(llvm::StringRef files_path,llvm::StringRef dirs_path,std::error_code & ec)48 FlushingFileCollector::FlushingFileCollector(llvm::StringRef files_path,
49                                              llvm::StringRef dirs_path,
50                                              std::error_code &ec) {
51   auto clear = llvm::make_scope_exit([this]() {
52     m_files_os.reset();
53     m_dirs_os.reset();
54   });
55   m_files_os.emplace(files_path, ec, llvm::sys::fs::OF_Append);
56   if (ec)
57     return;
58   m_dirs_os.emplace(dirs_path, ec, llvm::sys::fs::OF_Append);
59   if (ec)
60     return;
61   clear.release();
62 }
63 
addFileImpl(StringRef file)64 void FlushingFileCollector::addFileImpl(StringRef file) {
65   if (m_files_os) {
66     *m_files_os << file << '\0';
67     m_files_os->flush();
68   }
69 }
70 
71 llvm::vfs::directory_iterator
addDirectoryImpl(const Twine & dir,IntrusiveRefCntPtr<vfs::FileSystem> vfs,std::error_code & dir_ec)72 FlushingFileCollector::addDirectoryImpl(const Twine &dir,
73                                         IntrusiveRefCntPtr<vfs::FileSystem> vfs,
74                                         std::error_code &dir_ec) {
75   if (m_dirs_os) {
76     *m_dirs_os << dir << '\0';
77     m_dirs_os->flush();
78   }
79   return vfs->dir_begin(dir, dir_ec);
80 }
81 
RecordInterestingDirectory(const llvm::Twine & dir)82 void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) {
83   if (m_collector)
84     m_collector->addFile(dir);
85 }
86 
RecordInterestingDirectoryRecursive(const llvm::Twine & dir)87 void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) {
88   if (m_collector)
89     m_collector->addDirectory(dir);
90 }
91 
92 llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
Create(const FileSpec & filename)93 ProcessInfoRecorder::Create(const FileSpec &filename) {
94   std::error_code ec;
95   auto recorder =
96       std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
97   if (ec)
98     return llvm::errorCodeToError(ec);
99   return std::move(recorder);
100 }
101 
Keep()102 void ProcessInfoProvider::Keep() {
103   std::vector<std::string> files;
104   for (auto &recorder : m_process_info_recorders) {
105     recorder->Stop();
106     files.push_back(recorder->GetFilename().GetPath());
107   }
108 
109   FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
110   std::error_code ec;
111   llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
112   if (ec)
113     return;
114   llvm::yaml::Output yout(os);
115   yout << files;
116 }
117 
Discard()118 void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
119 
GetNewProcessInfoRecorder()120 ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
121   std::size_t i = m_process_info_recorders.size() + 1;
122   std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
123                           llvm::Twine(i) + llvm::Twine(".yaml"))
124                              .str();
125   auto recorder_or_error = ProcessInfoRecorder::Create(
126       GetRoot().CopyByAppendingPathComponent(filename));
127   if (!recorder_or_error) {
128     llvm::consumeError(recorder_or_error.takeError());
129     return nullptr;
130   }
131 
132   m_process_info_recorders.push_back(std::move(*recorder_or_error));
133   return m_process_info_recorders.back().get();
134 }
135 
Record(const ProcessInstanceInfoList & process_infos)136 void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
137   if (!m_record)
138     return;
139   llvm::yaml::Output yout(m_os);
140   yout << const_cast<ProcessInstanceInfoList &>(process_infos);
141   m_os.flush();
142 }
143 
AddSymbolFile(const UUID * uuid,const FileSpec & module_file,const FileSpec & symbol_file)144 void SymbolFileProvider::AddSymbolFile(const UUID *uuid,
145                                        const FileSpec &module_file,
146                                        const FileSpec &symbol_file) {
147   if (!uuid || (!module_file && !symbol_file))
148     return;
149   m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(),
150                               symbol_file.GetPath());
151 }
152 
Keep()153 void SymbolFileProvider::Keep() {
154   FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file);
155   std::error_code ec;
156   llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
157   if (ec)
158     return;
159 
160   // Remove duplicates.
161   llvm::sort(m_symbol_files.begin(), m_symbol_files.end());
162   m_symbol_files.erase(
163       std::unique(m_symbol_files.begin(), m_symbol_files.end()),
164       m_symbol_files.end());
165 
166   llvm::yaml::Output yout(os);
167   yout << m_symbol_files;
168 }
169 
SymbolFileLoader(Loader * loader)170 SymbolFileLoader::SymbolFileLoader(Loader *loader) {
171   if (!loader)
172     return;
173 
174   FileSpec file = loader->GetFile<SymbolFileProvider::Info>();
175   if (!file)
176     return;
177 
178   auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
179   if (auto err = error_or_file.getError())
180     return;
181 
182   llvm::yaml::Input yin((*error_or_file)->getBuffer());
183   yin >> m_symbol_files;
184 }
185 
186 std::pair<FileSpec, FileSpec>
GetPaths(const UUID * uuid) const187 SymbolFileLoader::GetPaths(const UUID *uuid) const {
188   if (!uuid)
189     return {};
190 
191   auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(),
192                              SymbolFileProvider::Entry(uuid->GetAsString()));
193   if (it == m_symbol_files.end())
194     return {};
195   return std::make_pair<FileSpec, FileSpec>(FileSpec(it->module_path),
196                                             FileSpec(it->symbol_path));
197 }
198 
anchor()199 void ProviderBase::anchor() {}
200 char CommandProvider::ID = 0;
201 char FileProvider::ID = 0;
202 char ProviderBase::ID = 0;
203 char VersionProvider::ID = 0;
204 char WorkingDirectoryProvider::ID = 0;
205 char HomeDirectoryProvider::ID = 0;
206 char ProcessInfoProvider::ID = 0;
207 char SymbolFileProvider::ID = 0;
208 const char *CommandProvider::Info::file = "command-interpreter.yaml";
209 const char *CommandProvider::Info::name = "command-interpreter";
210 const char *FileProvider::Info::file = "files.yaml";
211 const char *FileProvider::Info::name = "files";
212 const char *VersionProvider::Info::file = "version.txt";
213 const char *VersionProvider::Info::name = "version";
214 const char *WorkingDirectoryProvider::Info::file = "cwd.txt";
215 const char *WorkingDirectoryProvider::Info::name = "cwd";
216 const char *HomeDirectoryProvider::Info::file = "home.txt";
217 const char *HomeDirectoryProvider::Info::name = "home";
218 const char *ProcessInfoProvider::Info::file = "process-info.yaml";
219 const char *ProcessInfoProvider::Info::name = "process-info";
220 const char *SymbolFileProvider::Info::file = "symbol-files.yaml";
221 const char *SymbolFileProvider::Info::name = "symbol-files";
222