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/ExecutionEngine/JITSymbol.h"
14 #include "llvm/Support/Endian.h"
15 #include <optional>
16 
17 #include <cstdint>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 
22 namespace llvm {
23 
24 class StringRef;
25 class MCDisassembler;
26 class MemoryBuffer;
27 class MCInstPrinter;
28 class RuntimeDyld;
29 class RuntimeDyldCheckerImpl;
30 class 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 ///            | 'section_addr' '(' stub-container-name ',' symbol ')'
66 ///            | symbol
67 ///
68 /// binary_expr = expr '+' expr
69 ///             | expr '-' expr
70 ///             | expr '&' expr
71 ///             | expr '|' expr
72 ///             | expr '<<' expr
73 ///             | expr '>>' expr
74 ///
75 class RuntimeDyldChecker {
76 public:
77   class MemoryRegionInfo {
78   public:
79     MemoryRegionInfo() = default;
80 
81     /// Constructor for symbols/sections with content.
82     MemoryRegionInfo(ArrayRef<char> Content, JITTargetAddress TargetAddress)
83         : ContentPtr(Content.data()), Size(Content.size()),
84           TargetAddress(TargetAddress) {}
85 
86     /// Constructor for zero-fill symbols/sections.
87     MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress)
88         : Size(Size), TargetAddress(TargetAddress) {}
89 
90     /// Returns true if this is a zero-fill symbol/section.
91     bool isZeroFill() const {
92       assert(Size && "setContent/setZeroFill must be called first");
93       return !ContentPtr;
94     }
95 
96     /// Set the content for this memory region.
97     void setContent(ArrayRef<char> Content) {
98       assert(!ContentPtr && !Size && "Content/zero-fill already set");
99       ContentPtr = Content.data();
100       Size = Content.size();
101     }
102 
103     /// Set a zero-fill length for this memory region.
104     void setZeroFill(uint64_t Size) {
105       assert(!ContentPtr && !this->Size && "Content/zero-fill already set");
106       this->Size = Size;
107     }
108 
109     /// Returns the content for this section if there is any.
110     ArrayRef<char> getContent() const {
111       assert(!isZeroFill() && "Can't get content for a zero-fill section");
112       return {ContentPtr, static_cast<size_t>(Size)};
113     }
114 
115     /// Returns the zero-fill length for this section.
116     uint64_t getZeroFillLength() const {
117       assert(isZeroFill() && "Can't get zero-fill length for content section");
118       return Size;
119     }
120 
121     /// Set the target address for this region.
122     void setTargetAddress(JITTargetAddress TargetAddress) {
123       assert(!this->TargetAddress && "TargetAddress already set");
124       this->TargetAddress = TargetAddress;
125     }
126 
127     /// Return the target address for this region.
128     JITTargetAddress getTargetAddress() const { return TargetAddress; }
129 
130   private:
131     const char *ContentPtr = nullptr;
132     uint64_t Size = 0;
133     JITTargetAddress TargetAddress = 0;
134   };
135 
136   using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
137   using GetSymbolInfoFunction =
138       std::function<Expected<MemoryRegionInfo>(StringRef SymbolName)>;
139   using GetSectionInfoFunction = std::function<Expected<MemoryRegionInfo>(
140       StringRef FileName, StringRef SectionName)>;
141   using GetStubInfoFunction = std::function<Expected<MemoryRegionInfo>(
142       StringRef StubContainer, StringRef TargetName)>;
143   using GetGOTInfoFunction = std::function<Expected<MemoryRegionInfo>(
144       StringRef GOTContainer, StringRef TargetName)>;
145 
146   RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,
147                      GetSymbolInfoFunction GetSymbolInfo,
148                      GetSectionInfoFunction GetSectionInfo,
149                      GetStubInfoFunction GetStubInfo,
150                      GetGOTInfoFunction GetGOTInfo,
151                      support::endianness Endianness,
152                      MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
153                      raw_ostream &ErrStream);
154   ~RuntimeDyldChecker();
155 
156   /// Check a single expression against the attached RuntimeDyld
157   ///        instance.
158   bool check(StringRef CheckExpr) const;
159 
160   /// Scan the given memory buffer for lines beginning with the string
161   ///        in RulePrefix. The remainder of the line is passed to the check
162   ///        method to be evaluated as an expression.
163   bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
164 
165   /// Returns the address of the requested section (or an error message
166   ///        in the second element of the pair if the address cannot be found).
167   ///
168   /// if 'LocalAddress' is true, this returns the address of the section
169   /// within the linker's memory. If 'LocalAddress' is false it returns the
170   /// address within the target process (i.e. the load address).
171   std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
172                                                   StringRef SectionName,
173                                                   bool LocalAddress);
174 
175   /// If there is a section at the given local address, return its load
176   /// address, otherwise return std::nullopt.
177   std::optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const;
178 
179 private:
180   std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
181 };
182 
183 } // end namespace llvm
184 
185 #endif
186