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