Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 1 | //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Benjamin Kramer | 82de7d3 | 2016-05-27 14:27:24 +0000 | [diff] [blame] | 10 | #include "llvm/ExecutionEngine/RuntimeDyldChecker.h" |
Chandler Carruth | d990388 | 2015-01-14 11:23:27 +0000 | [diff] [blame] | 11 | #include "RuntimeDyldCheckerImpl.h" |
| 12 | #include "RuntimeDyldImpl.h" |
Benjamin Kramer | 82de7d3 | 2016-05-27 14:27:24 +0000 | [diff] [blame] | 13 | #include "llvm/ADT/STLExtras.h" |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 14 | #include "llvm/MC/MCContext.h" |
Benjamin Kramer | f57c197 | 2016-01-26 16:44:37 +0000 | [diff] [blame] | 15 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 16 | #include "llvm/MC/MCInst.h" |
Lang Hames | 480763f | 2014-07-29 20:40:37 +0000 | [diff] [blame] | 17 | #include "llvm/Support/Path.h" |
Lang Hames | 3b7ffd6 | 2014-06-27 20:37:39 +0000 | [diff] [blame] | 18 | #include <cctype> |
Lang Hames | adde5ba | 2018-09-25 19:48:46 +0000 | [diff] [blame] | 19 | #include <future> |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 20 | #include <memory> |
Benjamin Kramer | 82de7d3 | 2016-05-27 14:27:24 +0000 | [diff] [blame] | 21 | #include <utility> |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 22 | |
| 23 | #define DEBUG_TYPE "rtdyld" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | namespace llvm { |
| 28 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 29 | // Helper class that implements the language evaluated by RuntimeDyldChecker. |
| 30 | class RuntimeDyldCheckerExprEval { |
| 31 | public: |
| 32 | RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, |
| 33 | raw_ostream &ErrStream) |
| 34 | : Checker(Checker) {} |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 35 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 36 | bool evaluate(StringRef Expr) const { |
| 37 | // Expect equality expression of the form 'LHS = RHS'. |
| 38 | Expr = Expr.trim(); |
| 39 | size_t EQIdx = Expr.find('='); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 40 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 41 | ParseContext OutsideLoad(false); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 42 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 43 | // Evaluate LHS. |
| 44 | StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); |
| 45 | StringRef RemainingExpr; |
| 46 | EvalResult LHSResult; |
| 47 | std::tie(LHSResult, RemainingExpr) = |
| 48 | evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad); |
| 49 | if (LHSResult.hasError()) |
| 50 | return handleError(Expr, LHSResult); |
| 51 | if (RemainingExpr != "") |
| 52 | return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, "")); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 53 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 54 | // Evaluate RHS. |
| 55 | StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim(); |
| 56 | EvalResult RHSResult; |
| 57 | std::tie(RHSResult, RemainingExpr) = |
| 58 | evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad); |
| 59 | if (RHSResult.hasError()) |
| 60 | return handleError(Expr, RHSResult); |
| 61 | if (RemainingExpr != "") |
| 62 | return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 63 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 64 | if (LHSResult.getValue() != RHSResult.getValue()) { |
| 65 | Checker.ErrStream << "Expression '" << Expr << "' is false: " |
Lang Hames | b2eb492 | 2014-07-29 21:38:20 +0000 | [diff] [blame] | 66 | << format("0x%" PRIx64, LHSResult.getValue()) |
| 67 | << " != " << format("0x%" PRIx64, RHSResult.getValue()) |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 68 | << "\n"; |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 69 | return false; |
| 70 | } |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 71 | return true; |
| 72 | } |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 73 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 74 | private: |
| 75 | // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In |
| 76 | // particular, it needs to know whether a symbol is being evaluated in the |
| 77 | // context of a load, in which case we want the linker's local address for |
| 78 | // the symbol, or outside of a load, in which case we want the symbol's |
| 79 | // address in the remote target. |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 80 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 81 | struct ParseContext { |
| 82 | bool IsInsideLoad; |
| 83 | ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {} |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 84 | }; |
| 85 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 86 | const RuntimeDyldCheckerImpl &Checker; |
| 87 | |
| 88 | enum class BinOpToken : unsigned { |
| 89 | Invalid, |
| 90 | Add, |
| 91 | Sub, |
| 92 | BitwiseAnd, |
| 93 | BitwiseOr, |
| 94 | ShiftLeft, |
| 95 | ShiftRight |
| 96 | }; |
| 97 | |
| 98 | class EvalResult { |
| 99 | public: |
| 100 | EvalResult() : Value(0), ErrorMsg("") {} |
| 101 | EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {} |
Benjamin Kramer | 82de7d3 | 2016-05-27 14:27:24 +0000 | [diff] [blame] | 102 | EvalResult(std::string ErrorMsg) |
| 103 | : Value(0), ErrorMsg(std::move(ErrorMsg)) {} |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 104 | uint64_t getValue() const { return Value; } |
| 105 | bool hasError() const { return ErrorMsg != ""; } |
| 106 | const std::string &getErrorMsg() const { return ErrorMsg; } |
| 107 | |
| 108 | private: |
| 109 | uint64_t Value; |
| 110 | std::string ErrorMsg; |
| 111 | }; |
| 112 | |
| 113 | StringRef getTokenForError(StringRef Expr) const { |
| 114 | if (Expr.empty()) |
| 115 | return ""; |
| 116 | |
| 117 | StringRef Token, Remaining; |
| 118 | if (isalpha(Expr[0])) |
| 119 | std::tie(Token, Remaining) = parseSymbol(Expr); |
| 120 | else if (isdigit(Expr[0])) |
| 121 | std::tie(Token, Remaining) = parseNumberString(Expr); |
| 122 | else { |
| 123 | unsigned TokLen = 1; |
| 124 | if (Expr.startswith("<<") || Expr.startswith(">>")) |
| 125 | TokLen = 2; |
| 126 | Token = Expr.substr(0, TokLen); |
| 127 | } |
| 128 | return Token; |
| 129 | } |
| 130 | |
| 131 | EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr, |
| 132 | StringRef ErrText) const { |
| 133 | std::string ErrorMsg("Encountered unexpected token '"); |
| 134 | ErrorMsg += getTokenForError(TokenStart); |
| 135 | if (SubExpr != "") { |
| 136 | ErrorMsg += "' while parsing subexpression '"; |
| 137 | ErrorMsg += SubExpr; |
| 138 | } |
| 139 | ErrorMsg += "'"; |
| 140 | if (ErrText != "") { |
| 141 | ErrorMsg += " "; |
| 142 | ErrorMsg += ErrText; |
| 143 | } |
| 144 | return EvalResult(std::move(ErrorMsg)); |
| 145 | } |
| 146 | |
| 147 | bool handleError(StringRef Expr, const EvalResult &R) const { |
| 148 | assert(R.hasError() && "Not an error result."); |
| 149 | Checker.ErrStream << "Error evaluating expression '" << Expr |
| 150 | << "': " << R.getErrorMsg() << "\n"; |
| 151 | return false; |
| 152 | } |
| 153 | |
| 154 | std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const { |
| 155 | if (Expr.empty()) |
| 156 | return std::make_pair(BinOpToken::Invalid, ""); |
| 157 | |
| 158 | // Handle the two 2-character tokens. |
| 159 | if (Expr.startswith("<<")) |
| 160 | return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim()); |
| 161 | if (Expr.startswith(">>")) |
| 162 | return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim()); |
| 163 | |
| 164 | // Handle one-character tokens. |
| 165 | BinOpToken Op; |
| 166 | switch (Expr[0]) { |
| 167 | default: |
| 168 | return std::make_pair(BinOpToken::Invalid, Expr); |
| 169 | case '+': |
| 170 | Op = BinOpToken::Add; |
| 171 | break; |
| 172 | case '-': |
| 173 | Op = BinOpToken::Sub; |
| 174 | break; |
| 175 | case '&': |
| 176 | Op = BinOpToken::BitwiseAnd; |
| 177 | break; |
| 178 | case '|': |
| 179 | Op = BinOpToken::BitwiseOr; |
| 180 | break; |
| 181 | } |
| 182 | |
| 183 | return std::make_pair(Op, Expr.substr(1).ltrim()); |
| 184 | } |
| 185 | |
| 186 | EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult, |
| 187 | const EvalResult &RHSResult) const { |
| 188 | switch (Op) { |
| 189 | default: |
| 190 | llvm_unreachable("Tried to evaluate unrecognized operation."); |
| 191 | case BinOpToken::Add: |
| 192 | return EvalResult(LHSResult.getValue() + RHSResult.getValue()); |
| 193 | case BinOpToken::Sub: |
| 194 | return EvalResult(LHSResult.getValue() - RHSResult.getValue()); |
| 195 | case BinOpToken::BitwiseAnd: |
| 196 | return EvalResult(LHSResult.getValue() & RHSResult.getValue()); |
| 197 | case BinOpToken::BitwiseOr: |
| 198 | return EvalResult(LHSResult.getValue() | RHSResult.getValue()); |
| 199 | case BinOpToken::ShiftLeft: |
| 200 | return EvalResult(LHSResult.getValue() << RHSResult.getValue()); |
| 201 | case BinOpToken::ShiftRight: |
| 202 | return EvalResult(LHSResult.getValue() >> RHSResult.getValue()); |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | // Parse a symbol and return a (string, string) pair representing the symbol |
| 207 | // name and expression remaining to be parsed. |
| 208 | std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const { |
| 209 | size_t FirstNonSymbol = Expr.find_first_not_of("0123456789" |
| 210 | "abcdefghijklmnopqrstuvwxyz" |
| 211 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
Lang Hames | eb99df8 | 2014-08-19 20:04:45 +0000 | [diff] [blame] | 212 | ":_.$"); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 213 | return std::make_pair(Expr.substr(0, FirstNonSymbol), |
| 214 | Expr.substr(FirstNonSymbol).ltrim()); |
| 215 | } |
| 216 | |
| 217 | // Evaluate a call to decode_operand. Decode the instruction operand at the |
| 218 | // given symbol and get the value of the requested operand. |
| 219 | // Returns an error if the instruction cannot be decoded, or the requested |
| 220 | // operand is not an immediate. |
Simon Pilgrim | f2fbf43 | 2016-11-20 13:47:59 +0000 | [diff] [blame] | 221 | // On success, returns a pair containing the value of the operand, plus |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 222 | // the expression remaining to be evaluated. |
| 223 | std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const { |
| 224 | if (!Expr.startswith("(")) |
| 225 | return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); |
| 226 | StringRef RemainingExpr = Expr.substr(1).ltrim(); |
| 227 | StringRef Symbol; |
| 228 | std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); |
| 229 | |
| 230 | if (!Checker.isSymbolValid(Symbol)) |
| 231 | return std::make_pair( |
| 232 | EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), |
| 233 | ""); |
| 234 | |
| 235 | if (!RemainingExpr.startswith(",")) |
| 236 | return std::make_pair( |
| 237 | unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), ""); |
| 238 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 239 | |
| 240 | EvalResult OpIdxExpr; |
| 241 | std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); |
| 242 | if (OpIdxExpr.hasError()) |
| 243 | return std::make_pair(OpIdxExpr, ""); |
| 244 | |
| 245 | if (!RemainingExpr.startswith(")")) |
| 246 | return std::make_pair( |
| 247 | unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); |
| 248 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 249 | |
| 250 | MCInst Inst; |
| 251 | uint64_t Size; |
| 252 | if (!decodeInst(Symbol, Inst, Size)) |
| 253 | return std::make_pair( |
| 254 | EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), |
| 255 | ""); |
| 256 | |
| 257 | unsigned OpIdx = OpIdxExpr.getValue(); |
| 258 | if (OpIdx >= Inst.getNumOperands()) { |
| 259 | std::string ErrMsg; |
| 260 | raw_string_ostream ErrMsgStream(ErrMsg); |
| 261 | ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx) |
| 262 | << "' for instruction '" << Symbol |
| 263 | << "'. Instruction has only " |
| 264 | << format("%i", Inst.getNumOperands()) |
| 265 | << " operands.\nInstruction is:\n "; |
Sean Silva | 0e1fe18 | 2015-02-05 00:58:51 +0000 | [diff] [blame] | 266 | Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 267 | return std::make_pair(EvalResult(ErrMsgStream.str()), ""); |
| 268 | } |
| 269 | |
| 270 | const MCOperand &Op = Inst.getOperand(OpIdx); |
| 271 | if (!Op.isImm()) { |
| 272 | std::string ErrMsg; |
| 273 | raw_string_ostream ErrMsgStream(ErrMsg); |
| 274 | ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '" |
| 275 | << Symbol << "' is not an immediate.\nInstruction is:\n "; |
Sean Silva | 0e1fe18 | 2015-02-05 00:58:51 +0000 | [diff] [blame] | 276 | Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 277 | |
| 278 | return std::make_pair(EvalResult(ErrMsgStream.str()), ""); |
| 279 | } |
| 280 | |
| 281 | return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); |
| 282 | } |
| 283 | |
| 284 | // Evaluate a call to next_pc. |
| 285 | // Decode the instruction at the given symbol and return the following program |
| 286 | // counter. |
| 287 | // Returns an error if the instruction cannot be decoded. |
| 288 | // On success, returns a pair containing the next PC, plus of the |
| 289 | // expression remaining to be evaluated. |
| 290 | std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr, |
| 291 | ParseContext PCtx) const { |
| 292 | if (!Expr.startswith("(")) |
| 293 | return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); |
| 294 | StringRef RemainingExpr = Expr.substr(1).ltrim(); |
| 295 | StringRef Symbol; |
| 296 | std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); |
| 297 | |
| 298 | if (!Checker.isSymbolValid(Symbol)) |
| 299 | return std::make_pair( |
| 300 | EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), |
| 301 | ""); |
| 302 | |
| 303 | if (!RemainingExpr.startswith(")")) |
| 304 | return std::make_pair( |
| 305 | unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); |
| 306 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 307 | |
| 308 | MCInst Inst; |
| 309 | uint64_t InstSize; |
| 310 | if (!decodeInst(Symbol, Inst, InstSize)) |
| 311 | return std::make_pair( |
| 312 | EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), |
| 313 | ""); |
| 314 | |
| 315 | uint64_t SymbolAddr = PCtx.IsInsideLoad |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 316 | ? Checker.getSymbolLocalAddr(Symbol) |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 317 | : Checker.getSymbolRemoteAddr(Symbol); |
| 318 | uint64_t NextPC = SymbolAddr + InstSize; |
| 319 | |
| 320 | return std::make_pair(EvalResult(NextPC), RemainingExpr); |
| 321 | } |
| 322 | |
| 323 | // Evaluate a call to stub_addr. |
| 324 | // Look up and return the address of the stub for the given |
| 325 | // (<file name>, <section name>, <symbol name>) tuple. |
| 326 | // On success, returns a pair containing the stub address, plus the expression |
| 327 | // remaining to be evaluated. |
| 328 | std::pair<EvalResult, StringRef> evalStubAddr(StringRef Expr, |
| 329 | ParseContext PCtx) const { |
| 330 | if (!Expr.startswith("(")) |
| 331 | return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); |
| 332 | StringRef RemainingExpr = Expr.substr(1).ltrim(); |
| 333 | |
| 334 | // Handle file-name specially, as it may contain characters that aren't |
| 335 | // legal for symbols. |
| 336 | StringRef FileName; |
| 337 | size_t ComaIdx = RemainingExpr.find(','); |
| 338 | FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); |
| 339 | RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); |
| 340 | |
| 341 | if (!RemainingExpr.startswith(",")) |
| 342 | return std::make_pair( |
| 343 | unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); |
| 344 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 345 | |
| 346 | StringRef SectionName; |
| 347 | std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); |
| 348 | |
| 349 | if (!RemainingExpr.startswith(",")) |
| 350 | return std::make_pair( |
| 351 | unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); |
| 352 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 353 | |
| 354 | StringRef Symbol; |
| 355 | std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); |
| 356 | |
| 357 | if (!RemainingExpr.startswith(")")) |
| 358 | return std::make_pair( |
| 359 | unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); |
| 360 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 361 | |
| 362 | uint64_t StubAddr; |
| 363 | std::string ErrorMsg = ""; |
| 364 | std::tie(StubAddr, ErrorMsg) = Checker.getStubAddrFor( |
| 365 | FileName, SectionName, Symbol, PCtx.IsInsideLoad); |
| 366 | |
| 367 | if (ErrorMsg != "") |
| 368 | return std::make_pair(EvalResult(ErrorMsg), ""); |
| 369 | |
| 370 | return std::make_pair(EvalResult(StubAddr), RemainingExpr); |
| 371 | } |
| 372 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 373 | std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr, |
| 374 | ParseContext PCtx) const { |
| 375 | if (!Expr.startswith("(")) |
| 376 | return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); |
| 377 | StringRef RemainingExpr = Expr.substr(1).ltrim(); |
| 378 | |
| 379 | // Handle file-name specially, as it may contain characters that aren't |
| 380 | // legal for symbols. |
| 381 | StringRef FileName; |
| 382 | size_t ComaIdx = RemainingExpr.find(','); |
| 383 | FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); |
| 384 | RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); |
| 385 | |
| 386 | if (!RemainingExpr.startswith(",")) |
| 387 | return std::make_pair( |
| 388 | unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); |
| 389 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 390 | |
| 391 | StringRef SectionName; |
| 392 | std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); |
| 393 | |
| 394 | if (!RemainingExpr.startswith(")")) |
| 395 | return std::make_pair( |
| 396 | unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); |
| 397 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 398 | |
| 399 | uint64_t StubAddr; |
| 400 | std::string ErrorMsg = ""; |
| 401 | std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr( |
| 402 | FileName, SectionName, PCtx.IsInsideLoad); |
| 403 | |
| 404 | if (ErrorMsg != "") |
| 405 | return std::make_pair(EvalResult(ErrorMsg), ""); |
| 406 | |
| 407 | return std::make_pair(EvalResult(StubAddr), RemainingExpr); |
| 408 | } |
| 409 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 410 | // Evaluate an identiefer expr, which may be a symbol, or a call to |
| 411 | // one of the builtin functions: get_insn_opcode or get_insn_length. |
| 412 | // Return the result, plus the expression remaining to be parsed. |
| 413 | std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr, |
| 414 | ParseContext PCtx) const { |
| 415 | StringRef Symbol; |
| 416 | StringRef RemainingExpr; |
| 417 | std::tie(Symbol, RemainingExpr) = parseSymbol(Expr); |
| 418 | |
| 419 | // Check for builtin function calls. |
| 420 | if (Symbol == "decode_operand") |
| 421 | return evalDecodeOperand(RemainingExpr); |
| 422 | else if (Symbol == "next_pc") |
| 423 | return evalNextPC(RemainingExpr, PCtx); |
| 424 | else if (Symbol == "stub_addr") |
| 425 | return evalStubAddr(RemainingExpr, PCtx); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 426 | else if (Symbol == "section_addr") |
| 427 | return evalSectionAddr(RemainingExpr, PCtx); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 428 | |
| 429 | if (!Checker.isSymbolValid(Symbol)) { |
| 430 | std::string ErrMsg("No known address for symbol '"); |
| 431 | ErrMsg += Symbol; |
| 432 | ErrMsg += "'"; |
| 433 | if (Symbol.startswith("L")) |
| 434 | ErrMsg += " (this appears to be an assembler local label - " |
| 435 | " perhaps drop the 'L'?)"; |
| 436 | |
| 437 | return std::make_pair(EvalResult(ErrMsg), ""); |
| 438 | } |
| 439 | |
| 440 | // The value for the symbol depends on the context we're evaluating in: |
| 441 | // Inside a load this is the address in the linker's memory, outside a |
| 442 | // load it's the address in the target processes memory. |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 443 | uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol) |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 444 | : Checker.getSymbolRemoteAddr(Symbol); |
| 445 | |
| 446 | // Looks like a plain symbol reference. |
| 447 | return std::make_pair(EvalResult(Value), RemainingExpr); |
| 448 | } |
| 449 | |
| 450 | // Parse a number (hexadecimal or decimal) and return a (string, string) |
| 451 | // pair representing the number and the expression remaining to be parsed. |
| 452 | std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const { |
| 453 | size_t FirstNonDigit = StringRef::npos; |
| 454 | if (Expr.startswith("0x")) { |
| 455 | FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2); |
| 456 | if (FirstNonDigit == StringRef::npos) |
| 457 | FirstNonDigit = Expr.size(); |
| 458 | } else { |
| 459 | FirstNonDigit = Expr.find_first_not_of("0123456789"); |
| 460 | if (FirstNonDigit == StringRef::npos) |
| 461 | FirstNonDigit = Expr.size(); |
| 462 | } |
| 463 | return std::make_pair(Expr.substr(0, FirstNonDigit), |
| 464 | Expr.substr(FirstNonDigit)); |
| 465 | } |
| 466 | |
Simon Pilgrim | f2fbf43 | 2016-11-20 13:47:59 +0000 | [diff] [blame] | 467 | // Evaluate a constant numeric expression (hexadecimal or decimal) and |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 468 | // return a pair containing the result, and the expression remaining to be |
| 469 | // evaluated. |
| 470 | std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const { |
| 471 | StringRef ValueStr; |
| 472 | StringRef RemainingExpr; |
| 473 | std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr); |
| 474 | |
| 475 | if (ValueStr.empty() || !isdigit(ValueStr[0])) |
| 476 | return std::make_pair( |
| 477 | unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), ""); |
| 478 | uint64_t Value; |
| 479 | ValueStr.getAsInteger(0, Value); |
| 480 | return std::make_pair(EvalResult(Value), RemainingExpr); |
| 481 | } |
| 482 | |
| 483 | // Evaluate an expression of the form "(<expr>)" and return a pair |
| 484 | // containing the result of evaluating <expr>, plus the expression |
| 485 | // remaining to be parsed. |
| 486 | std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr, |
| 487 | ParseContext PCtx) const { |
| 488 | assert(Expr.startswith("(") && "Not a parenthesized expression"); |
| 489 | EvalResult SubExprResult; |
| 490 | StringRef RemainingExpr; |
| 491 | std::tie(SubExprResult, RemainingExpr) = |
| 492 | evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx); |
| 493 | if (SubExprResult.hasError()) |
| 494 | return std::make_pair(SubExprResult, ""); |
| 495 | if (!RemainingExpr.startswith(")")) |
| 496 | return std::make_pair( |
| 497 | unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); |
| 498 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 499 | return std::make_pair(SubExprResult, RemainingExpr); |
| 500 | } |
| 501 | |
| 502 | // Evaluate an expression in one of the following forms: |
| 503 | // *{<number>}<expr> |
| 504 | // Return a pair containing the result, plus the expression remaining to be |
| 505 | // parsed. |
| 506 | std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const { |
| 507 | assert(Expr.startswith("*") && "Not a load expression"); |
| 508 | StringRef RemainingExpr = Expr.substr(1).ltrim(); |
| 509 | |
| 510 | // Parse read size. |
| 511 | if (!RemainingExpr.startswith("{")) |
| 512 | return std::make_pair(EvalResult("Expected '{' following '*'."), ""); |
| 513 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 514 | EvalResult ReadSizeExpr; |
| 515 | std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); |
| 516 | if (ReadSizeExpr.hasError()) |
| 517 | return std::make_pair(ReadSizeExpr, RemainingExpr); |
| 518 | uint64_t ReadSize = ReadSizeExpr.getValue(); |
| 519 | if (ReadSize < 1 || ReadSize > 8) |
| 520 | return std::make_pair(EvalResult("Invalid size for dereference."), ""); |
| 521 | if (!RemainingExpr.startswith("}")) |
| 522 | return std::make_pair(EvalResult("Missing '}' for dereference."), ""); |
| 523 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 524 | |
| 525 | // Evaluate the expression representing the load address. |
| 526 | ParseContext LoadCtx(true); |
| 527 | EvalResult LoadAddrExprResult; |
| 528 | std::tie(LoadAddrExprResult, RemainingExpr) = |
| 529 | evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx); |
| 530 | |
| 531 | if (LoadAddrExprResult.hasError()) |
| 532 | return std::make_pair(LoadAddrExprResult, ""); |
| 533 | |
| 534 | uint64_t LoadAddr = LoadAddrExprResult.getValue(); |
| 535 | |
| 536 | return std::make_pair( |
| 537 | EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), |
| 538 | RemainingExpr); |
| 539 | } |
| 540 | |
| 541 | // Evaluate a "simple" expression. This is any expression that _isn't_ an |
| 542 | // un-parenthesized binary expression. |
| 543 | // |
| 544 | // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr. |
| 545 | // |
| 546 | // Returns a pair containing the result of the evaluation, plus the |
| 547 | // expression remaining to be parsed. |
| 548 | std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr, |
| 549 | ParseContext PCtx) const { |
| 550 | EvalResult SubExprResult; |
| 551 | StringRef RemainingExpr; |
| 552 | |
| 553 | if (Expr.empty()) |
| 554 | return std::make_pair(EvalResult("Unexpected end of expression"), ""); |
| 555 | |
| 556 | if (Expr[0] == '(') |
| 557 | std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx); |
| 558 | else if (Expr[0] == '*') |
| 559 | std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); |
Lang Hames | c90a85ff | 2014-07-22 23:17:21 +0000 | [diff] [blame] | 560 | else if (isalpha(Expr[0]) || Expr[0] == '_') |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 561 | std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx); |
| 562 | else if (isdigit(Expr[0])) |
| 563 | std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 564 | else |
| 565 | return std::make_pair( |
| 566 | unexpectedToken(Expr, Expr, |
| 567 | "expected '(', '*', identifier, or number"), ""); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 568 | |
| 569 | if (SubExprResult.hasError()) |
| 570 | return std::make_pair(SubExprResult, RemainingExpr); |
| 571 | |
| 572 | // Evaluate bit-slice if present. |
| 573 | if (RemainingExpr.startswith("[")) |
| 574 | std::tie(SubExprResult, RemainingExpr) = |
| 575 | evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr)); |
| 576 | |
| 577 | return std::make_pair(SubExprResult, RemainingExpr); |
| 578 | } |
| 579 | |
| 580 | // Evaluate a bit-slice of an expression. |
| 581 | // A bit-slice has the form "<expr>[high:low]". The result of evaluating a |
| 582 | // slice is the bits between high and low (inclusive) in the original |
| 583 | // expression, right shifted so that the "low" bit is in position 0 in the |
| 584 | // result. |
| 585 | // Returns a pair containing the result of the slice operation, plus the |
| 586 | // expression remaining to be parsed. |
| 587 | std::pair<EvalResult, StringRef> |
Benjamin Kramer | 1afc1de | 2016-06-17 20:41:14 +0000 | [diff] [blame] | 588 | evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const { |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 589 | EvalResult SubExprResult; |
| 590 | StringRef RemainingExpr; |
| 591 | std::tie(SubExprResult, RemainingExpr) = Ctx; |
| 592 | |
| 593 | assert(RemainingExpr.startswith("[") && "Not a slice expr."); |
| 594 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 595 | |
| 596 | EvalResult HighBitExpr; |
| 597 | std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); |
| 598 | |
| 599 | if (HighBitExpr.hasError()) |
| 600 | return std::make_pair(HighBitExpr, RemainingExpr); |
| 601 | |
| 602 | if (!RemainingExpr.startswith(":")) |
| 603 | return std::make_pair( |
| 604 | unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), ""); |
| 605 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 606 | |
| 607 | EvalResult LowBitExpr; |
| 608 | std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); |
| 609 | |
| 610 | if (LowBitExpr.hasError()) |
| 611 | return std::make_pair(LowBitExpr, RemainingExpr); |
| 612 | |
| 613 | if (!RemainingExpr.startswith("]")) |
| 614 | return std::make_pair( |
| 615 | unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), ""); |
| 616 | RemainingExpr = RemainingExpr.substr(1).ltrim(); |
| 617 | |
| 618 | unsigned HighBit = HighBitExpr.getValue(); |
| 619 | unsigned LowBit = LowBitExpr.getValue(); |
| 620 | uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1; |
| 621 | uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask; |
| 622 | return std::make_pair(EvalResult(SlicedValue), RemainingExpr); |
| 623 | } |
| 624 | |
| 625 | // Evaluate a "complex" expression. |
| 626 | // Takes an already evaluated subexpression and checks for the presence of a |
| 627 | // binary operator, computing the result of the binary operation if one is |
| 628 | // found. Used to make arithmetic expressions left-associative. |
| 629 | // Returns a pair containing the ultimate result of evaluating the |
| 630 | // expression, plus the expression remaining to be evaluated. |
| 631 | std::pair<EvalResult, StringRef> |
Benjamin Kramer | 1afc1de | 2016-06-17 20:41:14 +0000 | [diff] [blame] | 632 | evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining, |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 633 | ParseContext PCtx) const { |
| 634 | EvalResult LHSResult; |
| 635 | StringRef RemainingExpr; |
| 636 | std::tie(LHSResult, RemainingExpr) = LHSAndRemaining; |
| 637 | |
| 638 | // If there was an error, or there's nothing left to evaluate, return the |
| 639 | // result. |
| 640 | if (LHSResult.hasError() || RemainingExpr == "") |
| 641 | return std::make_pair(LHSResult, RemainingExpr); |
| 642 | |
| 643 | // Otherwise check if this is a binary expressioan. |
| 644 | BinOpToken BinOp; |
| 645 | std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); |
| 646 | |
| 647 | // If this isn't a recognized expression just return. |
| 648 | if (BinOp == BinOpToken::Invalid) |
| 649 | return std::make_pair(LHSResult, RemainingExpr); |
| 650 | |
| 651 | // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. |
| 652 | EvalResult RHSResult; |
| 653 | std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx); |
| 654 | |
| 655 | // If there was an error evaluating the RHS, return it. |
| 656 | if (RHSResult.hasError()) |
| 657 | return std::make_pair(RHSResult, RemainingExpr); |
| 658 | |
| 659 | // This is a binary expression - evaluate and try to continue as a |
| 660 | // complex expr. |
| 661 | EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult)); |
| 662 | |
| 663 | return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx); |
| 664 | } |
| 665 | |
| 666 | bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { |
| 667 | MCDisassembler *Dis = Checker.Disassembler; |
| 668 | StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); |
Aaron Ballman | 7a7b144 | 2014-11-12 13:55:27 +0000 | [diff] [blame] | 669 | ArrayRef<uint8_t> SectionBytes( |
Aaron Ballman | 9f8d2b09 | 2014-11-12 19:43:13 +0000 | [diff] [blame] | 670 | reinterpret_cast<const uint8_t *>(SectionMem.data()), |
Aaron Ballman | 7a7b144 | 2014-11-12 13:55:27 +0000 | [diff] [blame] | 671 | SectionMem.size()); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 672 | |
| 673 | MCDisassembler::DecodeStatus S = |
| 674 | Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); |
| 675 | |
| 676 | return (S == MCDisassembler::Success); |
| 677 | } |
| 678 | }; |
Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 679 | } |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 680 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 681 | RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, |
| 682 | MCDisassembler *Disassembler, |
| 683 | MCInstPrinter *InstPrinter, |
| 684 | raw_ostream &ErrStream) |
| 685 | : RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter), |
| 686 | ErrStream(ErrStream) { |
| 687 | RTDyld.Checker = this; |
| 688 | } |
| 689 | |
| 690 | bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 691 | CheckExpr = CheckExpr.trim(); |
Nicola Zaghen | d34e60c | 2018-05-14 12:53:11 +0000 | [diff] [blame] | 692 | LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr |
| 693 | << "'...\n"); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 694 | RuntimeDyldCheckerExprEval P(*this, ErrStream); |
| 695 | bool Result = P.evaluate(CheckExpr); |
| 696 | (void)Result; |
Nicola Zaghen | d34e60c | 2018-05-14 12:53:11 +0000 | [diff] [blame] | 697 | LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " |
| 698 | << (Result ? "passed" : "FAILED") << ".\n"); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 699 | return Result; |
| 700 | } |
| 701 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 702 | bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, |
| 703 | MemoryBuffer *MemBuf) const { |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 704 | bool DidAllTestsPass = true; |
| 705 | unsigned NumRules = 0; |
| 706 | |
| 707 | const char *LineStart = MemBuf->getBufferStart(); |
| 708 | |
| 709 | // Eat whitespace. |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 710 | while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart)) |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 711 | ++LineStart; |
| 712 | |
| 713 | while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') { |
| 714 | const char *LineEnd = LineStart; |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 715 | while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' && |
| 716 | *LineEnd != '\n') |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 717 | ++LineEnd; |
| 718 | |
| 719 | StringRef Line(LineStart, LineEnd - LineStart); |
| 720 | if (Line.startswith(RulePrefix)) { |
| 721 | DidAllTestsPass &= check(Line.substr(RulePrefix.size())); |
| 722 | ++NumRules; |
| 723 | } |
| 724 | |
| 725 | // Eat whitespace. |
| 726 | LineStart = LineEnd; |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 727 | while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart)) |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 728 | ++LineStart; |
| 729 | } |
| 730 | return DidAllTestsPass && (NumRules != 0); |
| 731 | } |
| 732 | |
Lang Hames | adde5ba | 2018-09-25 19:48:46 +0000 | [diff] [blame] | 733 | Expected<JITSymbolResolver::LookupResult> RuntimeDyldCheckerImpl::lookup( |
| 734 | const JITSymbolResolver::LookupSet &Symbols) const { |
| 735 | auto ResultP = std::make_shared< |
| 736 | std::promise<Expected<JITSymbolResolver::LookupResult>>>(); |
| 737 | auto ResultF = ResultP->get_future(); |
| 738 | |
| 739 | getRTDyld().Resolver.lookup( |
| 740 | Symbols, [=](Expected<JITSymbolResolver::LookupResult> Result) { |
| 741 | ResultP->set_value(std::move(Result)); |
| 742 | }); |
| 743 | return ResultF.get(); |
| 744 | } |
| 745 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 746 | bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { |
Lang Hames | a32d71b | 2015-10-18 01:41:37 +0000 | [diff] [blame] | 747 | if (getRTDyld().getSymbol(Symbol)) |
Lang Hames | 78937c2 | 2015-07-04 01:35:26 +0000 | [diff] [blame] | 748 | return true; |
Lang Hames | adde5ba | 2018-09-25 19:48:46 +0000 | [diff] [blame] | 749 | auto Result = lookup({Symbol}); |
| 750 | |
Lang Hames | b72f484 | 2018-01-19 22:24:13 +0000 | [diff] [blame] | 751 | if (!Result) { |
| 752 | logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); |
| 753 | return false; |
| 754 | } |
Lang Hames | adde5ba | 2018-09-25 19:48:46 +0000 | [diff] [blame] | 755 | |
Lang Hames | b72f484 | 2018-01-19 22:24:13 +0000 | [diff] [blame] | 756 | assert(Result->count(Symbol) && "Missing symbol result"); |
| 757 | return true; |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 758 | } |
| 759 | |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 760 | uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 761 | return static_cast<uint64_t>( |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 762 | reinterpret_cast<uintptr_t>(getRTDyld().getSymbolLocalAddress(Symbol))); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 763 | } |
| 764 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 765 | uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 766 | if (auto InternalSymbol = getRTDyld().getSymbol(Symbol)) |
| 767 | return InternalSymbol.getAddress(); |
Lang Hames | b72f484 | 2018-01-19 22:24:13 +0000 | [diff] [blame] | 768 | |
Lang Hames | adde5ba | 2018-09-25 19:48:46 +0000 | [diff] [blame] | 769 | auto Result = lookup({Symbol}); |
Lang Hames | b72f484 | 2018-01-19 22:24:13 +0000 | [diff] [blame] | 770 | if (!Result) { |
| 771 | logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); |
| 772 | return 0; |
| 773 | } |
| 774 | auto I = Result->find(Symbol); |
| 775 | assert(I != Result->end() && "Missing symbol result"); |
| 776 | return I->second.getAddress(); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 777 | } |
| 778 | |
| 779 | uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, |
| 780 | unsigned Size) const { |
| 781 | uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); |
| 782 | assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); |
Lang Hames | dc77feb | 2014-08-27 17:41:06 +0000 | [diff] [blame] | 783 | uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr); |
Lang Hames | e1287c0 | 2014-08-29 23:17:47 +0000 | [diff] [blame] | 784 | return getRTDyld().readBytesUnaligned(Src, Size); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 785 | } |
| 786 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 787 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 788 | std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string> |
| 789 | RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName, |
| 790 | StringRef SectionName) const { |
| 791 | |
| 792 | auto SectionMapItr = Stubs.find(FileName); |
| 793 | if (SectionMapItr == Stubs.end()) { |
Lang Hames | cce313b | 2014-07-22 23:07:52 +0000 | [diff] [blame] | 794 | std::string ErrorMsg = "File '"; |
| 795 | ErrorMsg += FileName; |
| 796 | ErrorMsg += "' not found. "; |
| 797 | if (Stubs.empty()) |
| 798 | ErrorMsg += "No stubs registered."; |
| 799 | else { |
| 800 | ErrorMsg += "Available files are:"; |
| 801 | for (const auto& StubEntry : Stubs) { |
| 802 | ErrorMsg += " '"; |
| 803 | ErrorMsg += StubEntry.first; |
| 804 | ErrorMsg += "'"; |
| 805 | } |
| 806 | } |
| 807 | ErrorMsg += "\n"; |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 808 | return std::make_pair(nullptr, ErrorMsg); |
Lang Hames | cce313b | 2014-07-22 23:07:52 +0000 | [diff] [blame] | 809 | } |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 810 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 811 | auto SectionInfoItr = SectionMapItr->second.find(SectionName); |
| 812 | if (SectionInfoItr == SectionMapItr->second.end()) |
| 813 | return std::make_pair(nullptr, |
| 814 | ("Section '" + SectionName + "' not found in file '" + |
| 815 | FileName + "'\n").str()); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 816 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 817 | return std::make_pair(&SectionInfoItr->second, std::string("")); |
| 818 | } |
| 819 | |
| 820 | std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr( |
| 821 | StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { |
| 822 | |
| 823 | const SectionAddressInfo *SectionInfo = nullptr; |
| 824 | { |
| 825 | std::string ErrorMsg; |
| 826 | std::tie(SectionInfo, ErrorMsg) = |
| 827 | findSectionAddrInfo(FileName, SectionName); |
| 828 | if (ErrorMsg != "") |
| 829 | return std::make_pair(0, ErrorMsg); |
| 830 | } |
| 831 | |
| 832 | unsigned SectionID = SectionInfo->SectionID; |
| 833 | uint64_t Addr; |
| 834 | if (IsInsideLoad) |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 835 | Addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>( |
| 836 | getRTDyld().Sections[SectionID].getAddress())); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 837 | else |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 838 | Addr = getRTDyld().Sections[SectionID].getLoadAddress(); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 839 | |
| 840 | return std::make_pair(Addr, std::string("")); |
| 841 | } |
| 842 | |
| 843 | std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor( |
| 844 | StringRef FileName, StringRef SectionName, StringRef SymbolName, |
| 845 | bool IsInsideLoad) const { |
| 846 | |
| 847 | const SectionAddressInfo *SectionInfo = nullptr; |
| 848 | { |
| 849 | std::string ErrorMsg; |
| 850 | std::tie(SectionInfo, ErrorMsg) = |
| 851 | findSectionAddrInfo(FileName, SectionName); |
| 852 | if (ErrorMsg != "") |
| 853 | return std::make_pair(0, ErrorMsg); |
| 854 | } |
| 855 | |
| 856 | unsigned SectionID = SectionInfo->SectionID; |
| 857 | const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets; |
| 858 | auto StubOffsetItr = SymbolStubs.find(SymbolName); |
| 859 | if (StubOffsetItr == SymbolStubs.end()) |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 860 | return std::make_pair(0, |
Lang Hames | 6f8525d | 2014-09-11 23:09:22 +0000 | [diff] [blame] | 861 | ("Stub for symbol '" + SymbolName + "' not found. " |
| 862 | "If '" + SymbolName + "' is an internal symbol this " |
| 863 | "may indicate that the stub target offset is being " |
| 864 | "computed incorrectly.\n").str()); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 865 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 866 | uint64_t StubOffset = StubOffsetItr->second; |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 867 | |
| 868 | uint64_t Addr; |
| 869 | if (IsInsideLoad) { |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 870 | uintptr_t SectionBase = reinterpret_cast<uintptr_t>( |
| 871 | getRTDyld().Sections[SectionID].getAddress()); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 872 | Addr = static_cast<uint64_t>(SectionBase) + StubOffset; |
Lang Hames | 9cb7353 | 2014-07-29 23:43:13 +0000 | [diff] [blame] | 873 | } else { |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 874 | uint64_t SectionBase = getRTDyld().Sections[SectionID].getLoadAddress(); |
Lang Hames | 9cb7353 | 2014-07-29 23:43:13 +0000 | [diff] [blame] | 875 | Addr = SectionBase + StubOffset; |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 876 | } |
| 877 | |
| 878 | return std::make_pair(Addr, std::string("")); |
| 879 | } |
| 880 | |
| 881 | StringRef |
| 882 | RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const { |
Lang Hames | 6bfd398 | 2015-01-16 23:13:56 +0000 | [diff] [blame] | 883 | RTDyldSymbolTable::const_iterator pos = |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 884 | getRTDyld().GlobalSymbolTable.find(Name); |
| 885 | if (pos == getRTDyld().GlobalSymbolTable.end()) |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 886 | return StringRef(); |
Lang Hames | 6bfd398 | 2015-01-16 23:13:56 +0000 | [diff] [blame] | 887 | const auto &SymInfo = pos->second; |
| 888 | uint8_t *SectionAddr = getRTDyld().getSectionAddress(SymInfo.getSectionID()); |
| 889 | return StringRef(reinterpret_cast<const char *>(SectionAddr) + |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 890 | SymInfo.getOffset(), |
| 891 | getRTDyld().Sections[SymInfo.getSectionID()].getSize() - |
| 892 | SymInfo.getOffset()); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 893 | } |
| 894 | |
Lang Hames | ff41150 | 2017-05-07 17:19:53 +0000 | [diff] [blame] | 895 | Optional<uint64_t> |
| 896 | RuntimeDyldCheckerImpl::getSectionLoadAddress(void *LocalAddress) const { |
| 897 | for (auto &S : getRTDyld().Sections) { |
| 898 | if (S.getAddress() == LocalAddress) |
| 899 | return S.getLoadAddress(); |
| 900 | } |
| 901 | return Optional<uint64_t>(); |
| 902 | } |
| 903 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 904 | void RuntimeDyldCheckerImpl::registerSection( |
| 905 | StringRef FilePath, unsigned SectionID) { |
| 906 | StringRef FileName = sys::path::filename(FilePath); |
| 907 | const SectionEntry &Section = getRTDyld().Sections[SectionID]; |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 908 | StringRef SectionName = Section.getName(); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 909 | |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 910 | Stubs[FileName][SectionName].SectionID = SectionID; |
| 911 | } |
| 912 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 913 | void RuntimeDyldCheckerImpl::registerStubMap( |
Lang Hames | 480763f | 2014-07-29 20:40:37 +0000 | [diff] [blame] | 914 | StringRef FilePath, unsigned SectionID, |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 915 | const RuntimeDyldImpl::StubMap &RTDyldStubs) { |
Lang Hames | 480763f | 2014-07-29 20:40:37 +0000 | [diff] [blame] | 916 | StringRef FileName = sys::path::filename(FilePath); |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 917 | const SectionEntry &Section = getRTDyld().Sections[SectionID]; |
Sanjoy Das | 277776a | 2015-11-23 21:47:41 +0000 | [diff] [blame] | 918 | StringRef SectionName = Section.getName(); |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 919 | |
| 920 | Stubs[FileName][SectionName].SectionID = SectionID; |
| 921 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 922 | for (auto &StubMapEntry : RTDyldStubs) { |
| 923 | std::string SymbolName = ""; |
| 924 | |
| 925 | if (StubMapEntry.first.SymbolName) |
| 926 | SymbolName = StubMapEntry.first.SymbolName; |
| 927 | else { |
| 928 | // If this is a (Section, Offset) pair, do a reverse lookup in the |
| 929 | // global symbol table to find the name. |
| 930 | for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) { |
Lang Hames | 6bfd398 | 2015-01-16 23:13:56 +0000 | [diff] [blame] | 931 | const auto &SymInfo = GSTEntry.second; |
| 932 | if (SymInfo.getSectionID() == StubMapEntry.first.SectionID && |
| 933 | SymInfo.getOffset() == |
| 934 | static_cast<uint64_t>(StubMapEntry.first.Offset)) { |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 935 | SymbolName = GSTEntry.first(); |
| 936 | break; |
| 937 | } |
| 938 | } |
| 939 | } |
| 940 | |
| 941 | if (SymbolName != "") |
Lang Hames | 587ee6a | 2014-09-03 05:01:46 +0000 | [diff] [blame] | 942 | Stubs[FileName][SectionName].StubOffsets[SymbolName] = |
| 943 | StubMapEntry.second; |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 944 | } |
| 945 | } |
| 946 | |
| 947 | RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld, |
| 948 | MCDisassembler *Disassembler, |
| 949 | MCInstPrinter *InstPrinter, |
| 950 | raw_ostream &ErrStream) |
| 951 | : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler, |
| 952 | InstPrinter, ErrStream)) {} |
| 953 | |
| 954 | RuntimeDyldChecker::~RuntimeDyldChecker() {} |
| 955 | |
Lang Hames | 778ef5b | 2014-09-04 04:19:54 +0000 | [diff] [blame] | 956 | RuntimeDyld& RuntimeDyldChecker::getRTDyld() { |
| 957 | return Impl->RTDyld; |
| 958 | } |
| 959 | |
| 960 | const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const { |
| 961 | return Impl->RTDyld; |
| 962 | } |
| 963 | |
Lang Hames | f7acddd | 2014-07-22 22:47:39 +0000 | [diff] [blame] | 964 | bool RuntimeDyldChecker::check(StringRef CheckExpr) const { |
| 965 | return Impl->check(CheckExpr); |
| 966 | } |
| 967 | |
| 968 | bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, |
| 969 | MemoryBuffer *MemBuf) const { |
| 970 | return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf); |
Lang Hames | e1c1138 | 2014-06-27 20:20:57 +0000 | [diff] [blame] | 971 | } |
Lang Hames | 778ef5b | 2014-09-04 04:19:54 +0000 | [diff] [blame] | 972 | |
| 973 | std::pair<uint64_t, std::string> |
| 974 | RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, |
Lang Hames | b118603 | 2015-03-11 00:43:26 +0000 | [diff] [blame] | 975 | bool LocalAddress) { |
| 976 | return Impl->getSectionAddr(FileName, SectionName, LocalAddress); |
Lang Hames | 778ef5b | 2014-09-04 04:19:54 +0000 | [diff] [blame] | 977 | } |
Lang Hames | ff41150 | 2017-05-07 17:19:53 +0000 | [diff] [blame] | 978 | |
| 979 | Optional<uint64_t> |
| 980 | RuntimeDyldChecker::getSectionLoadAddress(void *LocalAddress) const { |
| 981 | return Impl->getSectionLoadAddress(LocalAddress); |
| 982 | } |