1058 lines · cpp
1//===--- RuntimeDyldChecker.cpp - 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"10#include "RuntimeDyldCheckerImpl.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/MC/MCAsmInfo.h"13#include "llvm/MC/MCContext.h"14#include "llvm/MC/MCDisassembler/MCDisassembler.h"15#include "llvm/MC/MCInst.h"16#include "llvm/MC/MCInstPrinter.h"17#include "llvm/MC/MCInstrInfo.h"18#include "llvm/MC/MCRegisterInfo.h"19#include "llvm/MC/MCSubtargetInfo.h"20#include "llvm/MC/MCTargetOptions.h"21#include "llvm/MC/TargetRegistry.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/MemoryBuffer.h"24#include <cctype>25#include <memory>26#include <utility>27 28#define DEBUG_TYPE "rtdyld"29 30using namespace llvm;31 32namespace {33struct TargetInfo {34 const Target *TheTarget;35 std::unique_ptr<MCSubtargetInfo> STI;36 std::unique_ptr<MCRegisterInfo> MRI;37 std::unique_ptr<MCAsmInfo> MAI;38 std::unique_ptr<MCContext> Ctx;39 std::unique_ptr<MCDisassembler> Disassembler;40 std::unique_ptr<MCInstrInfo> MII;41 std::unique_ptr<MCInstPrinter> InstPrinter;42};43} // anonymous namespace44 45namespace llvm {46 47// Helper class that implements the language evaluated by RuntimeDyldChecker.48class RuntimeDyldCheckerExprEval {49public:50 RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker,51 raw_ostream &ErrStream)52 : Checker(Checker) {}53 54 bool evaluate(StringRef Expr) const {55 // Expect equality expression of the form 'LHS = RHS'.56 Expr = Expr.trim();57 size_t EQIdx = Expr.find('=');58 59 ParseContext OutsideLoad(false);60 61 // Evaluate LHS.62 StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();63 StringRef RemainingExpr;64 EvalResult LHSResult;65 std::tie(LHSResult, RemainingExpr) =66 evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad);67 if (LHSResult.hasError())68 return handleError(Expr, LHSResult);69 if (RemainingExpr != "")70 return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, ""));71 72 // Evaluate RHS.73 StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();74 EvalResult RHSResult;75 std::tie(RHSResult, RemainingExpr) =76 evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad);77 if (RHSResult.hasError())78 return handleError(Expr, RHSResult);79 if (RemainingExpr != "")80 return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, ""));81 82 if (LHSResult.getValue() != RHSResult.getValue()) {83 Checker.ErrStream << "Expression '" << Expr << "' is false: "84 << format("0x%" PRIx64, LHSResult.getValue())85 << " != " << format("0x%" PRIx64, RHSResult.getValue())86 << "\n";87 return false;88 }89 return true;90 }91 92private:93 // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In94 // particular, it needs to know whether a symbol is being evaluated in the95 // context of a load, in which case we want the linker's local address for96 // the symbol, or outside of a load, in which case we want the symbol's97 // address in the remote target.98 99 struct ParseContext {100 bool IsInsideLoad;101 ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}102 };103 104 const RuntimeDyldCheckerImpl &Checker;105 106 enum class BinOpToken : unsigned {107 Invalid,108 Add,109 Sub,110 BitwiseAnd,111 BitwiseOr,112 ShiftLeft,113 ShiftRight114 };115 116 class EvalResult {117 public:118 EvalResult() : Value(0) {}119 EvalResult(uint64_t Value) : Value(Value) {}120 EvalResult(std::string ErrorMsg)121 : Value(0), ErrorMsg(std::move(ErrorMsg)) {}122 uint64_t getValue() const { return Value; }123 bool hasError() const { return ErrorMsg != ""; }124 const std::string &getErrorMsg() const { return ErrorMsg; }125 126 private:127 uint64_t Value;128 std::string ErrorMsg;129 };130 131 StringRef getTokenForError(StringRef Expr) const {132 if (Expr.empty())133 return "";134 135 StringRef Token, Remaining;136 if (isalpha(Expr[0]))137 std::tie(Token, Remaining) = parseSymbol(Expr);138 else if (isdigit(Expr[0]))139 std::tie(Token, Remaining) = parseNumberString(Expr);140 else {141 unsigned TokLen = 1;142 if (Expr.starts_with("<<") || Expr.starts_with(">>"))143 TokLen = 2;144 Token = Expr.substr(0, TokLen);145 }146 return Token;147 }148 149 EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr,150 StringRef ErrText) const {151 std::string ErrorMsg("Encountered unexpected token '");152 ErrorMsg += getTokenForError(TokenStart);153 if (SubExpr != "") {154 ErrorMsg += "' while parsing subexpression '";155 ErrorMsg += SubExpr;156 }157 ErrorMsg += "'";158 if (ErrText != "") {159 ErrorMsg += " ";160 ErrorMsg += ErrText;161 }162 return EvalResult(std::move(ErrorMsg));163 }164 165 bool handleError(StringRef Expr, const EvalResult &R) const {166 assert(R.hasError() && "Not an error result.");167 Checker.ErrStream << "Error evaluating expression '" << Expr168 << "': " << R.getErrorMsg() << "\n";169 return false;170 }171 172 std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {173 if (Expr.empty())174 return std::make_pair(BinOpToken::Invalid, "");175 176 // Handle the two 2-character tokens.177 if (Expr.starts_with("<<"))178 return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim());179 if (Expr.starts_with(">>"))180 return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim());181 182 // Handle one-character tokens.183 BinOpToken Op;184 switch (Expr[0]) {185 default:186 return std::make_pair(BinOpToken::Invalid, Expr);187 case '+':188 Op = BinOpToken::Add;189 break;190 case '-':191 Op = BinOpToken::Sub;192 break;193 case '&':194 Op = BinOpToken::BitwiseAnd;195 break;196 case '|':197 Op = BinOpToken::BitwiseOr;198 break;199 }200 201 return std::make_pair(Op, Expr.substr(1).ltrim());202 }203 204 EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,205 const EvalResult &RHSResult) const {206 switch (Op) {207 default:208 llvm_unreachable("Tried to evaluate unrecognized operation.");209 case BinOpToken::Add:210 return EvalResult(LHSResult.getValue() + RHSResult.getValue());211 case BinOpToken::Sub:212 return EvalResult(LHSResult.getValue() - RHSResult.getValue());213 case BinOpToken::BitwiseAnd:214 return EvalResult(LHSResult.getValue() & RHSResult.getValue());215 case BinOpToken::BitwiseOr:216 return EvalResult(LHSResult.getValue() | RHSResult.getValue());217 case BinOpToken::ShiftLeft:218 return EvalResult(LHSResult.getValue() << RHSResult.getValue());219 case BinOpToken::ShiftRight:220 return EvalResult(LHSResult.getValue() >> RHSResult.getValue());221 }222 }223 224 // Parse a symbol and return a (string, string) pair representing the symbol225 // name and expression remaining to be parsed.226 std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const {227 size_t FirstNonSymbol = Expr.find_first_not_of("0123456789"228 "abcdefghijklmnopqrstuvwxyz"229 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"230 ":_.$");231 return std::make_pair(Expr.substr(0, FirstNonSymbol),232 Expr.substr(FirstNonSymbol).ltrim());233 }234 235 // Evaluate a call to decode_operand. Decode the instruction operand at the236 // given symbol and get the value of the requested operand.237 // Returns an error if the instruction cannot be decoded, or the requested238 // operand is not an immediate.239 // On success, returns a pair containing the value of the operand, plus240 // the expression remaining to be evaluated.241 std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const {242 if (!Expr.starts_with("("))243 return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");244 StringRef RemainingExpr = Expr.substr(1).ltrim();245 StringRef Symbol;246 std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);247 248 if (!Checker.isSymbolValid(Symbol))249 return std::make_pair(250 EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),251 "");252 253 // if there is an offset number expr254 int64_t Offset = 0;255 BinOpToken BinOp;256 std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);257 switch (BinOp) {258 case BinOpToken::Add: {259 EvalResult Number;260 std::tie(Number, RemainingExpr) = evalNumberExpr(RemainingExpr);261 Offset = Number.getValue();262 break;263 }264 case BinOpToken::Invalid:265 break;266 default:267 return std::make_pair(268 unexpectedToken(RemainingExpr, RemainingExpr,269 "expected '+' for offset or ',' if no offset"),270 "");271 }272 273 if (!RemainingExpr.starts_with(","))274 return std::make_pair(275 unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");276 RemainingExpr = RemainingExpr.substr(1).ltrim();277 278 EvalResult OpIdxExpr;279 std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);280 if (OpIdxExpr.hasError())281 return std::make_pair(OpIdxExpr, "");282 283 if (!RemainingExpr.starts_with(")"))284 return std::make_pair(285 unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");286 RemainingExpr = RemainingExpr.substr(1).ltrim();287 288 MCInst Inst;289 uint64_t Size;290 if (!decodeInst(Symbol, Inst, Size, Offset))291 return std::make_pair(292 EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),293 "");294 295 unsigned OpIdx = OpIdxExpr.getValue();296 297 auto printInst = [this](StringRef Symbol, MCInst Inst,298 raw_string_ostream &ErrMsgStream) {299 auto TT = Checker.getTripleForSymbol(Checker.getTargetFlag(Symbol));300 auto TI = getTargetInfo(TT, Checker.getCPU(), Checker.getFeatures());301 if (auto E = TI.takeError()) {302 errs() << "Error obtaining instruction printer: "303 << toString(std::move(E)) << "\n";304 return;305 }306 Inst.dump_pretty(ErrMsgStream, TI->InstPrinter.get());307 return;308 };309 310 if (OpIdx >= Inst.getNumOperands()) {311 std::string ErrMsg;312 raw_string_ostream ErrMsgStream(ErrMsg);313 ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx)314 << "' for instruction '" << Symbol315 << "'. Instruction has only "316 << format("%i", Inst.getNumOperands())317 << " operands.\nInstruction is:\n ";318 319 printInst(Symbol, Inst, ErrMsgStream);320 return {EvalResult(std::move(ErrMsg)), ""};321 }322 323 const MCOperand &Op = Inst.getOperand(OpIdx);324 if (!Op.isImm()) {325 std::string ErrMsg;326 raw_string_ostream ErrMsgStream(ErrMsg);327 ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '"328 << Symbol << "' is not an immediate.\nInstruction is:\n ";329 330 printInst(Symbol, Inst, ErrMsgStream);331 return {EvalResult(std::move(ErrMsg)), ""};332 }333 334 return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);335 }336 337 // Evaluate a call to next_pc.338 // Decode the instruction at the given symbol and return the following program339 // counter.340 // Returns an error if the instruction cannot be decoded.341 // On success, returns a pair containing the next PC, plus of the342 // expression remaining to be evaluated.343 std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr,344 ParseContext PCtx) const {345 if (!Expr.starts_with("("))346 return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");347 StringRef RemainingExpr = Expr.substr(1).ltrim();348 StringRef Symbol;349 std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);350 351 if (!Checker.isSymbolValid(Symbol))352 return std::make_pair(353 EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),354 "");355 356 if (!RemainingExpr.starts_with(")"))357 return std::make_pair(358 unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");359 RemainingExpr = RemainingExpr.substr(1).ltrim();360 361 MCInst Inst;362 uint64_t InstSize;363 if (!decodeInst(Symbol, Inst, InstSize, 0))364 return std::make_pair(365 EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),366 "");367 368 uint64_t SymbolAddr = PCtx.IsInsideLoad369 ? Checker.getSymbolLocalAddr(Symbol)370 : Checker.getSymbolRemoteAddr(Symbol);371 372 // ARM PC offset is 8 instead of 4, because it accounts for an additional373 // prefetch instruction that increments PC even though it is implicit.374 auto TT = Checker.getTripleForSymbol(Checker.getTargetFlag(Symbol));375 uint64_t PCOffset = TT.getArch() == Triple::ArchType::arm ? 4 : 0;376 377 uint64_t NextPC = SymbolAddr + InstSize + PCOffset;378 379 return std::make_pair(EvalResult(NextPC), RemainingExpr);380 }381 382 // Evaluate a call to stub_addr/got_addr.383 // Look up and return the address of the stub for the given384 // (<file name>, <section name>, <symbol name>) tuple.385 // On success, returns a pair containing the stub address, plus the expression386 // remaining to be evaluated.387 std::pair<EvalResult, StringRef>388 evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const {389 if (!Expr.starts_with("("))390 return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");391 StringRef RemainingExpr = Expr.substr(1).ltrim();392 393 // Handle file-name specially, as it may contain characters that aren't394 // legal for symbols.395 StringRef StubContainerName;396 size_t ComaIdx = RemainingExpr.find(',');397 StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim();398 RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();399 400 if (!RemainingExpr.starts_with(","))401 return std::make_pair(402 unexpectedToken(RemainingExpr, Expr, "expected ','"), "");403 RemainingExpr = RemainingExpr.substr(1).ltrim();404 405 StringRef Symbol;406 std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);407 408 // Parse optional parameter to filter by stub kind409 StringRef KindNameFilter;410 if (RemainingExpr.starts_with(",")) {411 RemainingExpr = RemainingExpr.substr(1).ltrim();412 size_t ClosingBracket = RemainingExpr.find(")");413 KindNameFilter = RemainingExpr.substr(0, ClosingBracket);414 RemainingExpr = RemainingExpr.substr(ClosingBracket);415 }416 417 if (!RemainingExpr.starts_with(")"))418 return std::make_pair(419 unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");420 RemainingExpr = RemainingExpr.substr(1).ltrim();421 422 uint64_t StubAddr;423 std::string ErrorMsg;424 std::tie(StubAddr, ErrorMsg) =425 Checker.getStubOrGOTAddrFor(StubContainerName, Symbol, KindNameFilter,426 PCtx.IsInsideLoad, IsStubAddr);427 428 if (ErrorMsg != "")429 return std::make_pair(EvalResult(ErrorMsg), "");430 431 return std::make_pair(EvalResult(StubAddr), RemainingExpr);432 }433 434 std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr,435 ParseContext PCtx) const {436 if (!Expr.starts_with("("))437 return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");438 StringRef RemainingExpr = Expr.substr(1).ltrim();439 440 // Handle file-name specially, as it may contain characters that aren't441 // legal for symbols.442 StringRef FileName;443 size_t ComaIdx = RemainingExpr.find(',');444 FileName = RemainingExpr.substr(0, ComaIdx).rtrim();445 RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();446 447 if (!RemainingExpr.starts_with(","))448 return std::make_pair(449 unexpectedToken(RemainingExpr, Expr, "expected ','"), "");450 RemainingExpr = RemainingExpr.substr(1).ltrim();451 452 StringRef SectionName;453 size_t CloseParensIdx = RemainingExpr.find(')');454 SectionName = RemainingExpr.substr(0, CloseParensIdx).rtrim();455 RemainingExpr = RemainingExpr.substr(CloseParensIdx).ltrim();456 457 if (!RemainingExpr.starts_with(")"))458 return std::make_pair(459 unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");460 RemainingExpr = RemainingExpr.substr(1).ltrim();461 462 uint64_t StubAddr;463 std::string ErrorMsg;464 std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(465 FileName, SectionName, PCtx.IsInsideLoad);466 467 if (ErrorMsg != "")468 return std::make_pair(EvalResult(ErrorMsg), "");469 470 return std::make_pair(EvalResult(StubAddr), RemainingExpr);471 }472 473 // Evaluate an identifier expr, which may be a symbol, or a call to474 // one of the builtin functions: get_insn_opcode or get_insn_length.475 // Return the result, plus the expression remaining to be parsed.476 std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr,477 ParseContext PCtx) const {478 StringRef Symbol;479 StringRef RemainingExpr;480 std::tie(Symbol, RemainingExpr) = parseSymbol(Expr);481 482 // Check for builtin function calls.483 if (Symbol == "decode_operand")484 return evalDecodeOperand(RemainingExpr);485 else if (Symbol == "next_pc")486 return evalNextPC(RemainingExpr, PCtx);487 else if (Symbol == "stub_addr")488 return evalStubOrGOTAddr(RemainingExpr, PCtx, true);489 else if (Symbol == "got_addr")490 return evalStubOrGOTAddr(RemainingExpr, PCtx, false);491 else if (Symbol == "section_addr")492 return evalSectionAddr(RemainingExpr, PCtx);493 494 if (!Checker.isSymbolValid(Symbol)) {495 std::string ErrMsg("No known address for symbol '");496 ErrMsg += Symbol;497 ErrMsg += "'";498 if (Symbol.starts_with("L"))499 ErrMsg += " (this appears to be an assembler local label - "500 " perhaps drop the 'L'?)";501 502 return std::make_pair(EvalResult(ErrMsg), "");503 }504 505 // The value for the symbol depends on the context we're evaluating in:506 // Inside a load this is the address in the linker's memory, outside a507 // load it's the address in the target processes memory.508 uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol)509 : Checker.getSymbolRemoteAddr(Symbol);510 511 // Looks like a plain symbol reference.512 return std::make_pair(EvalResult(Value), RemainingExpr);513 }514 515 // Parse a number (hexadecimal or decimal) and return a (string, string)516 // pair representing the number and the expression remaining to be parsed.517 std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {518 size_t FirstNonDigit = StringRef::npos;519 if (Expr.starts_with("0x")) {520 FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);521 if (FirstNonDigit == StringRef::npos)522 FirstNonDigit = Expr.size();523 } else {524 FirstNonDigit = Expr.find_first_not_of("0123456789");525 if (FirstNonDigit == StringRef::npos)526 FirstNonDigit = Expr.size();527 }528 return std::make_pair(Expr.substr(0, FirstNonDigit),529 Expr.substr(FirstNonDigit));530 }531 532 // Evaluate a constant numeric expression (hexadecimal or decimal) and533 // return a pair containing the result, and the expression remaining to be534 // evaluated.535 std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {536 StringRef ValueStr;537 StringRef RemainingExpr;538 std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);539 540 if (ValueStr.empty() || !isdigit(ValueStr[0]))541 return std::make_pair(542 unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), "");543 uint64_t Value;544 ValueStr.getAsInteger(0, Value);545 return std::make_pair(EvalResult(Value), RemainingExpr);546 }547 548 // Evaluate an expression of the form "(<expr>)" and return a pair549 // containing the result of evaluating <expr>, plus the expression550 // remaining to be parsed.551 std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr,552 ParseContext PCtx) const {553 assert(Expr.starts_with("(") && "Not a parenthesized expression");554 EvalResult SubExprResult;555 StringRef RemainingExpr;556 std::tie(SubExprResult, RemainingExpr) =557 evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx);558 if (SubExprResult.hasError())559 return std::make_pair(SubExprResult, "");560 if (!RemainingExpr.starts_with(")"))561 return std::make_pair(562 unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");563 RemainingExpr = RemainingExpr.substr(1).ltrim();564 return std::make_pair(SubExprResult, RemainingExpr);565 }566 567 // Evaluate an expression in one of the following forms:568 // *{<number>}<expr>569 // Return a pair containing the result, plus the expression remaining to be570 // parsed.571 std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {572 assert(Expr.starts_with("*") && "Not a load expression");573 StringRef RemainingExpr = Expr.substr(1).ltrim();574 575 // Parse read size.576 if (!RemainingExpr.starts_with("{"))577 return std::make_pair(EvalResult("Expected '{' following '*'."), "");578 RemainingExpr = RemainingExpr.substr(1).ltrim();579 EvalResult ReadSizeExpr;580 std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);581 if (ReadSizeExpr.hasError())582 return std::make_pair(ReadSizeExpr, RemainingExpr);583 uint64_t ReadSize = ReadSizeExpr.getValue();584 if (ReadSize < 1 || ReadSize > 8)585 return std::make_pair(EvalResult("Invalid size for dereference."), "");586 if (!RemainingExpr.starts_with("}"))587 return std::make_pair(EvalResult("Missing '}' for dereference."), "");588 RemainingExpr = RemainingExpr.substr(1).ltrim();589 590 // Evaluate the expression representing the load address.591 ParseContext LoadCtx(true);592 EvalResult LoadAddrExprResult;593 std::tie(LoadAddrExprResult, RemainingExpr) =594 evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx);595 596 if (LoadAddrExprResult.hasError())597 return std::make_pair(LoadAddrExprResult, "");598 599 uint64_t LoadAddr = LoadAddrExprResult.getValue();600 601 // If there is no error but the content pointer is null then this is a602 // zero-fill symbol/section.603 if (LoadAddr == 0)604 return std::make_pair(0, RemainingExpr);605 606 return std::make_pair(607 EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),608 RemainingExpr);609 }610 611 // Evaluate a "simple" expression. This is any expression that _isn't_ an612 // un-parenthesized binary expression.613 //614 // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.615 //616 // Returns a pair containing the result of the evaluation, plus the617 // expression remaining to be parsed.618 std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr,619 ParseContext PCtx) const {620 EvalResult SubExprResult;621 StringRef RemainingExpr;622 623 if (Expr.empty())624 return std::make_pair(EvalResult("Unexpected end of expression"), "");625 626 if (Expr[0] == '(')627 std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx);628 else if (Expr[0] == '*')629 std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);630 else if (isalpha(Expr[0]) || Expr[0] == '_')631 std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);632 else if (isdigit(Expr[0]))633 std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);634 else635 return std::make_pair(636 unexpectedToken(Expr, Expr,637 "expected '(', '*', identifier, or number"), "");638 639 if (SubExprResult.hasError())640 return std::make_pair(SubExprResult, RemainingExpr);641 642 // Evaluate bit-slice if present.643 if (RemainingExpr.starts_with("["))644 std::tie(SubExprResult, RemainingExpr) =645 evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));646 647 return std::make_pair(SubExprResult, RemainingExpr);648 }649 650 // Evaluate a bit-slice of an expression.651 // A bit-slice has the form "<expr>[high:low]". The result of evaluating a652 // slice is the bits between high and low (inclusive) in the original653 // expression, right shifted so that the "low" bit is in position 0 in the654 // result.655 // Returns a pair containing the result of the slice operation, plus the656 // expression remaining to be parsed.657 std::pair<EvalResult, StringRef>658 evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const {659 EvalResult SubExprResult;660 StringRef RemainingExpr;661 std::tie(SubExprResult, RemainingExpr) = Ctx;662 663 assert(RemainingExpr.starts_with("[") && "Not a slice expr.");664 RemainingExpr = RemainingExpr.substr(1).ltrim();665 666 EvalResult HighBitExpr;667 std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);668 669 if (HighBitExpr.hasError())670 return std::make_pair(HighBitExpr, RemainingExpr);671 672 if (!RemainingExpr.starts_with(":"))673 return std::make_pair(674 unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");675 RemainingExpr = RemainingExpr.substr(1).ltrim();676 677 EvalResult LowBitExpr;678 std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);679 680 if (LowBitExpr.hasError())681 return std::make_pair(LowBitExpr, RemainingExpr);682 683 if (!RemainingExpr.starts_with("]"))684 return std::make_pair(685 unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");686 RemainingExpr = RemainingExpr.substr(1).ltrim();687 688 unsigned HighBit = HighBitExpr.getValue();689 unsigned LowBit = LowBitExpr.getValue();690 uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1;691 uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask;692 return std::make_pair(EvalResult(SlicedValue), RemainingExpr);693 }694 695 // Evaluate a "complex" expression.696 // Takes an already evaluated subexpression and checks for the presence of a697 // binary operator, computing the result of the binary operation if one is698 // found. Used to make arithmetic expressions left-associative.699 // Returns a pair containing the ultimate result of evaluating the700 // expression, plus the expression remaining to be evaluated.701 std::pair<EvalResult, StringRef>702 evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining,703 ParseContext PCtx) const {704 EvalResult LHSResult;705 StringRef RemainingExpr;706 std::tie(LHSResult, RemainingExpr) = LHSAndRemaining;707 708 // If there was an error, or there's nothing left to evaluate, return the709 // result.710 if (LHSResult.hasError() || RemainingExpr == "")711 return std::make_pair(LHSResult, RemainingExpr);712 713 // Otherwise check if this is a binary expression.714 BinOpToken BinOp;715 std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);716 717 // If this isn't a recognized expression just return.718 if (BinOp == BinOpToken::Invalid)719 return std::make_pair(LHSResult, RemainingExpr);720 721 // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.722 EvalResult RHSResult;723 std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);724 725 // If there was an error evaluating the RHS, return it.726 if (RHSResult.hasError())727 return std::make_pair(RHSResult, RemainingExpr);728 729 // This is a binary expression - evaluate and try to continue as a730 // complex expr.731 EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));732 733 return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);734 }735 736 bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size,737 int64_t Offset) const {738 auto TT = Checker.getTripleForSymbol(Checker.getTargetFlag(Symbol));739 auto TI = getTargetInfo(TT, Checker.getCPU(), Checker.getFeatures());740 741 if (auto E = TI.takeError()) {742 errs() << "Error obtaining disassembler: " << toString(std::move(E))743 << "\n";744 return false;745 }746 747 StringRef SymbolMem = Checker.getSymbolContent(Symbol);748 ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin() + Offset,749 SymbolMem.size() - Offset);750 751 MCDisassembler::DecodeStatus S =752 TI->Disassembler->getInstruction(Inst, Size, SymbolBytes, 0, nulls());753 754 return (S == MCDisassembler::Success);755 }756 757 Expected<TargetInfo> getTargetInfo(const Triple &TT, const StringRef &CPU,758 const SubtargetFeatures &TF) const {759 std::string ErrorStr;760 const Target *TheTarget = TargetRegistry::lookupTarget(TT, ErrorStr);761 if (!TheTarget)762 return make_error<StringError>("Error accessing target '" + TT.str() +763 "': " + ErrorStr,764 inconvertibleErrorCode());765 766 std::unique_ptr<MCSubtargetInfo> STI(767 TheTarget->createMCSubtargetInfo(TT, CPU, TF.getString()));768 if (!STI)769 return make_error<StringError>("Unable to create subtarget for " +770 TT.str(),771 inconvertibleErrorCode());772 773 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));774 if (!MRI)775 return make_error<StringError>("Unable to create target register info "776 "for " +777 TT.str(),778 inconvertibleErrorCode());779 780 MCTargetOptions MCOptions;781 std::unique_ptr<MCAsmInfo> MAI(782 TheTarget->createMCAsmInfo(*MRI, TT, MCOptions));783 if (!MAI)784 return make_error<StringError>("Unable to create target asm info " +785 TT.str(),786 inconvertibleErrorCode());787 788 auto Ctx = std::make_unique<MCContext>(Triple(TT.str()), MAI.get(),789 MRI.get(), STI.get());790 791 std::unique_ptr<MCDisassembler> Disassembler(792 TheTarget->createMCDisassembler(*STI, *Ctx));793 if (!Disassembler)794 return make_error<StringError>("Unable to create disassembler for " +795 TT.str(),796 inconvertibleErrorCode());797 798 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());799 if (!MII)800 return make_error<StringError>("Unable to create instruction info for" +801 TT.str(),802 inconvertibleErrorCode());803 804 std::unique_ptr<MCInstPrinter> InstPrinter(805 TheTarget->createMCInstPrinter(TT, 0, *MAI, *MII, *MRI));806 if (!InstPrinter)807 return make_error<StringError>(808 "Unable to create instruction printer for" + TT.str(),809 inconvertibleErrorCode());810 811 return TargetInfo({TheTarget, std::move(STI), std::move(MRI),812 std::move(MAI), std::move(Ctx), std::move(Disassembler),813 std::move(MII), std::move(InstPrinter)});814 }815};816} // namespace llvm817 818RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(819 IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,820 GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,821 GetGOTInfoFunction GetGOTInfo, llvm::endianness Endianness, Triple TT,822 StringRef CPU, SubtargetFeatures TF, raw_ostream &ErrStream)823 : IsSymbolValid(std::move(IsSymbolValid)),824 GetSymbolInfo(std::move(GetSymbolInfo)),825 GetSectionInfo(std::move(GetSectionInfo)),826 GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)),827 Endianness(Endianness), TT(std::move(TT)), CPU(std::move(CPU)),828 TF(std::move(TF)), ErrStream(ErrStream) {}829 830bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const {831 CheckExpr = CheckExpr.trim();832 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr833 << "'...\n");834 RuntimeDyldCheckerExprEval P(*this, ErrStream);835 bool Result = P.evaluate(CheckExpr);836 (void)Result;837 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "838 << (Result ? "passed" : "FAILED") << ".\n");839 return Result;840}841 842bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,843 MemoryBuffer *MemBuf) const {844 bool DidAllTestsPass = true;845 unsigned NumRules = 0;846 847 std::string CheckExpr;848 const char *LineStart = MemBuf->getBufferStart();849 850 // Eat whitespace.851 while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))852 ++LineStart;853 854 while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') {855 const char *LineEnd = LineStart;856 while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&857 *LineEnd != '\n')858 ++LineEnd;859 860 StringRef Line(LineStart, LineEnd - LineStart);861 if (Line.starts_with(RulePrefix))862 CheckExpr += Line.substr(RulePrefix.size()).str();863 864 // If there's a check expr string...865 if (!CheckExpr.empty()) {866 // ... and it's complete then run it, otherwise remove the trailer '\'.867 if (CheckExpr.back() != '\\') {868 DidAllTestsPass &= check(CheckExpr);869 CheckExpr.clear();870 ++NumRules;871 } else872 CheckExpr.pop_back();873 }874 875 // Eat whitespace.876 LineStart = LineEnd;877 while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))878 ++LineStart;879 }880 return DidAllTestsPass && (NumRules != 0);881}882 883bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {884 return IsSymbolValid(Symbol);885}886 887uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const {888 auto SymInfo = GetSymbolInfo(Symbol);889 if (!SymInfo) {890 logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");891 return 0;892 }893 894 if (SymInfo->isZeroFill())895 return 0;896 897 return static_cast<uint64_t>(898 reinterpret_cast<uintptr_t>(SymInfo->getContent().data()));899}900 901uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {902 auto SymInfo = GetSymbolInfo(Symbol);903 if (!SymInfo) {904 logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");905 return 0;906 }907 908 return SymInfo->getTargetAddress();909}910 911uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr,912 unsigned Size) const {913 uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr);914 assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range.");915 void *Ptr = reinterpret_cast<void*>(PtrSizedAddr);916 917 switch (Size) {918 case 1:919 return support::endian::read<uint8_t>(Ptr, Endianness);920 case 2:921 return support::endian::read<uint16_t>(Ptr, Endianness);922 case 4:923 return support::endian::read<uint32_t>(Ptr, Endianness);924 case 8:925 return support::endian::read<uint64_t>(Ptr, Endianness);926 }927 llvm_unreachable("Unsupported read size");928}929 930StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {931 auto SymInfo = GetSymbolInfo(Symbol);932 if (!SymInfo) {933 logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");934 return StringRef();935 }936 return {SymInfo->getContent().data(), SymInfo->getContent().size()};937}938 939TargetFlagsType RuntimeDyldCheckerImpl::getTargetFlag(StringRef Symbol) const {940 auto SymInfo = GetSymbolInfo(Symbol);941 if (!SymInfo) {942 logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");943 return TargetFlagsType{};944 }945 return SymInfo->getTargetFlags();946}947 948Triple949RuntimeDyldCheckerImpl::getTripleForSymbol(TargetFlagsType Flag) const {950 Triple TheTriple = TT;951 952 switch (TT.getArch()) {953 case Triple::ArchType::arm:954 if (~Flag & 0x1)955 return TT;956 TheTriple.setArchName((Twine("thumb") + TT.getArchName().substr(3)).str());957 return TheTriple;958 case Triple::ArchType::thumb:959 if (Flag & 0x1)960 return TT;961 TheTriple.setArchName((Twine("arm") + TT.getArchName().substr(5)).str());962 return TheTriple;963 964 default:965 return TT;966 }967}968 969std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(970 StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {971 972 auto SecInfo = GetSectionInfo(FileName, SectionName);973 if (!SecInfo) {974 std::string ErrMsg;975 {976 raw_string_ostream ErrMsgStream(ErrMsg);977 logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream,978 "RTDyldChecker: ");979 }980 return std::make_pair(0, std::move(ErrMsg));981 }982 983 // If this address is being looked up in "load" mode, return the content984 // pointer, otherwise return the target address.985 986 uint64_t Addr = 0;987 988 if (IsInsideLoad) {989 if (SecInfo->isZeroFill())990 Addr = 0;991 else992 Addr = pointerToJITTargetAddress(SecInfo->getContent().data());993 } else994 Addr = SecInfo->getTargetAddress();995 996 return std::make_pair(Addr, "");997}998 999std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(1000 StringRef StubContainerName, StringRef SymbolName, StringRef StubKindFilter,1001 bool IsInsideLoad, bool IsStubAddr) const {1002 1003 assert((StubKindFilter.empty() || IsStubAddr) &&1004 "Kind name filter only supported for stubs");1005 auto StubInfo =1006 IsStubAddr ? GetStubInfo(StubContainerName, SymbolName, StubKindFilter)1007 : GetGOTInfo(StubContainerName, SymbolName);1008 1009 if (!StubInfo) {1010 std::string ErrMsg;1011 {1012 raw_string_ostream ErrMsgStream(ErrMsg);1013 logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream,1014 "RTDyldChecker: ");1015 }1016 return std::make_pair((uint64_t)0, std::move(ErrMsg));1017 }1018 1019 uint64_t Addr = 0;1020 1021 if (IsInsideLoad) {1022 if (StubInfo->isZeroFill())1023 return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");1024 Addr = pointerToJITTargetAddress(StubInfo->getContent().data());1025 } else1026 Addr = StubInfo->getTargetAddress();1027 1028 return std::make_pair(Addr, "");1029}1030 1031RuntimeDyldChecker::RuntimeDyldChecker(1032 IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,1033 GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,1034 GetGOTInfoFunction GetGOTInfo, llvm::endianness Endianness, Triple TT,1035 StringRef CPU, SubtargetFeatures TF, raw_ostream &ErrStream)1036 : Impl(::std::make_unique<RuntimeDyldCheckerImpl>(1037 std::move(IsSymbolValid), std::move(GetSymbolInfo),1038 std::move(GetSectionInfo), std::move(GetStubInfo),1039 std::move(GetGOTInfo), Endianness, std::move(TT), std::move(CPU),1040 std::move(TF), ErrStream)) {}1041 1042RuntimeDyldChecker::~RuntimeDyldChecker() = default;1043 1044bool RuntimeDyldChecker::check(StringRef CheckExpr) const {1045 return Impl->check(CheckExpr);1046}1047 1048bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,1049 MemoryBuffer *MemBuf) const {1050 return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);1051}1052 1053std::pair<uint64_t, std::string>1054RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName,1055 bool LocalAddress) {1056 return Impl->getSectionAddr(FileName, SectionName, LocalAddress);1057}1058