1//===---- RuntimeDyldChecker.h - RuntimeDyld tester framework -----*- 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
9#ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
10#define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
11
12#include "llvm/ADT/DenseMap.h"
13#include "llvm/ADT/Optional.h"
14#include "llvm/ExecutionEngine/JITSymbol.h"
15#include "llvm/Support/Endian.h"
16
17#include <cstdint>
18#include <memory>
19#include <string>
20#include <utility>
21
22namespace llvm {
23
24class StringRef;
25class MCDisassembler;
26class MemoryBuffer;
27class MCInstPrinter;
28class RuntimeDyld;
29class RuntimeDyldCheckerImpl;
30class raw_ostream;
31
32/// RuntimeDyld invariant checker for verifying that RuntimeDyld has
33///        correctly applied relocations.
34///
35/// The RuntimeDyldChecker class evaluates expressions against an attached
36/// RuntimeDyld instance to verify that relocations have been applied
37/// correctly.
38///
39/// The expression language supports basic pointer arithmetic and bit-masking,
40/// and has limited disassembler integration for accessing instruction
41/// operands and the next PC (program counter) address for each instruction.
42///
43/// The language syntax is:
44///
45/// check = expr '=' expr
46///
47/// expr = binary_expr
48///      | sliceable_expr
49///
50/// sliceable_expr = '*{' number '}' load_addr_expr [slice]
51///                | '(' expr ')' [slice]
52///                | ident_expr [slice]
53///                | number [slice]
54///
55/// slice = '[' high-bit-index ':' low-bit-index ']'
56///
57/// load_addr_expr = symbol
58///                | '(' symbol '+' number ')'
59///                | '(' symbol '-' number ')'
60///
61/// ident_expr = 'decode_operand' '(' symbol ',' operand-index ')'
62///            | 'next_pc'        '(' symbol ')'
63///            | 'stub_addr' '(' stub-container-name ',' symbol ')'
64///            | 'got_addr' '(' stub-container-name ',' symbol ')'
65///            | symbol
66///
67/// binary_expr = expr '+' expr
68///             | expr '-' expr
69///             | expr '&' expr
70///             | expr '|' expr
71///             | expr '<<' expr
72///             | expr '>>' expr
73///
74class RuntimeDyldChecker {
75public:
76  class MemoryRegionInfo {
77  public:
78    MemoryRegionInfo() = default;
79
80    /// Constructor for symbols/sections with content.
81    MemoryRegionInfo(StringRef Content, JITTargetAddress TargetAddress)
82        : ContentPtr(Content.data()), Size(Content.size()),
83          TargetAddress(TargetAddress) {}
84
85    /// Constructor for zero-fill symbols/sections.
86    MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress)
87        : Size(Size), TargetAddress(TargetAddress) {}
88
89    /// Returns true if this is a zero-fill symbol/section.
90    bool isZeroFill() const {
91      assert(Size && "setContent/setZeroFill must be called first");
92      return !ContentPtr;
93    }
94
95    /// Set the content for this memory region.
96    void setContent(StringRef Content) {
97      assert(!ContentPtr && !Size && "Content/zero-fill already set");
98      ContentPtr = Content.data();
99      Size = Content.size();
100    }
101
102    /// Set a zero-fill length for this memory region.
103    void setZeroFill(uint64_t Size) {
104      assert(!ContentPtr && !this->Size && "Content/zero-fill already set");
105      this->Size = Size;
106    }
107
108    /// Returns the content for this section if there is any.
109    StringRef getContent() const {
110      assert(!isZeroFill() && "Can't get content for a zero-fill section");
111      return StringRef(ContentPtr, static_cast<size_t>(Size));
112    }
113
114    /// Returns the zero-fill length for this section.
115    uint64_t getZeroFillLength() const {
116      assert(isZeroFill() && "Can't get zero-fill length for content section");
117      return Size;
118    }
119
120    /// Set the target address for this region.
121    void setTargetAddress(JITTargetAddress TargetAddress) {
122      assert(!this->TargetAddress && "TargetAddress already set");
123      this->TargetAddress = TargetAddress;
124    }
125
126    /// Return the target address for this region.
127    JITTargetAddress getTargetAddress() const { return TargetAddress; }
128
129  private:
130    const char *ContentPtr = 0;
131    uint64_t Size = 0;
132    JITTargetAddress TargetAddress = 0;
133  };
134
135  using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
136  using GetSymbolInfoFunction =
137      std::function<Expected<MemoryRegionInfo>(StringRef SymbolName)>;
138  using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
139      StringRef FileName, StringRef SectionName)>;
140  using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
141      StringRef StubContainer, StringRef TargetName)>;
142  using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
143      StringRef GOTContainer, StringRef TargetName)>;
144
145  RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,
146                     GetSymbolInfoFunction GetSymbolInfo,
147                     GetSectionInfoFunction GetSectionInfo,
148                     GetStubInfoFunction GetStubInfo,
149                     GetGOTInfoFunction GetGOTInfo,
150                     support::endianness Endianness,
151                     MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
152                     raw_ostream &ErrStream);
153  ~RuntimeDyldChecker();
154
155  /// Check a single expression against the attached RuntimeDyld
156  ///        instance.
157  bool check(StringRef CheckExpr) const;
158
159  /// Scan the given memory buffer for lines beginning with the string
160  ///        in RulePrefix. The remainder of the line is passed to the check
161  ///        method to be evaluated as an expression.
162  bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
163
164  /// Returns the address of the requested section (or an error message
165  ///        in the second element of the pair if the address cannot be found).
166  ///
167  /// if 'LocalAddress' is true, this returns the address of the section
168  /// within the linker's memory. If 'LocalAddress' is false it returns the
169  /// address within the target process (i.e. the load address).
170  std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
171                                                  StringRef SectionName,
172                                                  bool LocalAddress);
173
174  /// If there is a section at the given local address, return its load
175  /// address, otherwise return none.
176  Optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const;
177
178private:
179  std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
180};
181
182} // end namespace llvm
183
184#endif
185