| //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/ExecutionEngine/RuntimeDyldChecker.h" | 
 | #include "RuntimeDyldCheckerImpl.h" | 
 | #include "RuntimeDyldImpl.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/MC/MCContext.h" | 
 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" | 
 | #include "llvm/MC/MCInst.h" | 
 | #include "llvm/Support/Path.h" | 
 | #include <cctype> | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #define DEBUG_TYPE "rtdyld" | 
 |  | 
 | using namespace llvm; | 
 |  | 
 | namespace llvm { | 
 |  | 
 | // Helper class that implements the language evaluated by RuntimeDyldChecker. | 
 | class RuntimeDyldCheckerExprEval { | 
 | public: | 
 |   RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, | 
 |                              raw_ostream &ErrStream) | 
 |       : Checker(Checker) {} | 
 |  | 
 |   bool evaluate(StringRef Expr) const { | 
 |     // Expect equality expression of the form 'LHS = RHS'. | 
 |     Expr = Expr.trim(); | 
 |     size_t EQIdx = Expr.find('='); | 
 |  | 
 |     ParseContext OutsideLoad(false); | 
 |  | 
 |     // Evaluate LHS. | 
 |     StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); | 
 |     StringRef RemainingExpr; | 
 |     EvalResult LHSResult; | 
 |     std::tie(LHSResult, RemainingExpr) = | 
 |         evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad); | 
 |     if (LHSResult.hasError()) | 
 |       return handleError(Expr, LHSResult); | 
 |     if (RemainingExpr != "") | 
 |       return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, "")); | 
 |  | 
 |     // Evaluate RHS. | 
 |     StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim(); | 
 |     EvalResult RHSResult; | 
 |     std::tie(RHSResult, RemainingExpr) = | 
 |         evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad); | 
 |     if (RHSResult.hasError()) | 
 |       return handleError(Expr, RHSResult); | 
 |     if (RemainingExpr != "") | 
 |       return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); | 
 |  | 
 |     if (LHSResult.getValue() != RHSResult.getValue()) { | 
 |       Checker.ErrStream << "Expression '" << Expr << "' is false: " | 
 |                         << format("0x%" PRIx64, LHSResult.getValue()) | 
 |                         << " != " << format("0x%" PRIx64, RHSResult.getValue()) | 
 |                         << "\n"; | 
 |       return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 | private: | 
 |   // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In | 
 |   // particular, it needs to know whether a symbol is being evaluated in the | 
 |   // context of a load, in which case we want the linker's local address for | 
 |   // the symbol, or outside of a load, in which case we want the symbol's | 
 |   // address in the remote target. | 
 |  | 
 |   struct ParseContext { | 
 |     bool IsInsideLoad; | 
 |     ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {} | 
 |   }; | 
 |  | 
 |   const RuntimeDyldCheckerImpl &Checker; | 
 |  | 
 |   enum class BinOpToken : unsigned { | 
 |     Invalid, | 
 |     Add, | 
 |     Sub, | 
 |     BitwiseAnd, | 
 |     BitwiseOr, | 
 |     ShiftLeft, | 
 |     ShiftRight | 
 |   }; | 
 |  | 
 |   class EvalResult { | 
 |   public: | 
 |     EvalResult() : Value(0), ErrorMsg("") {} | 
 |     EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {} | 
 |     EvalResult(std::string ErrorMsg) | 
 |         : Value(0), ErrorMsg(std::move(ErrorMsg)) {} | 
 |     uint64_t getValue() const { return Value; } | 
 |     bool hasError() const { return ErrorMsg != ""; } | 
 |     const std::string &getErrorMsg() const { return ErrorMsg; } | 
 |  | 
 |   private: | 
 |     uint64_t Value; | 
 |     std::string ErrorMsg; | 
 |   }; | 
 |  | 
 |   StringRef getTokenForError(StringRef Expr) const { | 
 |     if (Expr.empty()) | 
 |       return ""; | 
 |  | 
 |     StringRef Token, Remaining; | 
 |     if (isalpha(Expr[0])) | 
 |       std::tie(Token, Remaining) = parseSymbol(Expr); | 
 |     else if (isdigit(Expr[0])) | 
 |       std::tie(Token, Remaining) = parseNumberString(Expr); | 
 |     else { | 
 |       unsigned TokLen = 1; | 
 |       if (Expr.startswith("<<") || Expr.startswith(">>")) | 
 |         TokLen = 2; | 
 |       Token = Expr.substr(0, TokLen); | 
 |     } | 
 |     return Token; | 
 |   } | 
 |  | 
 |   EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr, | 
 |                              StringRef ErrText) const { | 
 |     std::string ErrorMsg("Encountered unexpected token '"); | 
 |     ErrorMsg += getTokenForError(TokenStart); | 
 |     if (SubExpr != "") { | 
 |       ErrorMsg += "' while parsing subexpression '"; | 
 |       ErrorMsg += SubExpr; | 
 |     } | 
 |     ErrorMsg += "'"; | 
 |     if (ErrText != "") { | 
 |       ErrorMsg += " "; | 
 |       ErrorMsg += ErrText; | 
 |     } | 
 |     return EvalResult(std::move(ErrorMsg)); | 
 |   } | 
 |  | 
 |   bool handleError(StringRef Expr, const EvalResult &R) const { | 
 |     assert(R.hasError() && "Not an error result."); | 
 |     Checker.ErrStream << "Error evaluating expression '" << Expr | 
 |                       << "': " << R.getErrorMsg() << "\n"; | 
 |     return false; | 
 |   } | 
 |  | 
 |   std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const { | 
 |     if (Expr.empty()) | 
 |       return std::make_pair(BinOpToken::Invalid, ""); | 
 |  | 
 |     // Handle the two 2-character tokens. | 
 |     if (Expr.startswith("<<")) | 
 |       return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim()); | 
 |     if (Expr.startswith(">>")) | 
 |       return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim()); | 
 |  | 
 |     // Handle one-character tokens. | 
 |     BinOpToken Op; | 
 |     switch (Expr[0]) { | 
 |     default: | 
 |       return std::make_pair(BinOpToken::Invalid, Expr); | 
 |     case '+': | 
 |       Op = BinOpToken::Add; | 
 |       break; | 
 |     case '-': | 
 |       Op = BinOpToken::Sub; | 
 |       break; | 
 |     case '&': | 
 |       Op = BinOpToken::BitwiseAnd; | 
 |       break; | 
 |     case '|': | 
 |       Op = BinOpToken::BitwiseOr; | 
 |       break; | 
 |     } | 
 |  | 
 |     return std::make_pair(Op, Expr.substr(1).ltrim()); | 
 |   } | 
 |  | 
 |   EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult, | 
 |                                 const EvalResult &RHSResult) const { | 
 |     switch (Op) { | 
 |     default: | 
 |       llvm_unreachable("Tried to evaluate unrecognized operation."); | 
 |     case BinOpToken::Add: | 
 |       return EvalResult(LHSResult.getValue() + RHSResult.getValue()); | 
 |     case BinOpToken::Sub: | 
 |       return EvalResult(LHSResult.getValue() - RHSResult.getValue()); | 
 |     case BinOpToken::BitwiseAnd: | 
 |       return EvalResult(LHSResult.getValue() & RHSResult.getValue()); | 
 |     case BinOpToken::BitwiseOr: | 
 |       return EvalResult(LHSResult.getValue() | RHSResult.getValue()); | 
 |     case BinOpToken::ShiftLeft: | 
 |       return EvalResult(LHSResult.getValue() << RHSResult.getValue()); | 
 |     case BinOpToken::ShiftRight: | 
 |       return EvalResult(LHSResult.getValue() >> RHSResult.getValue()); | 
 |     } | 
 |   } | 
 |  | 
 |   // Parse a symbol and return a (string, string) pair representing the symbol | 
 |   // name and expression remaining to be parsed. | 
 |   std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const { | 
 |     size_t FirstNonSymbol = Expr.find_first_not_of("0123456789" | 
 |                                                    "abcdefghijklmnopqrstuvwxyz" | 
 |                                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | 
 |                                                    ":_.$"); | 
 |     return std::make_pair(Expr.substr(0, FirstNonSymbol), | 
 |                           Expr.substr(FirstNonSymbol).ltrim()); | 
 |   } | 
 |  | 
 |   // Evaluate a call to decode_operand. Decode the instruction operand at the | 
 |   // given symbol and get the value of the requested operand. | 
 |   // Returns an error if the instruction cannot be decoded, or the requested | 
 |   // operand is not an immediate. | 
 |   // On success, returns a pair containing the value of the operand, plus | 
 |   // the expression remaining to be evaluated. | 
 |   std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const { | 
 |     if (!Expr.startswith("(")) | 
 |       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); | 
 |     StringRef RemainingExpr = Expr.substr(1).ltrim(); | 
 |     StringRef Symbol; | 
 |     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); | 
 |  | 
 |     if (!Checker.isSymbolValid(Symbol)) | 
 |       return std::make_pair( | 
 |           EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), | 
 |           ""); | 
 |  | 
 |     if (!RemainingExpr.startswith(",")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     EvalResult OpIdxExpr; | 
 |     std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); | 
 |     if (OpIdxExpr.hasError()) | 
 |       return std::make_pair(OpIdxExpr, ""); | 
 |  | 
 |     if (!RemainingExpr.startswith(")")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     MCInst Inst; | 
 |     uint64_t Size; | 
 |     if (!decodeInst(Symbol, Inst, Size)) | 
 |       return std::make_pair( | 
 |           EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), | 
 |           ""); | 
 |  | 
 |     unsigned OpIdx = OpIdxExpr.getValue(); | 
 |     if (OpIdx >= Inst.getNumOperands()) { | 
 |       std::string ErrMsg; | 
 |       raw_string_ostream ErrMsgStream(ErrMsg); | 
 |       ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx) | 
 |                    << "' for instruction '" << Symbol | 
 |                    << "'. Instruction has only " | 
 |                    << format("%i", Inst.getNumOperands()) | 
 |                    << " operands.\nInstruction is:\n  "; | 
 |       Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); | 
 |       return std::make_pair(EvalResult(ErrMsgStream.str()), ""); | 
 |     } | 
 |  | 
 |     const MCOperand &Op = Inst.getOperand(OpIdx); | 
 |     if (!Op.isImm()) { | 
 |       std::string ErrMsg; | 
 |       raw_string_ostream ErrMsgStream(ErrMsg); | 
 |       ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '" | 
 |                    << Symbol << "' is not an immediate.\nInstruction is:\n  "; | 
 |       Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); | 
 |  | 
 |       return std::make_pair(EvalResult(ErrMsgStream.str()), ""); | 
 |     } | 
 |  | 
 |     return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate a call to next_pc. | 
 |   // Decode the instruction at the given symbol and return the following program | 
 |   // counter. | 
 |   // Returns an error if the instruction cannot be decoded. | 
 |   // On success, returns a pair containing the next PC, plus of the | 
 |   // expression remaining to be evaluated. | 
 |   std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr, | 
 |                                               ParseContext PCtx) const { | 
 |     if (!Expr.startswith("(")) | 
 |       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); | 
 |     StringRef RemainingExpr = Expr.substr(1).ltrim(); | 
 |     StringRef Symbol; | 
 |     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); | 
 |  | 
 |     if (!Checker.isSymbolValid(Symbol)) | 
 |       return std::make_pair( | 
 |           EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), | 
 |           ""); | 
 |  | 
 |     if (!RemainingExpr.startswith(")")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     MCInst Inst; | 
 |     uint64_t InstSize; | 
 |     if (!decodeInst(Symbol, Inst, InstSize)) | 
 |       return std::make_pair( | 
 |           EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), | 
 |           ""); | 
 |  | 
 |     uint64_t SymbolAddr = PCtx.IsInsideLoad | 
 |                               ? Checker.getSymbolLocalAddr(Symbol) | 
 |                               : Checker.getSymbolRemoteAddr(Symbol); | 
 |     uint64_t NextPC = SymbolAddr + InstSize; | 
 |  | 
 |     return std::make_pair(EvalResult(NextPC), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate a call to stub_addr. | 
 |   // Look up and return the address of the stub for the given | 
 |   // (<file name>, <section name>, <symbol name>) tuple. | 
 |   // On success, returns a pair containing the stub address, plus the expression | 
 |   // remaining to be evaluated. | 
 |   std::pair<EvalResult, StringRef> evalStubAddr(StringRef Expr, | 
 |                                                 ParseContext PCtx) const { | 
 |     if (!Expr.startswith("(")) | 
 |       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); | 
 |     StringRef RemainingExpr = Expr.substr(1).ltrim(); | 
 |  | 
 |     // Handle file-name specially, as it may contain characters that aren't | 
 |     // legal for symbols. | 
 |     StringRef FileName; | 
 |     size_t ComaIdx = RemainingExpr.find(','); | 
 |     FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); | 
 |     RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); | 
 |  | 
 |     if (!RemainingExpr.startswith(",")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     StringRef SectionName; | 
 |     std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); | 
 |  | 
 |     if (!RemainingExpr.startswith(",")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     StringRef Symbol; | 
 |     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); | 
 |  | 
 |     if (!RemainingExpr.startswith(")")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     uint64_t StubAddr; | 
 |     std::string ErrorMsg = ""; | 
 |     std::tie(StubAddr, ErrorMsg) = Checker.getStubAddrFor( | 
 |         FileName, SectionName, Symbol, PCtx.IsInsideLoad); | 
 |  | 
 |     if (ErrorMsg != "") | 
 |       return std::make_pair(EvalResult(ErrorMsg), ""); | 
 |  | 
 |     return std::make_pair(EvalResult(StubAddr), RemainingExpr); | 
 |   } | 
 |  | 
 |   std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr, | 
 |                                                    ParseContext PCtx) const { | 
 |     if (!Expr.startswith("(")) | 
 |       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); | 
 |     StringRef RemainingExpr = Expr.substr(1).ltrim(); | 
 |  | 
 |     // Handle file-name specially, as it may contain characters that aren't | 
 |     // legal for symbols. | 
 |     StringRef FileName; | 
 |     size_t ComaIdx = RemainingExpr.find(','); | 
 |     FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); | 
 |     RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); | 
 |  | 
 |     if (!RemainingExpr.startswith(",")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     StringRef SectionName; | 
 |     std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); | 
 |  | 
 |     if (!RemainingExpr.startswith(")")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     uint64_t StubAddr; | 
 |     std::string ErrorMsg = ""; | 
 |     std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr( | 
 |         FileName, SectionName, PCtx.IsInsideLoad); | 
 |  | 
 |     if (ErrorMsg != "") | 
 |       return std::make_pair(EvalResult(ErrorMsg), ""); | 
 |  | 
 |     return std::make_pair(EvalResult(StubAddr), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate an identiefer expr, which may be a symbol, or a call to | 
 |   // one of the builtin functions: get_insn_opcode or get_insn_length. | 
 |   // Return the result, plus the expression remaining to be parsed. | 
 |   std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr, | 
 |                                                       ParseContext PCtx) const { | 
 |     StringRef Symbol; | 
 |     StringRef RemainingExpr; | 
 |     std::tie(Symbol, RemainingExpr) = parseSymbol(Expr); | 
 |  | 
 |     // Check for builtin function calls. | 
 |     if (Symbol == "decode_operand") | 
 |       return evalDecodeOperand(RemainingExpr); | 
 |     else if (Symbol == "next_pc") | 
 |       return evalNextPC(RemainingExpr, PCtx); | 
 |     else if (Symbol == "stub_addr") | 
 |       return evalStubAddr(RemainingExpr, PCtx); | 
 |     else if (Symbol == "section_addr") | 
 |       return evalSectionAddr(RemainingExpr, PCtx); | 
 |  | 
 |     if (!Checker.isSymbolValid(Symbol)) { | 
 |       std::string ErrMsg("No known address for symbol '"); | 
 |       ErrMsg += Symbol; | 
 |       ErrMsg += "'"; | 
 |       if (Symbol.startswith("L")) | 
 |         ErrMsg += " (this appears to be an assembler local label - " | 
 |                   " perhaps drop the 'L'?)"; | 
 |  | 
 |       return std::make_pair(EvalResult(ErrMsg), ""); | 
 |     } | 
 |  | 
 |     // The value for the symbol depends on the context we're evaluating in: | 
 |     // Inside a load this is the address in the linker's memory, outside a | 
 |     // load it's the address in the target processes memory. | 
 |     uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol) | 
 |                                        : Checker.getSymbolRemoteAddr(Symbol); | 
 |  | 
 |     // Looks like a plain symbol reference. | 
 |     return std::make_pair(EvalResult(Value), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Parse a number (hexadecimal or decimal) and return a (string, string) | 
 |   // pair representing the number and the expression remaining to be parsed. | 
 |   std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const { | 
 |     size_t FirstNonDigit = StringRef::npos; | 
 |     if (Expr.startswith("0x")) { | 
 |       FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2); | 
 |       if (FirstNonDigit == StringRef::npos) | 
 |         FirstNonDigit = Expr.size(); | 
 |     } else { | 
 |       FirstNonDigit = Expr.find_first_not_of("0123456789"); | 
 |       if (FirstNonDigit == StringRef::npos) | 
 |         FirstNonDigit = Expr.size(); | 
 |     } | 
 |     return std::make_pair(Expr.substr(0, FirstNonDigit), | 
 |                           Expr.substr(FirstNonDigit)); | 
 |   } | 
 |  | 
 |   // Evaluate a constant numeric expression (hexadecimal or decimal) and | 
 |   // return a pair containing the result, and the expression remaining to be | 
 |   // evaluated. | 
 |   std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const { | 
 |     StringRef ValueStr; | 
 |     StringRef RemainingExpr; | 
 |     std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr); | 
 |  | 
 |     if (ValueStr.empty() || !isdigit(ValueStr[0])) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), ""); | 
 |     uint64_t Value; | 
 |     ValueStr.getAsInteger(0, Value); | 
 |     return std::make_pair(EvalResult(Value), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate an expression of the form "(<expr>)" and return a pair | 
 |   // containing the result of evaluating <expr>, plus the expression | 
 |   // remaining to be parsed. | 
 |   std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr, | 
 |                                                   ParseContext PCtx) const { | 
 |     assert(Expr.startswith("(") && "Not a parenthesized expression"); | 
 |     EvalResult SubExprResult; | 
 |     StringRef RemainingExpr; | 
 |     std::tie(SubExprResult, RemainingExpr) = | 
 |         evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx); | 
 |     if (SubExprResult.hasError()) | 
 |       return std::make_pair(SubExprResult, ""); | 
 |     if (!RemainingExpr.startswith(")")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |     return std::make_pair(SubExprResult, RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate an expression in one of the following forms: | 
 |   //   *{<number>}<expr> | 
 |   // Return a pair containing the result, plus the expression remaining to be | 
 |   // parsed. | 
 |   std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const { | 
 |     assert(Expr.startswith("*") && "Not a load expression"); | 
 |     StringRef RemainingExpr = Expr.substr(1).ltrim(); | 
 |  | 
 |     // Parse read size. | 
 |     if (!RemainingExpr.startswith("{")) | 
 |       return std::make_pair(EvalResult("Expected '{' following '*'."), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |     EvalResult ReadSizeExpr; | 
 |     std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); | 
 |     if (ReadSizeExpr.hasError()) | 
 |       return std::make_pair(ReadSizeExpr, RemainingExpr); | 
 |     uint64_t ReadSize = ReadSizeExpr.getValue(); | 
 |     if (ReadSize < 1 || ReadSize > 8) | 
 |       return std::make_pair(EvalResult("Invalid size for dereference."), ""); | 
 |     if (!RemainingExpr.startswith("}")) | 
 |       return std::make_pair(EvalResult("Missing '}' for dereference."), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     // Evaluate the expression representing the load address. | 
 |     ParseContext LoadCtx(true); | 
 |     EvalResult LoadAddrExprResult; | 
 |     std::tie(LoadAddrExprResult, RemainingExpr) = | 
 |         evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx); | 
 |  | 
 |     if (LoadAddrExprResult.hasError()) | 
 |       return std::make_pair(LoadAddrExprResult, ""); | 
 |  | 
 |     uint64_t LoadAddr = LoadAddrExprResult.getValue(); | 
 |  | 
 |     return std::make_pair( | 
 |         EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), | 
 |         RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate a "simple" expression. This is any expression that _isn't_ an | 
 |   // un-parenthesized binary expression. | 
 |   // | 
 |   // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr. | 
 |   // | 
 |   // Returns a pair containing the result of the evaluation, plus the | 
 |   // expression remaining to be parsed. | 
 |   std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr, | 
 |                                                   ParseContext PCtx) const { | 
 |     EvalResult SubExprResult; | 
 |     StringRef RemainingExpr; | 
 |  | 
 |     if (Expr.empty()) | 
 |       return std::make_pair(EvalResult("Unexpected end of expression"), ""); | 
 |  | 
 |     if (Expr[0] == '(') | 
 |       std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx); | 
 |     else if (Expr[0] == '*') | 
 |       std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); | 
 |     else if (isalpha(Expr[0]) || Expr[0] == '_') | 
 |       std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx); | 
 |     else if (isdigit(Expr[0])) | 
 |       std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); | 
 |     else | 
 |       return std::make_pair( | 
 |           unexpectedToken(Expr, Expr, | 
 |                           "expected '(', '*', identifier, or number"), ""); | 
 |  | 
 |     if (SubExprResult.hasError()) | 
 |       return std::make_pair(SubExprResult, RemainingExpr); | 
 |  | 
 |     // Evaluate bit-slice if present. | 
 |     if (RemainingExpr.startswith("[")) | 
 |       std::tie(SubExprResult, RemainingExpr) = | 
 |           evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr)); | 
 |  | 
 |     return std::make_pair(SubExprResult, RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate a bit-slice of an expression. | 
 |   // A bit-slice has the form "<expr>[high:low]". The result of evaluating a | 
 |   // slice is the bits between high and low (inclusive) in the original | 
 |   // expression, right shifted so that the "low" bit is in position 0 in the | 
 |   // result. | 
 |   // Returns a pair containing the result of the slice operation, plus the | 
 |   // expression remaining to be parsed. | 
 |   std::pair<EvalResult, StringRef> | 
 |   evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const { | 
 |     EvalResult SubExprResult; | 
 |     StringRef RemainingExpr; | 
 |     std::tie(SubExprResult, RemainingExpr) = Ctx; | 
 |  | 
 |     assert(RemainingExpr.startswith("[") && "Not a slice expr."); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     EvalResult HighBitExpr; | 
 |     std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); | 
 |  | 
 |     if (HighBitExpr.hasError()) | 
 |       return std::make_pair(HighBitExpr, RemainingExpr); | 
 |  | 
 |     if (!RemainingExpr.startswith(":")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     EvalResult LowBitExpr; | 
 |     std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); | 
 |  | 
 |     if (LowBitExpr.hasError()) | 
 |       return std::make_pair(LowBitExpr, RemainingExpr); | 
 |  | 
 |     if (!RemainingExpr.startswith("]")) | 
 |       return std::make_pair( | 
 |           unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), ""); | 
 |     RemainingExpr = RemainingExpr.substr(1).ltrim(); | 
 |  | 
 |     unsigned HighBit = HighBitExpr.getValue(); | 
 |     unsigned LowBit = LowBitExpr.getValue(); | 
 |     uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1; | 
 |     uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask; | 
 |     return std::make_pair(EvalResult(SlicedValue), RemainingExpr); | 
 |   } | 
 |  | 
 |   // Evaluate a "complex" expression. | 
 |   // Takes an already evaluated subexpression and checks for the presence of a | 
 |   // binary operator, computing the result of the binary operation if one is | 
 |   // found. Used to make arithmetic expressions left-associative. | 
 |   // Returns a pair containing the ultimate result of evaluating the | 
 |   // expression, plus the expression remaining to be evaluated. | 
 |   std::pair<EvalResult, StringRef> | 
 |   evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining, | 
 |                   ParseContext PCtx) const { | 
 |     EvalResult LHSResult; | 
 |     StringRef RemainingExpr; | 
 |     std::tie(LHSResult, RemainingExpr) = LHSAndRemaining; | 
 |  | 
 |     // If there was an error, or there's nothing left to evaluate, return the | 
 |     // result. | 
 |     if (LHSResult.hasError() || RemainingExpr == "") | 
 |       return std::make_pair(LHSResult, RemainingExpr); | 
 |  | 
 |     // Otherwise check if this is a binary expressioan. | 
 |     BinOpToken BinOp; | 
 |     std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); | 
 |  | 
 |     // If this isn't a recognized expression just return. | 
 |     if (BinOp == BinOpToken::Invalid) | 
 |       return std::make_pair(LHSResult, RemainingExpr); | 
 |  | 
 |     // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. | 
 |     EvalResult RHSResult; | 
 |     std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx); | 
 |  | 
 |     // If there was an error evaluating the RHS, return it. | 
 |     if (RHSResult.hasError()) | 
 |       return std::make_pair(RHSResult, RemainingExpr); | 
 |  | 
 |     // This is a binary expression - evaluate and try to continue as a | 
 |     // complex expr. | 
 |     EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult)); | 
 |  | 
 |     return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx); | 
 |   } | 
 |  | 
 |   bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { | 
 |     MCDisassembler *Dis = Checker.Disassembler; | 
 |     StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); | 
 |     ArrayRef<uint8_t> SectionBytes( | 
 |         reinterpret_cast<const uint8_t *>(SectionMem.data()), | 
 |         SectionMem.size()); | 
 |  | 
 |     MCDisassembler::DecodeStatus S = | 
 |         Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); | 
 |  | 
 |     return (S == MCDisassembler::Success); | 
 |   } | 
 | }; | 
 | } | 
 |  | 
 | RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, | 
 |                                                MCDisassembler *Disassembler, | 
 |                                                MCInstPrinter *InstPrinter, | 
 |                                                raw_ostream &ErrStream) | 
 |     : RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter), | 
 |       ErrStream(ErrStream) { | 
 |   RTDyld.Checker = this; | 
 | } | 
 |  | 
 | bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { | 
 |   CheckExpr = CheckExpr.trim(); | 
 |   LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr | 
 |                     << "'...\n"); | 
 |   RuntimeDyldCheckerExprEval P(*this, ErrStream); | 
 |   bool Result = P.evaluate(CheckExpr); | 
 |   (void)Result; | 
 |   LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " | 
 |                     << (Result ? "passed" : "FAILED") << ".\n"); | 
 |   return Result; | 
 | } | 
 |  | 
 | bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, | 
 |                                                    MemoryBuffer *MemBuf) const { | 
 |   bool DidAllTestsPass = true; | 
 |   unsigned NumRules = 0; | 
 |  | 
 |   const char *LineStart = MemBuf->getBufferStart(); | 
 |  | 
 |   // Eat whitespace. | 
 |   while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart)) | 
 |     ++LineStart; | 
 |  | 
 |   while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') { | 
 |     const char *LineEnd = LineStart; | 
 |     while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' && | 
 |            *LineEnd != '\n') | 
 |       ++LineEnd; | 
 |  | 
 |     StringRef Line(LineStart, LineEnd - LineStart); | 
 |     if (Line.startswith(RulePrefix)) { | 
 |       DidAllTestsPass &= check(Line.substr(RulePrefix.size())); | 
 |       ++NumRules; | 
 |     } | 
 |  | 
 |     // Eat whitespace. | 
 |     LineStart = LineEnd; | 
 |     while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart)) | 
 |       ++LineStart; | 
 |   } | 
 |   return DidAllTestsPass && (NumRules != 0); | 
 | } | 
 |  | 
 | bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { | 
 |   if (getRTDyld().getSymbol(Symbol)) | 
 |     return true; | 
 |   JITSymbolResolver::LookupSet Symbols({Symbol}); | 
 |   auto Result = getRTDyld().Resolver.lookup(Symbols); | 
 |   if (!Result) { | 
 |     logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); | 
 |     return false; | 
 |   } | 
 |   assert(Result->count(Symbol) && "Missing symbol result"); | 
 |   return true; | 
 | } | 
 |  | 
 | uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { | 
 |   return static_cast<uint64_t>( | 
 |       reinterpret_cast<uintptr_t>(getRTDyld().getSymbolLocalAddress(Symbol))); | 
 | } | 
 |  | 
 | uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { | 
 |   if (auto InternalSymbol = getRTDyld().getSymbol(Symbol)) | 
 |     return InternalSymbol.getAddress(); | 
 |  | 
 |   JITSymbolResolver::LookupSet Symbols({Symbol}); | 
 |   auto Result = getRTDyld().Resolver.lookup(Symbols); | 
 |   if (!Result) { | 
 |     logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); | 
 |     return 0; | 
 |   } | 
 |   auto I = Result->find(Symbol); | 
 |   assert(I != Result->end() && "Missing symbol result"); | 
 |   return I->second.getAddress(); | 
 | } | 
 |  | 
 | uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, | 
 |                                                   unsigned Size) const { | 
 |   uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); | 
 |   assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); | 
 |   uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr); | 
 |   return getRTDyld().readBytesUnaligned(Src, Size); | 
 | } | 
 |  | 
 |  | 
 | std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string> | 
 | RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName, | 
 |                                             StringRef SectionName) const { | 
 |  | 
 |   auto SectionMapItr = Stubs.find(FileName); | 
 |   if (SectionMapItr == Stubs.end()) { | 
 |     std::string ErrorMsg = "File '"; | 
 |     ErrorMsg += FileName; | 
 |     ErrorMsg += "' not found. "; | 
 |     if (Stubs.empty()) | 
 |       ErrorMsg += "No stubs registered."; | 
 |     else { | 
 |       ErrorMsg += "Available files are:"; | 
 |       for (const auto& StubEntry : Stubs) { | 
 |         ErrorMsg += " '"; | 
 |         ErrorMsg += StubEntry.first; | 
 |         ErrorMsg += "'"; | 
 |       } | 
 |     } | 
 |     ErrorMsg += "\n"; | 
 |     return std::make_pair(nullptr, ErrorMsg); | 
 |   } | 
 |  | 
 |   auto SectionInfoItr = SectionMapItr->second.find(SectionName); | 
 |   if (SectionInfoItr == SectionMapItr->second.end()) | 
 |     return std::make_pair(nullptr, | 
 |                           ("Section '" + SectionName + "' not found in file '" + | 
 |                            FileName + "'\n").str()); | 
 |  | 
 |   return std::make_pair(&SectionInfoItr->second, std::string("")); | 
 | } | 
 |  | 
 | std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr( | 
 |     StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { | 
 |  | 
 |   const SectionAddressInfo *SectionInfo = nullptr; | 
 |   { | 
 |     std::string ErrorMsg; | 
 |     std::tie(SectionInfo, ErrorMsg) = | 
 |       findSectionAddrInfo(FileName, SectionName); | 
 |     if (ErrorMsg != "") | 
 |       return std::make_pair(0, ErrorMsg); | 
 |   } | 
 |  | 
 |   unsigned SectionID = SectionInfo->SectionID; | 
 |   uint64_t Addr; | 
 |   if (IsInsideLoad) | 
 |     Addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>( | 
 |         getRTDyld().Sections[SectionID].getAddress())); | 
 |   else | 
 |     Addr = getRTDyld().Sections[SectionID].getLoadAddress(); | 
 |  | 
 |   return std::make_pair(Addr, std::string("")); | 
 | } | 
 |  | 
 | std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor( | 
 |     StringRef FileName, StringRef SectionName, StringRef SymbolName, | 
 |     bool IsInsideLoad) const { | 
 |  | 
 |   const SectionAddressInfo *SectionInfo = nullptr; | 
 |   { | 
 |     std::string ErrorMsg; | 
 |     std::tie(SectionInfo, ErrorMsg) = | 
 |       findSectionAddrInfo(FileName, SectionName); | 
 |     if (ErrorMsg != "") | 
 |       return std::make_pair(0, ErrorMsg); | 
 |   } | 
 |  | 
 |   unsigned SectionID = SectionInfo->SectionID; | 
 |   const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets; | 
 |   auto StubOffsetItr = SymbolStubs.find(SymbolName); | 
 |   if (StubOffsetItr == SymbolStubs.end()) | 
 |     return std::make_pair(0, | 
 |                           ("Stub for symbol '" + SymbolName + "' not found. " | 
 |                            "If '" + SymbolName + "' is an internal symbol this " | 
 |                            "may indicate that the stub target offset is being " | 
 |                            "computed incorrectly.\n").str()); | 
 |  | 
 |   uint64_t StubOffset = StubOffsetItr->second; | 
 |  | 
 |   uint64_t Addr; | 
 |   if (IsInsideLoad) { | 
 |     uintptr_t SectionBase = reinterpret_cast<uintptr_t>( | 
 |         getRTDyld().Sections[SectionID].getAddress()); | 
 |     Addr = static_cast<uint64_t>(SectionBase) + StubOffset; | 
 |   } else { | 
 |     uint64_t SectionBase = getRTDyld().Sections[SectionID].getLoadAddress(); | 
 |     Addr = SectionBase + StubOffset; | 
 |   } | 
 |  | 
 |   return std::make_pair(Addr, std::string("")); | 
 | } | 
 |  | 
 | StringRef | 
 | RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const { | 
 |   RTDyldSymbolTable::const_iterator pos = | 
 |       getRTDyld().GlobalSymbolTable.find(Name); | 
 |   if (pos == getRTDyld().GlobalSymbolTable.end()) | 
 |     return StringRef(); | 
 |   const auto &SymInfo = pos->second; | 
 |   uint8_t *SectionAddr = getRTDyld().getSectionAddress(SymInfo.getSectionID()); | 
 |   return StringRef(reinterpret_cast<const char *>(SectionAddr) + | 
 |                        SymInfo.getOffset(), | 
 |                    getRTDyld().Sections[SymInfo.getSectionID()].getSize() - | 
 |                        SymInfo.getOffset()); | 
 | } | 
 |  | 
 | Optional<uint64_t> | 
 | RuntimeDyldCheckerImpl::getSectionLoadAddress(void *LocalAddress) const { | 
 |   for (auto &S : getRTDyld().Sections) { | 
 |     if (S.getAddress() == LocalAddress) | 
 |       return S.getLoadAddress(); | 
 |   } | 
 |   return Optional<uint64_t>(); | 
 | } | 
 |  | 
 | void RuntimeDyldCheckerImpl::registerSection( | 
 |     StringRef FilePath, unsigned SectionID) { | 
 |   StringRef FileName = sys::path::filename(FilePath); | 
 |   const SectionEntry &Section = getRTDyld().Sections[SectionID]; | 
 |   StringRef SectionName = Section.getName(); | 
 |  | 
 |   Stubs[FileName][SectionName].SectionID = SectionID; | 
 | } | 
 |  | 
 | void RuntimeDyldCheckerImpl::registerStubMap( | 
 |     StringRef FilePath, unsigned SectionID, | 
 |     const RuntimeDyldImpl::StubMap &RTDyldStubs) { | 
 |   StringRef FileName = sys::path::filename(FilePath); | 
 |   const SectionEntry &Section = getRTDyld().Sections[SectionID]; | 
 |   StringRef SectionName = Section.getName(); | 
 |  | 
 |   Stubs[FileName][SectionName].SectionID = SectionID; | 
 |  | 
 |   for (auto &StubMapEntry : RTDyldStubs) { | 
 |     std::string SymbolName = ""; | 
 |  | 
 |     if (StubMapEntry.first.SymbolName) | 
 |       SymbolName = StubMapEntry.first.SymbolName; | 
 |     else { | 
 |       // If this is a (Section, Offset) pair, do a reverse lookup in the | 
 |       // global symbol table to find the name. | 
 |       for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) { | 
 |         const auto &SymInfo = GSTEntry.second; | 
 |         if (SymInfo.getSectionID() == StubMapEntry.first.SectionID && | 
 |             SymInfo.getOffset() == | 
 |               static_cast<uint64_t>(StubMapEntry.first.Offset)) { | 
 |           SymbolName = GSTEntry.first(); | 
 |           break; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     if (SymbolName != "") | 
 |       Stubs[FileName][SectionName].StubOffsets[SymbolName] = | 
 |         StubMapEntry.second; | 
 |   } | 
 | } | 
 |  | 
 | RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld, | 
 |                                        MCDisassembler *Disassembler, | 
 |                                        MCInstPrinter *InstPrinter, | 
 |                                        raw_ostream &ErrStream) | 
 |     : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler, | 
 |                                                InstPrinter, ErrStream)) {} | 
 |  | 
 | RuntimeDyldChecker::~RuntimeDyldChecker() {} | 
 |  | 
 | RuntimeDyld& RuntimeDyldChecker::getRTDyld() { | 
 |   return Impl->RTDyld; | 
 | } | 
 |  | 
 | const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const { | 
 |   return Impl->RTDyld; | 
 | } | 
 |  | 
 | bool RuntimeDyldChecker::check(StringRef CheckExpr) const { | 
 |   return Impl->check(CheckExpr); | 
 | } | 
 |  | 
 | bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, | 
 |                                                MemoryBuffer *MemBuf) const { | 
 |   return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf); | 
 | } | 
 |  | 
 | std::pair<uint64_t, std::string> | 
 | RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, | 
 |                                    bool LocalAddress) { | 
 |   return Impl->getSectionAddr(FileName, SectionName, LocalAddress); | 
 | } | 
 |  | 
 | Optional<uint64_t> | 
 | RuntimeDyldChecker::getSectionLoadAddress(void *LocalAddress) const { | 
 |   return Impl->getSectionLoadAddress(LocalAddress); | 
 | } |