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