/// \file Runner.cpp /// Implements the logic for inspecting a trace file. Right now this entails /// listing and extracting buffers. // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/Support/Base64.h" #include "revng/ADT/ConstexprString.h" #include "revng/PipelineC/PipelineC.h" #include "revng/PipelineC/Tracing/Common.h" #include "revng/PipelineC/Tracing/Trace.h" static class BufferRegistry { private: llvm::StringMap> Registry; public: BufferRegistry() { // Add autogenerated registerRunner calls to register the // other functions automatically #define FUNCTION(fname) registerFunction<#fname>(fname); #include "revng/PipelineC/Functions.inc" #undef FUNCTION } public: bool has(const llvm::StringRef Name) { return Registry.count(Name) != 0; } std::set &operator[](const llvm::StringRef Name) { return Registry[Name]; } private: template void handleArguments() { using ArgT = std::tuple_element_t; constexpr int LH = LengthHint; if constexpr (anyOf() && LH >= 0) { std::string StrName(Name); Registry[StrName].insert(I); } if constexpr (I + 1 < std::tuple_size_v) handleArguments(); } template void handleFunction(std::function Function) { if constexpr (sizeof...(Args) > 0) handleArguments>(); } template void registerFunction(FunctionT Function) { handleFunction(std::function{ Function }); } } BufferRegistry; inline llvm::Expected> extractBuffer(const revng::tracing::Argument &Arg) { revng_assert(Arg.isScalar()); std::vector Result; llvm::Error Err = llvm::decodeBase64(Arg.getScalar(), Result); if (Err) return std::move(Err); llvm::consumeError(std::move(Err)); return Result; } namespace revng::tracing { std::vector Trace::listBuffers() const { std::vector Result; for (size_t CommandI = 0; CommandI < this->Commands.size(); CommandI++) { auto &Command = this->Commands[CommandI]; if (BufferRegistry.has(Command.Name)) { for (size_t ArgI : BufferRegistry[Command.Name]) { Result.push_back({ Command.Name, CommandI, ArgI }); } } } return Result; } llvm::Expected> Trace::getBuffer(const BufferLocation &Location) const { return getBuffer(Location.CommandNumber, Location.ArgumentNumber); }; llvm::Expected> Trace::getBuffer(size_t CommandNo, size_t ArgNo) const { if (CommandNo > this->Commands.size()) return revng::createError("Command number OOB"); const revng::tracing::Command &Command = this->Commands[CommandNo]; if (!BufferRegistry.has(Command.Name) || !BufferRegistry[Command.Name].contains(ArgNo)) return revng::createError("No buffer information"); return extractBuffer(Command.Arguments[ArgNo]); } } // namespace revng::tracing