ReproducerProvider.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. //===-- Reproducer.h --------------------------------------------*- C++ -*-===//
  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. #ifndef LLDB_UTILITY_REPRODUCER_PROVIDER_H
  9. #define LLDB_UTILITY_REPRODUCER_PROVIDER_H
  10. #include "lldb/Utility/FileSpec.h"
  11. #include "lldb/Utility/ProcessInfo.h"
  12. #include "lldb/Utility/Reproducer.h"
  13. #include "lldb/Utility/UUID.h"
  14. #include "llvm/ADT/StringRef.h"
  15. #include "llvm/Support/Error.h"
  16. #include "llvm/Support/FileCollector.h"
  17. #include "llvm/Support/YAMLTraits.h"
  18. #include <string>
  19. #include <utility>
  20. #include <vector>
  21. namespace lldb_private {
  22. namespace repro {
  23. /// The recorder is a small object handed out by a provider to record data. It
  24. /// is commonly used in combination with a MultiProvider which is meant to
  25. /// record information for multiple instances of the same source of data.
  26. class AbstractRecorder {
  27. protected:
  28. AbstractRecorder(const FileSpec &filename, std::error_code &ec)
  29. : m_filename(filename.GetFilename().GetStringRef()),
  30. m_os(filename.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF),
  31. m_record(true) {}
  32. public:
  33. const FileSpec &GetFilename() { return m_filename; }
  34. void Stop() {
  35. assert(m_record);
  36. m_record = false;
  37. }
  38. private:
  39. FileSpec m_filename;
  40. protected:
  41. llvm::raw_fd_ostream m_os;
  42. bool m_record;
  43. };
  44. /// Recorder that records its data as text to a file.
  45. class DataRecorder : public AbstractRecorder {
  46. public:
  47. DataRecorder(const FileSpec &filename, std::error_code &ec)
  48. : AbstractRecorder(filename, ec) {}
  49. static llvm::Expected<std::unique_ptr<DataRecorder>>
  50. Create(const FileSpec &filename);
  51. template <typename T> void Record(const T &t, bool newline = false) {
  52. if (!m_record)
  53. return;
  54. m_os << t;
  55. if (newline)
  56. m_os << '\n';
  57. m_os.flush();
  58. }
  59. };
  60. /// Recorder that records its data as YAML to a file.
  61. class YamlRecorder : public AbstractRecorder {
  62. public:
  63. YamlRecorder(const FileSpec &filename, std::error_code &ec)
  64. : AbstractRecorder(filename, ec) {}
  65. static llvm::Expected<std::unique_ptr<YamlRecorder>>
  66. Create(const FileSpec &filename);
  67. template <typename T> void Record(const T &t) {
  68. if (!m_record)
  69. return;
  70. llvm::yaml::Output yout(m_os);
  71. // The YAML traits are defined as non-const because they are used for
  72. // serialization and deserialization. The cast is safe because
  73. // serialization doesn't modify the object.
  74. yout << const_cast<T &>(t);
  75. m_os.flush();
  76. }
  77. };
  78. class FlushingFileCollector : public llvm::FileCollectorBase {
  79. public:
  80. FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path,
  81. std::error_code &ec);
  82. protected:
  83. void addFileImpl(llvm::StringRef file) override;
  84. llvm::vfs::directory_iterator
  85. addDirectoryImpl(const llvm::Twine &dir,
  86. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
  87. std::error_code &dir_ec) override;
  88. llvm::Optional<llvm::raw_fd_ostream> m_files_os;
  89. llvm::Optional<llvm::raw_fd_ostream> m_dirs_os;
  90. };
  91. class FileProvider : public Provider<FileProvider> {
  92. public:
  93. struct Info {
  94. static const char *name;
  95. static const char *file;
  96. };
  97. FileProvider(const FileSpec &directory) : Provider(directory) {
  98. std::error_code ec;
  99. m_collector = std::make_shared<FlushingFileCollector>(
  100. directory.CopyByAppendingPathComponent("files.txt").GetPath(),
  101. directory.CopyByAppendingPathComponent("dirs.txt").GetPath(), ec);
  102. if (ec)
  103. m_collector.reset();
  104. }
  105. std::shared_ptr<llvm::FileCollectorBase> GetFileCollector() {
  106. return m_collector;
  107. }
  108. void RecordInterestingDirectory(const llvm::Twine &dir);
  109. void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
  110. static char ID;
  111. private:
  112. std::shared_ptr<FlushingFileCollector> m_collector;
  113. };
  114. /// Provider for the LLDB version number.
  115. ///
  116. /// When the reproducer is kept, it writes the lldb version to a file named
  117. /// version.txt in the reproducer root.
  118. class VersionProvider : public Provider<VersionProvider> {
  119. public:
  120. VersionProvider(const FileSpec &directory) : Provider(directory) {}
  121. struct Info {
  122. static const char *name;
  123. static const char *file;
  124. };
  125. void SetVersion(std::string version) {
  126. assert(m_version.empty());
  127. m_version = std::move(version);
  128. }
  129. void Keep() override;
  130. std::string m_version;
  131. static char ID;
  132. };
  133. /// Abstract provider to storing directory paths.
  134. template <typename T> class DirectoryProvider : public repro::Provider<T> {
  135. public:
  136. DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
  137. void SetDirectory(std::string directory) {
  138. m_directory = std::move(directory);
  139. }
  140. llvm::StringRef GetDirectory() { return m_directory; }
  141. void Keep() override {
  142. FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
  143. std::error_code ec;
  144. llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
  145. if (ec)
  146. return;
  147. os << m_directory << "\n";
  148. }
  149. protected:
  150. std::string m_directory;
  151. };
  152. /// Provider for the current working directory.
  153. ///
  154. /// When the reproducer is kept, it writes lldb's current working directory to
  155. /// a file named cwd.txt in the reproducer root.
  156. class WorkingDirectoryProvider
  157. : public DirectoryProvider<WorkingDirectoryProvider> {
  158. public:
  159. WorkingDirectoryProvider(const FileSpec &directory)
  160. : DirectoryProvider(directory) {
  161. llvm::SmallString<128> cwd;
  162. if (std::error_code EC = llvm::sys::fs::current_path(cwd))
  163. return;
  164. SetDirectory(std::string(cwd));
  165. }
  166. struct Info {
  167. static const char *name;
  168. static const char *file;
  169. };
  170. static char ID;
  171. };
  172. /// Provider for the home directory.
  173. ///
  174. /// When the reproducer is kept, it writes the user's home directory to a file
  175. /// a file named home.txt in the reproducer root.
  176. class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
  177. public:
  178. HomeDirectoryProvider(const FileSpec &directory)
  179. : DirectoryProvider(directory) {
  180. llvm::SmallString<128> home_dir;
  181. llvm::sys::path::home_directory(home_dir);
  182. SetDirectory(std::string(home_dir));
  183. }
  184. struct Info {
  185. static const char *name;
  186. static const char *file;
  187. };
  188. static char ID;
  189. };
  190. /// Provider for mapping UUIDs to symbol and executable files.
  191. class SymbolFileProvider : public Provider<SymbolFileProvider> {
  192. public:
  193. SymbolFileProvider(const FileSpec &directory)
  194. : Provider(directory), m_symbol_files() {}
  195. void AddSymbolFile(const UUID *uuid, const FileSpec &module_path,
  196. const FileSpec &symbol_path);
  197. void Keep() override;
  198. struct Entry {
  199. Entry() = default;
  200. Entry(std::string uuid) : uuid(std::move(uuid)) {}
  201. Entry(std::string uuid, std::string module_path, std::string symbol_path)
  202. : uuid(std::move(uuid)), module_path(std::move(module_path)),
  203. symbol_path(std::move(symbol_path)) {}
  204. bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; }
  205. bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; }
  206. std::string uuid;
  207. std::string module_path;
  208. std::string symbol_path;
  209. };
  210. struct Info {
  211. static const char *name;
  212. static const char *file;
  213. };
  214. static char ID;
  215. private:
  216. std::vector<Entry> m_symbol_files;
  217. };
  218. /// The MultiProvider is a provider that hands out recorder which can be used
  219. /// to capture data for different instances of the same object. The recorders
  220. /// can be passed around or stored as an instance member.
  221. ///
  222. /// The Info::file for the MultiProvider contains an index of files for every
  223. /// recorder. Use the MultiLoader to read the index and get the individual
  224. /// files.
  225. template <typename T, typename V>
  226. class MultiProvider : public repro::Provider<V> {
  227. public:
  228. MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
  229. T *GetNewRecorder() {
  230. std::size_t i = m_recorders.size() + 1;
  231. std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
  232. llvm::Twine(i) + llvm::Twine(".yaml"))
  233. .str();
  234. auto recorder_or_error =
  235. T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
  236. if (!recorder_or_error) {
  237. llvm::consumeError(recorder_or_error.takeError());
  238. return nullptr;
  239. }
  240. m_recorders.push_back(std::move(*recorder_or_error));
  241. return m_recorders.back().get();
  242. }
  243. void Keep() override {
  244. std::vector<std::string> files;
  245. for (auto &recorder : m_recorders) {
  246. recorder->Stop();
  247. files.push_back(recorder->GetFilename().GetPath());
  248. }
  249. FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
  250. std::error_code ec;
  251. llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
  252. if (ec)
  253. return;
  254. llvm::yaml::Output yout(os);
  255. yout << files;
  256. }
  257. void Discard() override { m_recorders.clear(); }
  258. private:
  259. std::vector<std::unique_ptr<T>> m_recorders;
  260. };
  261. class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
  262. public:
  263. struct Info {
  264. static const char *name;
  265. static const char *file;
  266. };
  267. CommandProvider(const FileSpec &directory)
  268. : MultiProvider<DataRecorder, CommandProvider>(directory) {}
  269. static char ID;
  270. };
  271. class ProcessInfoRecorder : public AbstractRecorder {
  272. public:
  273. ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
  274. : AbstractRecorder(filename, ec) {}
  275. static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
  276. Create(const FileSpec &filename);
  277. void Record(const ProcessInstanceInfoList &process_infos);
  278. };
  279. class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
  280. public:
  281. struct Info {
  282. static const char *name;
  283. static const char *file;
  284. };
  285. ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
  286. ProcessInfoRecorder *GetNewProcessInfoRecorder();
  287. void Keep() override;
  288. void Discard() override;
  289. static char ID;
  290. private:
  291. std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
  292. std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
  293. };
  294. /// Loader for data captured with the MultiProvider. It will read the index and
  295. /// return the path to the files in the index.
  296. template <typename T> class MultiLoader {
  297. public:
  298. MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
  299. static std::unique_ptr<MultiLoader> Create(Loader *loader) {
  300. if (!loader)
  301. return {};
  302. FileSpec file = loader->GetFile<typename T::Info>();
  303. if (!file)
  304. return {};
  305. auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
  306. if (auto err = error_or_file.getError())
  307. return {};
  308. std::vector<std::string> files;
  309. llvm::yaml::Input yin((*error_or_file)->getBuffer());
  310. yin >> files;
  311. if (auto err = yin.error())
  312. return {};
  313. for (auto &file : files) {
  314. FileSpec absolute_path =
  315. loader->GetRoot().CopyByAppendingPathComponent(file);
  316. file = absolute_path.GetPath();
  317. }
  318. return std::make_unique<MultiLoader<T>>(std::move(files));
  319. }
  320. llvm::Optional<std::string> GetNextFile() {
  321. if (m_index >= m_files.size())
  322. return {};
  323. return m_files[m_index++];
  324. }
  325. private:
  326. std::vector<std::string> m_files;
  327. unsigned m_index = 0;
  328. };
  329. class SymbolFileLoader {
  330. public:
  331. SymbolFileLoader(Loader *loader);
  332. std::pair<FileSpec, FileSpec> GetPaths(const UUID *uuid) const;
  333. private:
  334. // Sorted list of UUID to path mappings.
  335. std::vector<SymbolFileProvider::Entry> m_symbol_files;
  336. };
  337. /// Helper to read directories written by the DirectoryProvider.
  338. template <typename T>
  339. llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
  340. llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
  341. if (!dir)
  342. return dir.takeError();
  343. return std::string(llvm::StringRef(*dir).rtrim());
  344. }
  345. } // namespace repro
  346. } // namespace lldb_private
  347. LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry)
  348. namespace llvm {
  349. namespace yaml {
  350. template <>
  351. struct MappingTraits<lldb_private::repro::SymbolFileProvider::Entry> {
  352. static void mapping(IO &io,
  353. lldb_private::repro::SymbolFileProvider::Entry &entry) {
  354. io.mapRequired("uuid", entry.uuid);
  355. io.mapRequired("module-path", entry.module_path);
  356. io.mapRequired("symbol-path", entry.symbol_path);
  357. }
  358. };
  359. } // namespace yaml
  360. } // namespace llvm
  361. #endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H