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

source code of llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h