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