| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- //===-- Reproducer.h --------------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLDB_UTILITY_REPRODUCER_PROVIDER_H
- #define LLDB_UTILITY_REPRODUCER_PROVIDER_H
- #include "lldb/Utility/FileSpec.h"
- #include "lldb/Utility/ProcessInfo.h"
- #include "lldb/Utility/Reproducer.h"
- #include "lldb/Utility/UUID.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/FileCollector.h"
- #include "llvm/Support/YAMLTraits.h"
- #include <string>
- #include <utility>
- #include <vector>
- namespace lldb_private {
- namespace repro {
- /// The recorder is a small object handed out by a provider to record data. It
- /// is commonly used in combination with a MultiProvider which is meant to
- /// record information for multiple instances of the same source of data.
- class AbstractRecorder {
- protected:
- AbstractRecorder(const FileSpec &filename, std::error_code &ec)
- : m_filename(filename.GetFilename().GetStringRef()),
- m_os(filename.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF),
- m_record(true) {}
- public:
- const FileSpec &GetFilename() { return m_filename; }
- void Stop() {
- assert(m_record);
- m_record = false;
- }
- private:
- FileSpec m_filename;
- protected:
- llvm::raw_fd_ostream m_os;
- bool m_record;
- };
- /// Recorder that records its data as text to a file.
- class DataRecorder : public AbstractRecorder {
- public:
- DataRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
- static llvm::Expected<std::unique_ptr<DataRecorder>>
- Create(const FileSpec &filename);
- template <typename T> void Record(const T &t, bool newline = false) {
- if (!m_record)
- return;
- m_os << t;
- if (newline)
- m_os << '\n';
- m_os.flush();
- }
- };
- /// Recorder that records its data as YAML to a file.
- class YamlRecorder : public AbstractRecorder {
- public:
- YamlRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
- static llvm::Expected<std::unique_ptr<YamlRecorder>>
- Create(const FileSpec &filename);
- template <typename T> void Record(const T &t) {
- if (!m_record)
- return;
- llvm::yaml::Output yout(m_os);
- // The YAML traits are defined as non-const because they are used for
- // serialization and deserialization. The cast is safe because
- // serialization doesn't modify the object.
- yout << const_cast<T &>(t);
- m_os.flush();
- }
- };
- class FlushingFileCollector : public llvm::FileCollectorBase {
- public:
- FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path,
- std::error_code &ec);
- protected:
- void addFileImpl(llvm::StringRef file) override;
- llvm::vfs::directory_iterator
- addDirectoryImpl(const llvm::Twine &dir,
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
- std::error_code &dir_ec) override;
- llvm::Optional<llvm::raw_fd_ostream> m_files_os;
- llvm::Optional<llvm::raw_fd_ostream> m_dirs_os;
- };
- class FileProvider : public Provider<FileProvider> {
- public:
- struct Info {
- static const char *name;
- static const char *file;
- };
- FileProvider(const FileSpec &directory) : Provider(directory) {
- std::error_code ec;
- m_collector = std::make_shared<FlushingFileCollector>(
- directory.CopyByAppendingPathComponent("files.txt").GetPath(),
- directory.CopyByAppendingPathComponent("dirs.txt").GetPath(), ec);
- if (ec)
- m_collector.reset();
- }
- std::shared_ptr<llvm::FileCollectorBase> GetFileCollector() {
- return m_collector;
- }
- void RecordInterestingDirectory(const llvm::Twine &dir);
- void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
- static char ID;
- private:
- std::shared_ptr<FlushingFileCollector> m_collector;
- };
- /// Provider for the LLDB version number.
- ///
- /// When the reproducer is kept, it writes the lldb version to a file named
- /// version.txt in the reproducer root.
- class VersionProvider : public Provider<VersionProvider> {
- public:
- VersionProvider(const FileSpec &directory) : Provider(directory) {}
- struct Info {
- static const char *name;
- static const char *file;
- };
- void SetVersion(std::string version) {
- assert(m_version.empty());
- m_version = std::move(version);
- }
- void Keep() override;
- std::string m_version;
- static char ID;
- };
- /// Abstract provider to storing directory paths.
- template <typename T> class DirectoryProvider : public repro::Provider<T> {
- public:
- DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
- void SetDirectory(std::string directory) {
- m_directory = std::move(directory);
- }
- llvm::StringRef GetDirectory() { return m_directory; }
- void Keep() override {
- FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- os << m_directory << "\n";
- }
- protected:
- std::string m_directory;
- };
- /// Provider for the current working directory.
- ///
- /// When the reproducer is kept, it writes lldb's current working directory to
- /// a file named cwd.txt in the reproducer root.
- class WorkingDirectoryProvider
- : public DirectoryProvider<WorkingDirectoryProvider> {
- public:
- WorkingDirectoryProvider(const FileSpec &directory)
- : DirectoryProvider(directory) {
- llvm::SmallString<128> cwd;
- if (std::error_code EC = llvm::sys::fs::current_path(cwd))
- return;
- SetDirectory(std::string(cwd));
- }
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
- };
- /// Provider for the home directory.
- ///
- /// When the reproducer is kept, it writes the user's home directory to a file
- /// a file named home.txt in the reproducer root.
- class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
- public:
- HomeDirectoryProvider(const FileSpec &directory)
- : DirectoryProvider(directory) {
- llvm::SmallString<128> home_dir;
- llvm::sys::path::home_directory(home_dir);
- SetDirectory(std::string(home_dir));
- }
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
- };
- /// Provider for mapping UUIDs to symbol and executable files.
- class SymbolFileProvider : public Provider<SymbolFileProvider> {
- public:
- SymbolFileProvider(const FileSpec &directory)
- : Provider(directory), m_symbol_files() {}
- void AddSymbolFile(const UUID *uuid, const FileSpec &module_path,
- const FileSpec &symbol_path);
- void Keep() override;
- struct Entry {
- Entry() = default;
- Entry(std::string uuid) : uuid(std::move(uuid)) {}
- Entry(std::string uuid, std::string module_path, std::string symbol_path)
- : uuid(std::move(uuid)), module_path(std::move(module_path)),
- symbol_path(std::move(symbol_path)) {}
- bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; }
- bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; }
- std::string uuid;
- std::string module_path;
- std::string symbol_path;
- };
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
- private:
- std::vector<Entry> m_symbol_files;
- };
- /// The MultiProvider is a provider that hands out recorder which can be used
- /// to capture data for different instances of the same object. The recorders
- /// can be passed around or stored as an instance member.
- ///
- /// The Info::file for the MultiProvider contains an index of files for every
- /// recorder. Use the MultiLoader to read the index and get the individual
- /// files.
- template <typename T, typename V>
- class MultiProvider : public repro::Provider<V> {
- public:
- MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
- T *GetNewRecorder() {
- std::size_t i = m_recorders.size() + 1;
- std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
- llvm::Twine(i) + llvm::Twine(".yaml"))
- .str();
- auto recorder_or_error =
- T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
- if (!recorder_or_error) {
- llvm::consumeError(recorder_or_error.takeError());
- return nullptr;
- }
- m_recorders.push_back(std::move(*recorder_or_error));
- return m_recorders.back().get();
- }
- void Keep() override {
- std::vector<std::string> files;
- for (auto &recorder : m_recorders) {
- recorder->Stop();
- files.push_back(recorder->GetFilename().GetPath());
- }
- FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- llvm::yaml::Output yout(os);
- yout << files;
- }
- void Discard() override { m_recorders.clear(); }
- private:
- std::vector<std::unique_ptr<T>> m_recorders;
- };
- class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
- public:
- struct Info {
- static const char *name;
- static const char *file;
- };
- CommandProvider(const FileSpec &directory)
- : MultiProvider<DataRecorder, CommandProvider>(directory) {}
- static char ID;
- };
- class ProcessInfoRecorder : public AbstractRecorder {
- public:
- ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
- static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
- Create(const FileSpec &filename);
- void Record(const ProcessInstanceInfoList &process_infos);
- };
- class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
- public:
- struct Info {
- static const char *name;
- static const char *file;
- };
- ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
- ProcessInfoRecorder *GetNewProcessInfoRecorder();
- void Keep() override;
- void Discard() override;
- static char ID;
- private:
- std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
- std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
- };
- /// Loader for data captured with the MultiProvider. It will read the index and
- /// return the path to the files in the index.
- template <typename T> class MultiLoader {
- public:
- MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
- static std::unique_ptr<MultiLoader> Create(Loader *loader) {
- if (!loader)
- return {};
- FileSpec file = loader->GetFile<typename T::Info>();
- if (!file)
- return {};
- auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
- if (auto err = error_or_file.getError())
- return {};
- std::vector<std::string> files;
- llvm::yaml::Input yin((*error_or_file)->getBuffer());
- yin >> files;
- if (auto err = yin.error())
- return {};
- for (auto &file : files) {
- FileSpec absolute_path =
- loader->GetRoot().CopyByAppendingPathComponent(file);
- file = absolute_path.GetPath();
- }
- return std::make_unique<MultiLoader<T>>(std::move(files));
- }
- llvm::Optional<std::string> GetNextFile() {
- if (m_index >= m_files.size())
- return {};
- return m_files[m_index++];
- }
- private:
- std::vector<std::string> m_files;
- unsigned m_index = 0;
- };
- class SymbolFileLoader {
- public:
- SymbolFileLoader(Loader *loader);
- std::pair<FileSpec, FileSpec> GetPaths(const UUID *uuid) const;
- private:
- // Sorted list of UUID to path mappings.
- std::vector<SymbolFileProvider::Entry> m_symbol_files;
- };
- /// Helper to read directories written by the DirectoryProvider.
- template <typename T>
- llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
- llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
- if (!dir)
- return dir.takeError();
- return std::string(llvm::StringRef(*dir).rtrim());
- }
- } // namespace repro
- } // namespace lldb_private
- LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry)
- namespace llvm {
- namespace yaml {
- template <>
- struct MappingTraits<lldb_private::repro::SymbolFileProvider::Entry> {
- static void mapping(IO &io,
- lldb_private::repro::SymbolFileProvider::Entry &entry) {
- io.mapRequired("uuid", entry.uuid);
- io.mapRequired("module-path", entry.module_path);
- io.mapRequired("symbol-path", entry.symbol_path);
- }
- };
- } // namespace yaml
- } // namespace llvm
- #endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H
|