//===---- RuntimeDyldChecker.h - RuntimeDyld tester framework -----*- 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 LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
 
#define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
 
 
 
#include "llvm/ADT/DenseMap.h"
 
#include "llvm/ExecutionEngine/JITSymbol.h"
 
#include "llvm/Support/Endian.h"
 
#include <optional>
 
 
 
#include <cstdint>
 
#include <memory>
 
#include <string>
 
#include <utility>
 
 
 
namespace llvm {
 
 
 
class StringRef;
 
class MCDisassembler;
 
class MemoryBuffer;
 
class MCInstPrinter;
 
class RuntimeDyld;
 
class RuntimeDyldCheckerImpl;
 
class raw_ostream;
 
 
 
/// RuntimeDyld invariant checker for verifying that RuntimeDyld has
 
///        correctly applied relocations.
 
///
 
/// The RuntimeDyldChecker class evaluates expressions against an attached
 
/// RuntimeDyld instance to verify that relocations have been applied
 
/// correctly.
 
///
 
/// The expression language supports basic pointer arithmetic and bit-masking,
 
/// and has limited disassembler integration for accessing instruction
 
/// operands and the next PC (program counter) address for each instruction.
 
///
 
/// The language syntax is:
 
///
 
/// check = expr '=' expr
 
///
 
/// expr = binary_expr
 
///      | sliceable_expr
 
///
 
/// sliceable_expr = '*{' number '}' load_addr_expr [slice]
 
///                | '(' expr ')' [slice]
 
///                | ident_expr [slice]
 
///                | number [slice]
 
///
 
/// slice = '[' high-bit-index ':' low-bit-index ']'
 
///
 
/// load_addr_expr = symbol
 
///                | '(' symbol '+' number ')'
 
///                | '(' symbol '-' number ')'
 
///
 
/// ident_expr = 'decode_operand' '(' symbol ',' operand-index ')'
 
///            | 'next_pc'        '(' symbol ')'
 
///            | 'stub_addr' '(' stub-container-name ',' symbol ')'
 
///            | 'got_addr' '(' stub-container-name ',' symbol ')'
 
///            | symbol
 
///
 
/// binary_expr = expr '+' expr
 
///             | expr '-' expr
 
///             | expr '&' expr
 
///             | expr '|' expr
 
///             | expr '<<' expr
 
///             | expr '>>' expr
 
///
 
class RuntimeDyldChecker {
 
public:
 
  class MemoryRegionInfo {
 
  public:
 
    MemoryRegionInfo() = default;
 
 
 
    /// Constructor for symbols/sections with content.
 
    MemoryRegionInfo(ArrayRef<char> Content, JITTargetAddress TargetAddress)
 
        : ContentPtr(Content.data()), Size(Content.size()),
 
          TargetAddress(TargetAddress) {}
 
 
 
    /// Constructor for zero-fill symbols/sections.
 
    MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress)
 
        : Size(Size), TargetAddress(TargetAddress) {}
 
 
 
    /// Returns true if this is a zero-fill symbol/section.
 
    bool isZeroFill() const {
 
      assert(Size && "setContent/setZeroFill must be called first");
 
      return !ContentPtr;
 
    }
 
 
 
    /// Set the content for this memory region.
 
    void setContent(ArrayRef<char> Content) {
 
      assert(!ContentPtr && !Size && "Content/zero-fill already set");
 
      ContentPtr = Content.data();
 
      Size = Content.size();
 
    }
 
 
 
    /// Set a zero-fill length for this memory region.
 
    void setZeroFill(uint64_t Size) {
 
      assert(!ContentPtr && !this->Size && "Content/zero-fill already set");
 
      this->Size = Size;
 
    }
 
 
 
    /// Returns the content for this section if there is any.
 
    ArrayRef<char> getContent() const {
 
      assert(!isZeroFill() && "Can't get content for a zero-fill section");
 
      return {ContentPtr, static_cast<size_t>(Size)};
 
    }
 
 
 
    /// Returns the zero-fill length for this section.
 
    uint64_t getZeroFillLength() const {
 
      assert(isZeroFill() && "Can't get zero-fill length for content section");
 
      return Size;
 
    }
 
 
 
    /// Set the target address for this region.
 
    void setTargetAddress(JITTargetAddress TargetAddress) {
 
      assert(!this->TargetAddress && "TargetAddress already set");
 
      this->TargetAddress = TargetAddress;
 
    }
 
 
 
    /// Return the target address for this region.
 
    JITTargetAddress getTargetAddress() const { return TargetAddress; }
 
 
 
  private:
 
    const char *ContentPtr = nullptr;
 
    uint64_t Size = 0;
 
    JITTargetAddress TargetAddress = 0;
 
  };
 
 
 
  using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
 
  using GetSymbolInfoFunction =
 
      std::function<Expected<MemoryRegionInfo>(StringRef SymbolName)>;
 
  using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
 
      StringRef FileName, StringRef SectionName)>;
 
  using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
 
      StringRef StubContainer, StringRef TargetName)>;
 
  using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
 
      StringRef GOTContainer, StringRef TargetName)>;
 
 
 
  RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,
 
                     GetSymbolInfoFunction GetSymbolInfo,
 
                     GetSectionInfoFunction GetSectionInfo,
 
                     GetStubInfoFunction GetStubInfo,
 
                     GetGOTInfoFunction GetGOTInfo,
 
                     support::endianness Endianness,
 
                     MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
 
                     raw_ostream &ErrStream);
 
  ~RuntimeDyldChecker();
 
 
 
  /// Check a single expression against the attached RuntimeDyld
 
  ///        instance.
 
  bool check(StringRef CheckExpr) const;
 
 
 
  /// Scan the given memory buffer for lines beginning with the string
 
  ///        in RulePrefix. The remainder of the line is passed to the check
 
  ///        method to be evaluated as an expression.
 
  bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
 
 
 
  /// Returns the address of the requested section (or an error message
 
  ///        in the second element of the pair if the address cannot be found).
 
  ///
 
  /// if 'LocalAddress' is true, this returns the address of the section
 
  /// within the linker's memory. If 'LocalAddress' is false it returns the
 
  /// address within the target process (i.e. the load address).
 
  std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
 
                                                  StringRef SectionName,
 
                                                  bool LocalAddress);
 
 
 
  /// If there is a section at the given local address, return its load
 
  /// address, otherwise return none.
 
  std::optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const;
 
 
 
private:
 
  std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
 
};
 
 
 
} // end namespace llvm
 
 
 
#endif