Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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 | /// | symbol |
||
66 | /// |
||
67 | /// binary_expr = expr '+' expr |
||
68 | /// | expr '-' expr |
||
69 | /// | expr '&' expr |
||
70 | /// | expr '|' expr |
||
71 | /// | expr '<<' expr |
||
72 | /// | expr '>>' expr |
||
73 | /// |
||
74 | class RuntimeDyldChecker { |
||
75 | public: |
||
76 | class MemoryRegionInfo { |
||
77 | public: |
||
78 | MemoryRegionInfo() = default; |
||
79 | |||
80 | /// Constructor for symbols/sections with content. |
||
81 | MemoryRegionInfo(ArrayRef<char> 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(ArrayRef<char> 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 | ArrayRef<char> getContent() const { |
||
110 | assert(!isZeroFill() && "Can't get content for a zero-fill section"); |
||
111 | return {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 = nullptr; |
||
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 | std::optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const; |
||
177 | |||
178 | private: |
||
179 | std::unique_ptr<RuntimeDyldCheckerImpl> Impl; |
||
180 | }; |
||
181 | |||
182 | } // end namespace llvm |
||
183 | |||
184 | #endif |