xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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 
23 namespace llvm {
24 
25 class StringRef;
26 class MCDisassembler;
27 class MemoryBuffer;
28 class MCInstPrinter;
29 class RuntimeDyld;
30 class RuntimeDyldCheckerImpl;
31 class raw_ostream;
32 
33 /// Holds target-specific properties for a symbol.
34 using 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 ///
79 class RuntimeDyldChecker {
80 public:
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 
193 private:
194   std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
195 };
196 
197 } // end namespace llvm
198 
199 #endif
200