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