[llvm] r213698 - [MCJIT] Refactor and add stub inspection to the RuntimeDyldChecker framework.

Juergen Ributzka juergen at apple.com
Tue Jul 22 16:45:09 PDT 2014


Awesome :D

Dang, now I have to write more unit tests ;)

On Jul 22, 2014, at 3:47 PM, Lang Hames <lhames at gmail.com> wrote:

> Author: lhames
> Date: Tue Jul 22 17:47:39 2014
> New Revision: 213698
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=213698&view=rev
> Log:
> [MCJIT] Refactor and add stub inspection to the RuntimeDyldChecker framework.
> 
> This patch introduces a 'stub_addr' builtin that can be used to find the address
> of the stub for a given (<file>, <section>, <symbol>) tuple. This address can be
> used both to verify the contents of stubs (by loading from the returned address)
> and to verify references to stubs (by comparing against the returned address).
> 
> Example (1) - Verifying stub contents:
> 
> Load 8 bytes (assuming a 64-bit target) from the stub for 'x' in the __text
> section of f.o, and compare that value against the addres of 'x'.
> 
> # rtdyld-check: *{8}(stub_addr(f.o, __text, x) = x
> 
> Example (2) - Verifying references to stubs:
> 
> Decode the immediate of the instruction at label 'l', and verify that it's
> equal to the offset from the next instruction's PC to the stub for 'y' in the
> __text section of f.o (i.e. it's the correct PC-rel difference).
> 
> # rtdyld-check: decode_operand(l, 4) = stub_addr(f.o, __text, y) - next_pc(l)
> l:
>        movq    y at GOTPCREL(%rip), %rax
> 
> Since stub inspection requires cooperation with RuntimeDyldImpl this patch
> pimpl-ifies RuntimeDyldChecker. Its implementation is moved in to a new class,
> RuntimeDyldCheckerImpl, that has access to the definition of RuntimeDyldImpl.
> 
> 
> Added:
>    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
> Modified:
>    llvm/trunk/include/llvm/ExecutionEngine/ObjectBuffer.h
>    llvm/trunk/include/llvm/ExecutionEngine/ObjectImage.h
>    llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyld.h
>    llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyldChecker.h
>    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
>    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
>    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
>    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
>    llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s
>    llvm/trunk/tools/llvm-rtdyld/llvm-rtdyld.cpp
> 
> Modified: llvm/trunk/include/llvm/ExecutionEngine/ObjectBuffer.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/ObjectBuffer.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/ObjectBuffer.h (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/ObjectBuffer.h Tue Jul 22 17:47:39 2014
> @@ -46,6 +46,9 @@ public:
>   const char *getBufferStart() const { return Buffer->getBufferStart(); }
>   size_t getBufferSize() const { return Buffer->getBufferSize(); }
>   StringRef getBuffer() const { return Buffer->getBuffer(); }
> +  StringRef getBufferIdentifier() const {
> +    return Buffer->getBufferIdentifier();
> +  }
> 
> protected:
>   // The memory contained in an ObjectBuffer
> 
> Modified: llvm/trunk/include/llvm/ExecutionEngine/ObjectImage.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/ObjectImage.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/ObjectImage.h (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/ObjectImage.h Tue Jul 22 17:47:39 2014
> @@ -50,6 +50,11 @@ public:
> 
>   virtual /* Triple::ArchType */ unsigned getArch() const = 0;
> 
> +  // Return the name associated with this ObjectImage.
> +  // This is usually the name of the file or MemoryBuffer that the the
> +  // ObjectBuffer was constructed from.
> +  StringRef getImageName() const { return Buffer->getBufferIdentifier(); }
> +
>   // Subclasses can override these methods to update the image with loaded
>   // addresses for sections and common symbols
>   virtual void updateSectionAddress(const object::SectionRef &Sec,
> 
> Modified: llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyld.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyld.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyld.h (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyld.h Tue Jul 22 17:47:39 2014
> @@ -26,10 +26,11 @@ namespace object {
> }
> 
> class RuntimeDyldImpl;
> +class RuntimeDyldCheckerImpl;
> class ObjectImage;
> 
> class RuntimeDyld {
> -  friend class RuntimeDyldChecker;
> +  friend class RuntimeDyldCheckerImpl;
> 
>   RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
>   void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
> @@ -39,6 +40,7 @@ class RuntimeDyld {
>   RuntimeDyldImpl *Dyld;
>   RTDyldMemoryManager *MM;
>   bool ProcessAllSections;
> +  RuntimeDyldCheckerImpl *Checker;
> protected:
>   // Change the address associated with a section when resolving relocations.
>   // Any relocations already associated with the symbol will be re-resolved.
> 
> Modified: llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyldChecker.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyldChecker.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyldChecker.h (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/RuntimeDyldChecker.h Tue Jul 22 17:47:39 2014
> @@ -10,15 +10,16 @@
> #ifndef LLVM_RUNTIMEDYLDCHECKER_H
> #define LLVM_RUNTIMEDYLDCHECKER_H
> 
> -#include "RuntimeDyld.h"
> -#include "llvm/Support/Debug.h"
> -#include "llvm/Support/raw_ostream.h"
> -#include <map>
> +#include "llvm/ADT/StringRef.h"
> 
> namespace llvm {
> 
> class MCDisassembler;
> +class MemoryBuffer;
> class MCInstPrinter;
> +class RuntimeDyld;
> +class RuntimeDyldCheckerImpl;
> +class raw_ostream;
> 
> /// \brief RuntimeDyld invariant checker for verifying that RuntimeDyld has
> ///        correctly applied relocations.
> @@ -61,14 +62,10 @@ class MCInstPrinter;
> ///             | expr '>>' expr
> ///
> class RuntimeDyldChecker {
> -  friend class RuntimeDyldCheckerExprEval;
> public:
> -  RuntimeDyldChecker(RuntimeDyld &RTDyld,
> -                     MCDisassembler *Disassembler,
> -                     MCInstPrinter *InstPrinter,
> -                     llvm::raw_ostream &ErrStream)
> -    : RTDyld(*RTDyld.Dyld), Disassembler(Disassembler),
> -      InstPrinter(InstPrinter), ErrStream(ErrStream) {}
> +  RuntimeDyldChecker(RuntimeDyld &RTDyld, MCDisassembler *Disassembler,
> +                     MCInstPrinter *InstPrinter, raw_ostream &ErrStream);
> +  ~RuntimeDyldChecker();
> 
>   /// \brief Check a single expression against the attached RuntimeDyld
>   ///        instance.
> @@ -80,17 +77,7 @@ public:
>   bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
> 
> private:
> -
> -  bool isSymbolValid(StringRef Symbol) const;
> -  uint64_t getSymbolAddress(StringRef Symbol) const;
> -  uint64_t readMemoryAtSymbol(StringRef Symbol, int64_t Offset,
> -                              unsigned Size) const;
> -  StringRef getSubsectionStartingAt(StringRef Name) const;
> -
> -  RuntimeDyldImpl &RTDyld;
> -  MCDisassembler *Disassembler;
> -  MCInstPrinter *InstPrinter;
> -  llvm::raw_ostream &ErrStream;
> +  std::unique_ptr<RuntimeDyldCheckerImpl> Impl;
> };
> 
> } // end namespace llvm
> 
> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp Tue Jul 22 17:47:39 2014
> @@ -14,6 +14,7 @@
> #include "llvm/ExecutionEngine/RuntimeDyld.h"
> #include "JITRegistrar.h"
> #include "ObjectImageCommon.h"
> +#include "RuntimeDyldCheckerImpl.h"
> #include "RuntimeDyldELF.h"
> #include "RuntimeDyldImpl.h"
> #include "RuntimeDyldMachO.h"
> @@ -204,6 +205,13 @@ ObjectImage *RuntimeDyldImpl::loadObject
>     for (; I != E;)
>       I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols,
>                                Stubs);
> +
> +#ifndef NDEBUG
> +    // If there is an attached checker, notify it about the stubs for this
> +    // section so that they can be verified.
> +    if (Checker)
> +      Checker->registerStubMap(Obj->getImageName(), SectionID, Stubs);
> +#endif
>   }
> 
>   // Give the subclasses a chance to tie-up any loose ends.
> @@ -695,22 +703,26 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryMan
>   Dyld = nullptr;
>   MM = mm;
>   ProcessAllSections = false;
> +  Checker = nullptr;
> }
> 
> RuntimeDyld::~RuntimeDyld() { delete Dyld; }
> 
> static std::unique_ptr<RuntimeDyldELF>
> -createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections) {
> +createRuntimeDyldELF(RTDyldMemoryManager *MM, bool ProcessAllSections,
> +                     RuntimeDyldCheckerImpl *Checker) {
>   std::unique_ptr<RuntimeDyldELF> Dyld(new RuntimeDyldELF(MM));
>   Dyld->setProcessAllSections(ProcessAllSections);
> +  Dyld->setRuntimeDyldChecker(Checker);
>   return Dyld;
> }
> 
> static std::unique_ptr<RuntimeDyldMachO>
> createRuntimeDyldMachO(Triple::ArchType Arch, RTDyldMemoryManager *MM,
> -                       bool ProcessAllSections) {
> +                       bool ProcessAllSections, RuntimeDyldCheckerImpl *Checker) {
>   std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM));
>   Dyld->setProcessAllSections(ProcessAllSections);
> +  Dyld->setRuntimeDyldChecker(Checker);
>   return Dyld;
> }
> 
> @@ -722,13 +734,13 @@ ObjectImage *RuntimeDyld::loadObject(std
>   if (InputObject->isELF()) {
>     InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject)));
>     if (!Dyld)
> -      Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release();
> +      Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker).release();
>   } else if (InputObject->isMachO()) {
>     InputImage.reset(RuntimeDyldMachO::createObjectImageFromFile(std::move(InputObject)));
>     if (!Dyld)
>       Dyld = createRuntimeDyldMachO(
>                            static_cast<Triple::ArchType>(InputImage->getArch()),
> -                           MM, ProcessAllSections).release();
> +                           MM, ProcessAllSections, Checker).release();
>   } else
>     report_fatal_error("Incompatible object format!");
> 
> @@ -750,7 +762,7 @@ ObjectImage *RuntimeDyld::loadObject(Obj
>   case sys::fs::file_magic::elf_core:
>     InputImage.reset(RuntimeDyldELF::createObjectImage(InputBuffer));
>     if (!Dyld)
> -      Dyld = createRuntimeDyldELF(MM, ProcessAllSections).release();
> +      Dyld = createRuntimeDyldELF(MM, ProcessAllSections, Checker).release();
>     break;
>   case sys::fs::file_magic::macho_object:
>   case sys::fs::file_magic::macho_executable:
> @@ -766,7 +778,7 @@ ObjectImage *RuntimeDyld::loadObject(Obj
>     if (!Dyld)
>       Dyld = createRuntimeDyldMachO(
>                            static_cast<Triple::ArchType>(InputImage->getArch()),
> -                           MM, ProcessAllSections).release();
> +                           MM, ProcessAllSections, Checker).release();
>     break;
>   case sys::fs::file_magic::unknown:
>   case sys::fs::file_magic::bitcode:
> 
> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp Tue Jul 22 17:47:39 2014
> @@ -7,11 +7,13 @@
> //
> //===----------------------------------------------------------------------===//
> 
> +#include "llvm/ADT/STLExtras.h"
> #include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
> #include "llvm/MC/MCContext.h"
> #include "llvm/MC/MCDisassembler.h"
> #include "llvm/MC/MCInst.h"
> #include "llvm/Support/StringRefMemoryObject.h"
> +#include "RuntimeDyldCheckerImpl.h"
> #include "RuntimeDyldImpl.h"
> #include <cctype>
> #include <memory>
> @@ -22,594 +24,651 @@ using namespace llvm;
> 
> namespace llvm {
> 
> -  // Helper class that implements the language evaluated by RuntimeDyldChecker.
> -  class RuntimeDyldCheckerExprEval {
> -  public:
> -
> -    RuntimeDyldCheckerExprEval(const RuntimeDyldChecker &Checker,
> -                               llvm::raw_ostream &ErrStream)
> -      : Checker(Checker), ErrStream(ErrStream) {}
> -
> -    bool evaluate(StringRef Expr) const {
> -      // Expect equality expression of the form 'LHS = RHS'.
> -      Expr = Expr.trim();
> -      size_t EQIdx = Expr.find('=');
> -
> -      // Evaluate LHS.
> -      StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
> -      StringRef RemainingExpr;
> -      EvalResult LHSResult;
> -      std::tie(LHSResult, RemainingExpr) =
> -        evalComplexExpr(evalSimpleExpr(LHSExpr));
> -      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));
> -      if (RHSResult.hasError())
> -        return handleError(Expr, RHSResult);
> -      if (RemainingExpr != "")
> -        return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, ""));
> -
> -      if (LHSResult.getValue() != RHSResult.getValue()) {
> -        ErrStream << "Expression '" << Expr << "' is false: "
> -                  << format("0x%lx", LHSResult.getValue()) << " != "
> -                  << format("0x%lx", RHSResult.getValue()) << "\n";
> -        return false;
> -      }
> -      return true;
> +// 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%lx", LHSResult.getValue())
> +                        << " != " << format("0x%lx", RHSResult.getValue())
> +                        << "\n";
> +      return false;
>     }
> +    return true;
> +  }
> 
> -  private:
> -    const RuntimeDyldChecker &Checker;
> -    llvm::raw_ostream &ErrStream;
> +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) {}
> +  };
> 
> -    enum class BinOpToken : unsigned { Invalid, Add, Sub, BitwiseAnd,
> -                                       BitwiseOr, ShiftLeft, ShiftRight };
> +  const RuntimeDyldCheckerImpl &Checker;
> 
> -    class EvalResult {
> -    public:
> -      EvalResult()
> -        : Value(0), ErrorMsg("") {}
> -      EvalResult(uint64_t Value)
> -        : Value(Value), ErrorMsg("") {}
> -      EvalResult(std::string ErrorMsg)
> -        : Value(0), ErrorMsg(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;
> -    }
> +  enum class BinOpToken : unsigned {
> +    Invalid,
> +    Add,
> +    Sub,
> +    BitwiseAnd,
> +    BitwiseOr,
> +    ShiftLeft,
> +    ShiftRight
> +  };
> 
> -    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));
> +  class EvalResult {
> +  public:
> +    EvalResult() : Value(0), ErrorMsg("") {}
> +    EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {}
> +    EvalResult(std::string ErrorMsg) : Value(0), ErrorMsg(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;
> +  }
> 
> -    bool handleError(StringRef Expr, const EvalResult &R) const {
> -      assert(R.hasError() && "Not an error result.");
> -      ErrStream << "Error evaluating expression '" << Expr << "': "
> -                << R.getErrorMsg() << "\n";
> -      return false;
> +  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));
> +  }
> 
> -    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;
> -      }
> +  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;
> +  }
> 
> -      return std::make_pair(Op, Expr.substr(1).ltrim());
> +  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;
>     }
> 
> -    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());
> -      }
> +    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, retuns 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.Disassembler->getContext().getAsmInfo(),
> -                         Checker.InstPrinter);
> -        return std::make_pair(EvalResult(ErrMsgStream.str()), "");
> -      }
> +  // 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());
> +  }
> 
> -      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.Disassembler->getContext().getAsmInfo(),
> -                         Checker.InstPrinter);
> +  // 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, retuns 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);
> 
> -        return std::make_pair(EvalResult(ErrMsgStream.str()), "");
> -      }
> +    if (!Checker.isSymbolValid(Symbol))
> +      return std::make_pair(
> +          EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
> +          "");
> 
> -      return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
> -    }
> +    if (!RemainingExpr.startswith(","))
> +      return std::make_pair(
> +          unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
> +    RemainingExpr = RemainingExpr.substr(1).ltrim();
> 
> -    // 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 the length of the
> -    // expression remaining to be evaluated.
> -    std::pair<EvalResult, StringRef> evalNextPC(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();
> -
> -      MCInst Inst;
> -      uint64_t Size;
> -      if (!decodeInst(Symbol, Inst, Size))
> -        return std::make_pair(EvalResult(("Couldn't decode instruction at '" +
> -                                          Symbol + "'").str()),
> -                              "");
> -      uint64_t NextPC = Checker.getSymbolAddress(Symbol) + Size;
> -
> -      return std::make_pair(EvalResult(NextPC), 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) 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);
> -
> -      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'?)";
> +    EvalResult OpIdxExpr;
> +    std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
> +    if (OpIdxExpr.hasError())
> +      return std::make_pair(OpIdxExpr, "");
> 
> -        return std::make_pair(EvalResult(ErrMsg), "");
> -      }
> +    if (!RemainingExpr.startswith(")"))
> +      return std::make_pair(
> +          unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
> +    RemainingExpr = RemainingExpr.substr(1).ltrim();
> 
> -      // Looks like a plain symbol reference.
> -      return std::make_pair(EvalResult(Checker.getSymbolAddress(Symbol)),
> -                            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));
> -    }
> +    MCInst Inst;
> +    uint64_t Size;
> +    if (!decodeInst(Symbol, Inst, Size))
> +      return std::make_pair(
> +          EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
> +          "");
> 
> -    // Evaluate a constant numeric expression (hexidecimal 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) const {
> -      assert(Expr.startswith("(") && "Not a parenthesized expression");
> -      EvalResult SubExprResult;
> -      StringRef RemainingExpr;
> -      std::tie(SubExprResult, RemainingExpr) =
> -        evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim()));
> -      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);
> +    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.Disassembler->getContext().getAsmInfo(),
> +                       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.Disassembler->getContext().getAsmInfo(),
> +                       Checker.InstPrinter);
> +
> +      return std::make_pair(EvalResult(ErrMsgStream.str()), "");
>     }
> 
> -    // Evaluate an expression in one of the following forms:
> -    //   *{<number>}<symbol>
> -    //   *{<number>}(<symbol> + <number>)
> -    //   *{<number>}(<symbol> - <number>)
> -    // 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();
> -
> -      // Check for '(symbol +/- constant)' form.
> -      bool SymbolPlusConstant = false;
> -      if (RemainingExpr.startswith("(")) {
> -        SymbolPlusConstant = true;
> -        RemainingExpr = RemainingExpr.substr(1).ltrim();
> -      }
> +    return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
> +  }
> 
> -      // Read symbol.
> -      StringRef Symbol;
> -      std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
> -
> -      if (!Checker.isSymbolValid(Symbol))
> -        return std::make_pair(EvalResult(("Cannot dereference unknown symbol '"
> -                                          + Symbol + "'").str()),
> -                              "");
> -
> -      // Set up defaut offset.
> -      int64_t Offset = 0;
> -
> -      // Handle "+/- constant)" portion if necessary.
> -      if (SymbolPlusConstant) {
> -        char OpChar = RemainingExpr[0];
> -        if (OpChar != '+' && OpChar != '-')
> -          return std::make_pair(EvalResult("Invalid operator in load address."),
> -                                "");
> -        RemainingExpr = RemainingExpr.substr(1).ltrim();
> -
> -        EvalResult OffsetExpr;
> -        std::tie(OffsetExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
> -
> -        Offset = (OpChar == '+') ?
> -                   OffsetExpr.getValue() : -1 * OffsetExpr.getValue();
> -
> -        if (!RemainingExpr.startswith(")"))
> -          return std::make_pair(EvalResult("Missing ')' in load address."),
> -                                "");
> +  // 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);
> 
> -        RemainingExpr = RemainingExpr.substr(1).ltrim();
> -      }
> +    if (!Checker.isSymbolValid(Symbol))
> +      return std::make_pair(
> +          EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
> +          "");
> 
> +    if (!RemainingExpr.startswith(")"))
>       return std::make_pair(
> -               EvalResult(Checker.readMemoryAtSymbol(Symbol, Offset, ReadSize)),
> -               RemainingExpr);
> +          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.getSymbolLinkerAddr(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);
> +  }
> +
> +  // 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);
> +
> +    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.getSymbolLinkerAddr(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 "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) 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);
> -      else if (Expr[0] == '*')
> -        std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
> -      else if (isalpha(Expr[0]))
> -        std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr);
> -      else if (isdigit(Expr[0]))
> -        std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
> -
> -      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));
> +  // Evaluate a constant numeric expression (hexidecimal 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]))
> +      std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);
> +    else if (isdigit(Expr[0]))
> +      std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
> +
> +    if (SubExprResult.hasError())
>       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
> +    // 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(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(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.
> -    // Returns a pair containing the result of the slice operation, plus the
> -    // expression remaining to be parsed.
> -    std::pair<EvalResult, StringRef> evalSliceExpr(
> -                                    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(
> -                                   std::pair<EvalResult, StringRef> Ctx) const {
> -      EvalResult LHSResult;
> -      StringRef RemainingExpr;
> -      std::tie(LHSResult, RemainingExpr) = Ctx;
> -
> -      // 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);
> -
> -      // 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));
> -    }
> -
> -    bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const {
> -      MCDisassembler *Dis = Checker.Disassembler;
> -      StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol);
> -      StringRefMemoryObject SectionBytes(SectionMem, 0);
> +    if (LHSResult.hasError() || RemainingExpr == "")
> +      return std::make_pair(LHSResult, RemainingExpr);
> 
> -      MCDisassembler::DecodeStatus S =
> -        Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
> +    // 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 (S == MCDisassembler::Success);
> -    }
> +    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);
> +    StringRefMemoryObject SectionBytes(SectionMem, 0);
> 
> +    MCDisassembler::DecodeStatus S =
> +        Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
> +
> +    return (S == MCDisassembler::Success);
> +  }
> +};
> }
> 
> -bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
> +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();
> -  DEBUG(llvm::dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
> -                     << "'...\n");
> +  DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr << "'...\n");
>   RuntimeDyldCheckerExprEval P(*this, ErrStream);
>   bool Result = P.evaluate(CheckExpr);
>   (void)Result;
> -  DEBUG(llvm::dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
> -                     << (Result ? "passed" : "FAILED") << ".\n");
> +  DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
> +               << (Result ? "passed" : "FAILED") << ".\n");
>   return Result;
> }
> 
> -bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
> -                                               MemoryBuffer* MemBuf) const {
> +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))
> +  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')
> +    while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&
> +           *LineEnd != '\n')
>       ++LineEnd;
> 
>     StringRef Line(LineStart, LineEnd - LineStart);
> @@ -620,37 +679,126 @@ bool RuntimeDyldChecker::checkAllRulesIn
> 
>     // Eat whitespace.
>     LineStart = LineEnd;
> -    while (LineStart != MemBuf->getBufferEnd() &&
> -           std::isspace(*LineStart))
> +    while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
>       ++LineStart;
>   }
>   return DidAllTestsPass && (NumRules != 0);
> }
> 
> -bool RuntimeDyldChecker::isSymbolValid(StringRef Symbol) const {
> -  return RTDyld.getSymbolAddress(Symbol) != nullptr;
> +bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
> +  return getRTDyld().getSymbolAddress(Symbol) != nullptr;
> +}
> +
> +uint64_t RuntimeDyldCheckerImpl::getSymbolLinkerAddr(StringRef Symbol) const {
> +  return static_cast<uint64_t>(
> +      reinterpret_cast<uintptr_t>(getRTDyld().getSymbolAddress(Symbol)));
> }
> 
> -uint64_t RuntimeDyldChecker::getSymbolAddress(StringRef Symbol) const {
> -  return RTDyld.getAnySymbolRemoteAddress(Symbol);
> +uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
> +  return getRTDyld().getAnySymbolRemoteAddress(Symbol);
> }
> 
> -uint64_t RuntimeDyldChecker::readMemoryAtSymbol(StringRef Symbol,
> -                                                int64_t Offset,
> -                                                unsigned Size) const {
> -  uint8_t *Src = RTDyld.getSymbolAddress(Symbol);
> +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);
>   uint64_t Result = 0;
> -  memcpy(&Result, Src + Offset, Size);
> +  memcpy(&Result, Src, Size);
>   return Result;
> }
> 
> -StringRef RuntimeDyldChecker::getSubsectionStartingAt(StringRef Name) const {
> +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor(
> +    StringRef FileName, StringRef SectionName, StringRef SymbolName,
> +    bool IsInsideLoad) const {
> +
> +  auto SI1 = Stubs.find(FileName);
> +  if (SI1 == Stubs.end())
> +    return std::make_pair(0, ("File '" + FileName + "' not found.\n").str());
> +
> +  const SectionStubMap &SectionStubs = SI1->second;
> +  auto SI2 = SectionStubs.find(SectionName);
> +  if (SI2 == SectionStubs.end())
> +    return std::make_pair(0,
> +                          ("Section '" + SectionName + "' not found.\n").str());
> +
> +  const SymbolStubMap &SymbolStubs = SI2->second;
> +  auto SI3 = SymbolStubs.find(SymbolName);
> +  if (SI3 == SymbolStubs.end())
> +    return std::make_pair(0,
> +                          ("Symbol '" + SymbolName + "' not found.\n").str());
> +
> +  unsigned SectionID = SI3->second.first;
> +  uint64_t StubOffset = SI3->second.second;
> +
> +  uint64_t Addr;
> +  if (IsInsideLoad) {
> +    uint64_t SectionBase = getRTDyld().Sections[SectionID].LoadAddress;
> +    Addr = SectionBase + StubOffset;
> +  } else {
> +    uintptr_t SectionBase =
> +        reinterpret_cast<uintptr_t>(getRTDyld().Sections[SectionID].Address);
> +    Addr = static_cast<uint64_t>(SectionBase) + StubOffset;
> +  }
> +
> +  return std::make_pair(Addr, std::string(""));
> +}
> +
> +StringRef
> +RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const {
>   RuntimeDyldImpl::SymbolTableMap::const_iterator pos =
> -    RTDyld.GlobalSymbolTable.find(Name);
> -  if (pos == RTDyld.GlobalSymbolTable.end())
> +      getRTDyld().GlobalSymbolTable.find(Name);
> +  if (pos == getRTDyld().GlobalSymbolTable.end())
>     return StringRef();
>   RuntimeDyldImpl::SymbolLoc Loc = pos->second;
> -  uint8_t *SectionAddr = RTDyld.getSectionAddress(Loc.first);
> -  return StringRef(reinterpret_cast<const char*>(SectionAddr) + Loc.second,
> -                   RTDyld.Sections[Loc.first].Size - Loc.second);
> +  uint8_t *SectionAddr = getRTDyld().getSectionAddress(Loc.first);
> +  return StringRef(reinterpret_cast<const char *>(SectionAddr) + Loc.second,
> +                   getRTDyld().Sections[Loc.first].Size - Loc.second);
> +}
> +
> +void RuntimeDyldCheckerImpl::registerStubMap(
> +    StringRef FileName, unsigned SectionID,
> +    const RuntimeDyldImpl::StubMap &RTDyldStubs) {
> +  const SectionEntry &Section = getRTDyld().Sections[SectionID];
> +  StringRef SectionName = Section.Name;
> +  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) {
> +        if (GSTEntry.second.first == StubMapEntry.first.SectionID &&
> +            GSTEntry.second.second ==
> +                static_cast<uint64_t>(StubMapEntry.first.Addend)) {
> +          SymbolName = GSTEntry.first();
> +          break;
> +        }
> +      }
> +    }
> +
> +    if (SymbolName != "")
> +      Stubs[FileName][SectionName][SymbolName] =
> +          StubLoc(SectionID, StubMapEntry.second);
> +  }
> +}
> +
> +RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld,
> +                                       MCDisassembler *Disassembler,
> +                                       MCInstPrinter *InstPrinter,
> +                                       raw_ostream &ErrStream)
> +    : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler,
> +                                               InstPrinter, ErrStream)) {}
> +
> +RuntimeDyldChecker::~RuntimeDyldChecker() {}
> +
> +bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
> +  return Impl->check(CheckExpr);
> +}
> +
> +bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
> +                                               MemoryBuffer *MemBuf) const {
> +  return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
> }
> 
> Added: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h?rev=213698&view=auto
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h (added)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h Tue Jul 22 17:47:39 2014
> @@ -0,0 +1,60 @@
> +//===-- RuntimeDyldCheckerImpl.h -- RuntimeDyld test framework --*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_RUNTIMEDYLDCHECKERIMPL_H
> +#define LLVM_RUNTIMEDYLDCHECKERIMPL_H
> +
> +#include "RuntimeDyldImpl.h"
> +#include <set>
> +
> +namespace llvm {
> +
> +class RuntimeDyldCheckerImpl {
> +  friend class RuntimeDyldImpl;
> +  friend class RuntimeDyldCheckerExprEval;
> +
> +public:
> +  RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, MCDisassembler *Disassembler,
> +                         MCInstPrinter *InstPrinter,
> +                         llvm::raw_ostream &ErrStream);
> +
> +  bool check(StringRef CheckExpr) const;
> +  bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
> +
> +private:
> +  RuntimeDyldImpl &getRTDyld() const { return *RTDyld.Dyld; }
> +
> +  bool isSymbolValid(StringRef Symbol) const;
> +  uint64_t getSymbolLinkerAddr(StringRef Symbol) const;
> +  uint64_t getSymbolRemoteAddr(StringRef Symbol) const;
> +  uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const;
> +  std::pair<uint64_t, std::string> getStubAddrFor(StringRef FileName,
> +                                                  StringRef SectionName,
> +                                                  StringRef Symbol,
> +                                                  bool IsInsideLoad) const;
> +  StringRef getSubsectionStartingAt(StringRef Name) const;
> +
> +  void registerStubMap(StringRef FileName, unsigned SectionID,
> +                       const RuntimeDyldImpl::StubMap &RTDyldStubs);
> +
> +  RuntimeDyld &RTDyld;
> +  MCDisassembler *Disassembler;
> +  MCInstPrinter *InstPrinter;
> +  llvm::raw_ostream &ErrStream;
> +
> +  // StubMap typedefs.
> +  typedef std::pair<unsigned, uint64_t> StubLoc;
> +  typedef std::map<std::string, StubLoc> SymbolStubMap;
> +  typedef std::map<std::string, SymbolStubMap> SectionStubMap;
> +  typedef std::map<std::string, SectionStubMap> StubMap;
> +  StubMap Stubs;
> +};
> +};
> +
> +#endif // LLVM_RUNTIMEDYLDCHECKERIMPL_H
> 
> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h (original)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h Tue Jul 22 17:47:39 2014
> @@ -159,7 +159,7 @@ public:
> };
> 
> class RuntimeDyldImpl {
> -  friend class RuntimeDyldChecker;
> +  friend class RuntimeDyldCheckerImpl;
> private:
> 
>   uint64_t getAnySymbolRemoteAddress(StringRef Symbol) {
> @@ -172,6 +172,9 @@ protected:
>   // The MemoryManager to load objects into.
>   RTDyldMemoryManager *MemMgr;
> 
> +  // Attached RuntimeDyldChecker instance. Null if no instance attached.
> +  RuntimeDyldCheckerImpl *Checker;
> +
>   // A list of all sections emitted by the dynamic linker.  These sections are
>   // referenced in the code by means of their index in this list - SectionID.
>   typedef SmallVector<SectionEntry, 64> SectionList;
> @@ -211,6 +214,7 @@ protected:
>   // modules.  This map is indexed by symbol name.
>   StringMap<RelocationList> ExternalSymbolRelocations;
> 
> +
>   typedef std::map<RelocationValueRef, uintptr_t> StubMap;
> 
>   Triple::ArchType Arch;
> @@ -349,7 +353,7 @@ protected:
> 
> public:
>   RuntimeDyldImpl(RTDyldMemoryManager *mm)
> -      : MemMgr(mm), ProcessAllSections(false), HasError(false) {
> +    : MemMgr(mm), Checker(nullptr), ProcessAllSections(false), HasError(false) {
>   }
> 
>   virtual ~RuntimeDyldImpl();
> @@ -358,6 +362,10 @@ public:
>     this->ProcessAllSections = ProcessAllSections;
>   }
> 
> +  void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) {
> +    this->Checker = Checker;
> +  }
> +
>   ObjectImage *loadObject(ObjectImage *InputObject);
> 
>   uint8_t* getSymbolAddress(StringRef Name) {
> 
> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h (original)
> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h Tue Jul 22 17:47:39 2014
> @@ -37,6 +37,7 @@ protected:
>         : EHFrameSID(RTDYLD_INVALID_SECTION_ID),
>           TextSID(RTDYLD_INVALID_SECTION_ID),
>           ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {}
> +
>     EHFrameRelatedSections(SID EH, SID T, SID Ex)
>         : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {}
>     SID EHFrameSID;
> 
> Modified: llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s (original)
> +++ llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s Tue Jul 22 17:47:39 2014
> @@ -1,6 +1,6 @@
> -# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -relocation-model=pic -filetype=obj -o %t.o %s
> -# RUN: llvm-rtdyld -triple=x86_64-apple-macosx10.9 -verify -check=%s %t.o
> -# RUN: rm %t.o
> +# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -relocation-model=pic -filetype=obj -o %T/foo.o %s
> +# RUN: sed "s,<filename>,%T/foo.o,g" %s > %T/foo.s
> +# RUN: llvm-rtdyld -triple=x86_64-apple-macosx10.9 -verify -check=%T/foo.s %T/foo.o
> 
>         .section	__TEXT,__text,regular,pure_instructions
> 	.globl	foo
> @@ -20,9 +20,20 @@ insn1:
> # rtdyld-check: decode_operand(insn2, 4) = x - next_pc(insn2)
> insn2:
> 	movl	x(%rip), %eax
> -	movl	$0, %eax
> +
> +# Test PC-rel GOT relocation.
> +# Verify both the contents of the GOT entry for y, and that the movq instruction
> +# references the correct GOT entry address:
> +# rtdyld-check: *{8}(stub_addr(<filename>, __text, y)) = y
> +# rtdyld-check: decode_operand(insn3, 4) = stub_addr(<filename>, __text, y) - next_pc(insn3)
> +insn3:
> +        movq	y at GOTPCREL(%rip), %rax
> +
> +        movl	$0, %eax
> 	retq
> 
> +        .comm   y,4,2
> +
>         .section	__DATA,__data
> 	.globl	x
> 	.align	2
> 
> Modified: llvm/trunk/tools/llvm-rtdyld/llvm-rtdyld.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rtdyld/llvm-rtdyld.cpp?rev=213698&r1=213697&r2=213698&view=diff
> ==============================================================================
> --- llvm/trunk/tools/llvm-rtdyld/llvm-rtdyld.cpp (original)
> +++ llvm/trunk/tools/llvm-rtdyld/llvm-rtdyld.cpp Tue Jul 22 17:47:39 2014
> @@ -347,6 +347,8 @@ static int linkAndVerify() {
>   // Instantiate a dynamic linker.
>   TrivialMemoryManager MemMgr;
>   RuntimeDyld Dyld(&MemMgr);
> +  RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
> +                             llvm::dbgs());
> 
>   // If we don't have any input files, read from stdin.
>   if (!InputFileList.size())
> @@ -370,8 +372,6 @@ static int linkAndVerify() {
>   // Resolve all the relocations we can.
>   Dyld.resolveRelocations();
> 
> -  RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
> -                             llvm::dbgs());
>   return checkAllExpressions(Checker);
> }
> 
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list