[MCJIT] Refactor and add stub inspection to the RuntimeDyldChecker framework.
authorLang Hames <lhames@gmail.com>
Tue, 22 Jul 2014 22:47:39 +0000 (22:47 +0000)
committerLang Hames <lhames@gmail.com>
Tue, 22 Jul 2014 22:47:39 +0000 (22:47 +0000)
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@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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213698 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/ObjectBuffer.h
include/llvm/ExecutionEngine/ObjectImage.h
include/llvm/ExecutionEngine/RuntimeDyld.h
include/llvm/ExecutionEngine/RuntimeDyldChecker.h
lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h [new file with mode: 0644]
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
test/ExecutionEngine/RuntimeDyld/X86/MachO_x86-64_PIC_relocations.s
tools/llvm-rtdyld/llvm-rtdyld.cpp

index 6221d3b335df6759d44a260bd308e2175a4a84ec..c817c17aa8629f7a802f7149ff00f255e60e0abc 100644 (file)
@@ -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(); }
   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
 
 protected:
   // The memory contained in an ObjectBuffer
index 1fcedd8d6a923acd1a9877724a8b5f4fb33d7c76..afd98c796af74abf7733e467ffef5cc917ada916 100644 (file)
@@ -50,6 +50,11 @@ public:
 
   virtual /* Triple::ArchType */ unsigned getArch() const = 0;
 
 
   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,
   // Subclasses can override these methods to update the image with loaded
   // addresses for sections and common symbols
   virtual void updateSectionAddress(const object::SectionRef &Sec,
index f123ffb803bda86ab5079a3dd935b2ff0558ef97..65b06ffc40700b522e3d93a145acf436fdcc4138 100644 (file)
@@ -26,10 +26,11 @@ namespace object {
 }
 
 class RuntimeDyldImpl;
 }
 
 class RuntimeDyldImpl;
+class RuntimeDyldCheckerImpl;
 class ObjectImage;
 
 class RuntimeDyld {
 class ObjectImage;
 
 class RuntimeDyld {
-  friend class RuntimeDyldChecker;
+  friend class RuntimeDyldCheckerImpl;
 
   RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
   void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
 
   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;
   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.
 protected:
   // Change the address associated with a section when resolving relocations.
   // Any relocations already associated with the symbol will be re-resolved.
index 8dd891e8364829f33d823b44503995ee69a4ed13..276abffc0202012fe80b71da489ea3581edf8ac4 100644 (file)
 #ifndef LLVM_RUNTIMEDYLDCHECKER_H
 #define LLVM_RUNTIMEDYLDCHECKER_H
 
 #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;
 
 namespace llvm {
 
 class MCDisassembler;
+class MemoryBuffer;
 class MCInstPrinter;
 class MCInstPrinter;
+class RuntimeDyld;
+class RuntimeDyldCheckerImpl;
+class raw_ostream;
 
 /// \brief RuntimeDyld invariant checker for verifying that RuntimeDyld has
 ///        correctly applied relocations.
 
 /// \brief RuntimeDyld invariant checker for verifying that RuntimeDyld has
 ///        correctly applied relocations.
@@ -61,14 +62,10 @@ class MCInstPrinter;
 ///             | expr '>>' expr
 ///
 class RuntimeDyldChecker {
 ///             | expr '>>' expr
 ///
 class RuntimeDyldChecker {
-  friend class RuntimeDyldCheckerExprEval;
 public:
 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.
 
   /// \brief Check a single expression against the attached RuntimeDyld
   ///        instance.
@@ -80,17 +77,7 @@ public:
   bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
 
 private:
   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
 };
 
 } // end namespace llvm
index d86a75130685050719398ed94fdb6b5699aef5fb..7434c2a06666f35915344d01fe266aec78426d1f 100644 (file)
@@ -14,6 +14,7 @@
 #include "llvm/ExecutionEngine/RuntimeDyld.h"
 #include "JITRegistrar.h"
 #include "ObjectImageCommon.h"
 #include "llvm/ExecutionEngine/RuntimeDyld.h"
 #include "JITRegistrar.h"
 #include "ObjectImageCommon.h"
+#include "RuntimeDyldCheckerImpl.h"
 #include "RuntimeDyldELF.h"
 #include "RuntimeDyldImpl.h"
 #include "RuntimeDyldMachO.h"
 #include "RuntimeDyldELF.h"
 #include "RuntimeDyldImpl.h"
 #include "RuntimeDyldMachO.h"
@@ -204,6 +205,13 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
     for (; I != E;)
       I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols,
                                Stubs);
     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.
   }
 
   // Give the subclasses a chance to tie-up any loose ends.
@@ -695,22 +703,26 @@ RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {
   Dyld = nullptr;
   MM = mm;
   ProcessAllSections = false;
   Dyld = nullptr;
   MM = mm;
   ProcessAllSections = false;
+  Checker = nullptr;
 }
 
 RuntimeDyld::~RuntimeDyld() { delete Dyld; }
 
 static std::unique_ptr<RuntimeDyldELF>
 }
 
 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);
   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,
   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);
   std::unique_ptr<RuntimeDyldMachO> Dyld(RuntimeDyldMachO::create(Arch, MM));
   Dyld->setProcessAllSections(ProcessAllSections);
+  Dyld->setRuntimeDyldChecker(Checker);
   return Dyld;
 }
 
   return Dyld;
 }
 
@@ -722,13 +734,13 @@ ObjectImage *RuntimeDyld::loadObject(std::unique_ptr<ObjectFile> InputObject) {
   if (InputObject->isELF()) {
     InputImage.reset(RuntimeDyldELF::createObjectImageFromFile(std::move(InputObject)));
     if (!Dyld)
   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()),
   } 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!");
 
   } else
     report_fatal_error("Incompatible object format!");
 
@@ -750,7 +762,7 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
   case sys::fs::file_magic::elf_core:
     InputImage.reset(RuntimeDyldELF::createObjectImage(InputBuffer));
     if (!Dyld)
   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:
     break;
   case sys::fs::file_magic::macho_object:
   case sys::fs::file_magic::macho_executable:
@@ -766,7 +778,7 @@ ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) {
     if (!Dyld)
       Dyld = createRuntimeDyldMachO(
                            static_cast<Triple::ArchType>(InputImage->getArch()),
     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:
     break;
   case sys::fs::file_magic::unknown:
   case sys::fs::file_magic::bitcode:
index 1e63d9207f73fbc6854e830f0c2e3538c0c99d22..3ac4dd6b4f04f5c036e689cb4b03977206ed6b4a 100644 (file)
@@ -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 "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>
 #include "RuntimeDyldImpl.h"
 #include <cctype>
 #include <memory>
@@ -22,594 +24,651 @@ using namespace llvm;
 
 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:
+  // 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(ErrorMsg) {}
+    uint64_t getValue() const { return Value; }
+    bool hasError() const { return ErrorMsg != ""; }
+    const std::string &getErrorMsg() const { return ErrorMsg; }
 
   private:
 
   private:
-    const RuntimeDyldChecker &Checker;
-    llvm::raw_ostream &ErrStream;
-
-    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(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;
-    }
+    uint64_t Value;
+    std::string ErrorMsg;
+  };
 
 
-    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));
+  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());
+  }
 
 
-    // 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());
+  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());
     }
     }
+  }
 
 
-    // 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()), "");
-      }
-
-      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()), "");
-      }
+  // 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());
+  }
 
 
-      return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
-    }
+  // 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()),
+          "");
 
 
-    // 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);
-    }
+    if (!RemainingExpr.startswith(","))
+      return std::make_pair(
+          unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
+    RemainingExpr = RemainingExpr.substr(1).ltrim();
 
 
-    // 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'?)";
-
-        return std::make_pair(EvalResult(ErrMsg), "");
-      }
+    EvalResult OpIdxExpr;
+    std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
+    if (OpIdxExpr.hasError())
+      return std::make_pair(OpIdxExpr, "");
 
 
-      // Looks like a plain symbol reference.
-      return std::make_pair(EvalResult(Checker.getSymbolAddress(Symbol)),
-                            RemainingExpr);
-    }
+    if (!RemainingExpr.startswith(")"))
+      return std::make_pair(
+          unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
+    RemainingExpr = RemainingExpr.substr(1).ltrim();
 
 
-    // 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()),
+          "");
+
+    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()), "");
     }
 
     }
 
-    // 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);
+    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 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);
-    }
+    return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
+  }
 
 
-    // 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();
-      }
+  // 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()),
+          "");
 
 
-      // Read symbol.
-      StringRef Symbol;
-      std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
+    if (!RemainingExpr.startswith(")"))
+      return std::make_pair(
+          unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
+    RemainingExpr = RemainingExpr.substr(1).ltrim();
 
 
-      if (!Checker.isSymbolValid(Symbol))
-        return std::make_pair(EvalResult(("Cannot dereference unknown symbol '"
-                                          + Symbol + "'").str()),
-                              "");
+    MCInst Inst;
+    uint64_t InstSize;
+    if (!decodeInst(Symbol, Inst, InstSize))
+      return std::make_pair(
+          EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
+          "");
 
 
-      // Set up defaut offset.
-      int64_t Offset = 0;
+    uint64_t SymbolAddr = PCtx.IsInsideLoad
+                              ? Checker.getSymbolLinkerAddr(Symbol)
+                              : Checker.getSymbolRemoteAddr(Symbol);
+    uint64_t NextPC = SymbolAddr + InstSize;
 
 
-      // 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();
+    return std::make_pair(EvalResult(NextPC), RemainingExpr);
+  }
 
 
-        EvalResult OffsetExpr;
-        std::tie(OffsetExpr, RemainingExpr) = evalNumberExpr(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();
 
 
-        Offset = (OpChar == '+') ?
-                   OffsetExpr.getValue() : -1 * OffsetExpr.getValue();
+    StringRef SectionName;
+    std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr);
 
 
-        if (!RemainingExpr.startswith(")"))
-          return std::make_pair(EvalResult("Missing ')' in load address."),
-                                "");
+    if (!RemainingExpr.startswith(","))
+      return std::make_pair(
+          unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
+    RemainingExpr = RemainingExpr.substr(1).ltrim();
 
 
-        RemainingExpr = RemainingExpr.substr(1).ltrim();
-      }
+    StringRef Symbol;
+    std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
 
 
+    if (!RemainingExpr.startswith(")"))
       return std::make_pair(
       return std::make_pair(
-               EvalResult(Checker.readMemoryAtSymbol(Symbol, Offset, ReadSize)),
-               RemainingExpr);
+          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), "");
     }
 
     }
 
-    // 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));
+    // 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);
 
 
-      return std::make_pair(SubExprResult, RemainingExpr);
+    // 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 (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 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);
 
 
-    // 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
+    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.
     // 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);
-    }
+    if (LHSResult.hasError() || RemainingExpr == "")
+      return std::make_pair(LHSResult, 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));
-    }
+    // Otherwise check if this is a binary expressioan.
+    BinOpToken BinOp;
+    std::tie(BinOp, RemainingExpr) = parseBinOpToken(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 this isn't a recognized expression just return.
+    if (BinOp == BinOpToken::Invalid)
+      return std::make_pair(LHSResult, RemainingExpr);
 
 
-      MCDisassembler::DecodeStatus S =
-        Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
+    // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
+    EvalResult RHSResult;
+    std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);
 
 
-      return (S == MCDisassembler::Success);
-    }
+    // 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);
+    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();
   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;
   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;
 }
 
   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.
   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;
     ++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);
       ++LineEnd;
 
     StringRef Line(LineStart, LineEnd - LineStart);
@@ -620,37 +679,126 @@ bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
 
     // Eat whitespace.
     LineStart = LineEnd;
 
     // Eat whitespace.
     LineStart = LineEnd;
-    while (LineStart != MemBuf->getBufferEnd() &&
-           std::isspace(*LineStart))
+    while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
       ++LineStart;
   }
   return DidAllTestsPass && (NumRules != 0);
 }
 
       ++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;
   uint64_t Result = 0;
-  memcpy(&Result, Src + Offset, Size);
+  memcpy(&Result, Src, Size);
   return Result;
 }
 
   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 =
   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;
     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);
 }
 }
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h
new file mode 100644 (file)
index 0000000..62e8dcb
--- /dev/null
@@ -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
index 0211d2bbbb0520b9e2c96a56110b7607923e23e9..3fabf5ebd6deac4a2ccd5bb93d7f434d57eb1100 100644 (file)
@@ -159,7 +159,7 @@ public:
 };
 
 class RuntimeDyldImpl {
 };
 
 class RuntimeDyldImpl {
-  friend class RuntimeDyldChecker;
+  friend class RuntimeDyldCheckerImpl;
 private:
 
   uint64_t getAnySymbolRemoteAddress(StringRef Symbol) {
 private:
 
   uint64_t getAnySymbolRemoteAddress(StringRef Symbol) {
@@ -172,6 +172,9 @@ protected:
   // The MemoryManager to load objects into.
   RTDyldMemoryManager *MemMgr;
 
   // 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;
   // 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;
 
   // modules.  This map is indexed by symbol name.
   StringMap<RelocationList> ExternalSymbolRelocations;
 
+
   typedef std::map<RelocationValueRef, uintptr_t> StubMap;
 
   Triple::ArchType Arch;
   typedef std::map<RelocationValueRef, uintptr_t> StubMap;
 
   Triple::ArchType Arch;
@@ -349,7 +353,7 @@ protected:
 
 public:
   RuntimeDyldImpl(RTDyldMemoryManager *mm)
 
 public:
   RuntimeDyldImpl(RTDyldMemoryManager *mm)
-      : MemMgr(mm), ProcessAllSections(false), HasError(false) {
+    : MemMgr(mm), Checker(nullptr), ProcessAllSections(false), HasError(false) {
   }
 
   virtual ~RuntimeDyldImpl();
   }
 
   virtual ~RuntimeDyldImpl();
@@ -358,6 +362,10 @@ public:
     this->ProcessAllSections = ProcessAllSections;
   }
 
     this->ProcessAllSections = ProcessAllSections;
   }
 
+  void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) {
+    this->Checker = Checker;
+  }
+
   ObjectImage *loadObject(ObjectImage *InputObject);
 
   uint8_t* getSymbolAddress(StringRef Name) {
   ObjectImage *loadObject(ObjectImage *InputObject);
 
   uint8_t* getSymbolAddress(StringRef Name) {
index ecbbf8282513d2f5c12f5cb5e38be0bea9c40d7c..abc98944a82ac912dd32be395e3e20baecb75f99 100644 (file)
@@ -37,6 +37,7 @@ protected:
         : EHFrameSID(RTDYLD_INVALID_SECTION_ID),
           TextSID(RTDYLD_INVALID_SECTION_ID),
           ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {}
         : 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;
     EHFrameRelatedSections(SID EH, SID T, SID Ex)
         : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {}
     SID EHFrameSID;
index e87b449bb2378651a0f9804ae6d34f678a82d870..847977b9eac5a647ee16d9ff11d7ef823f7ca026 100644 (file)
@@ -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
 
         .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
 # 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@GOTPCREL(%rip), %rax
+
+        movl   $0, %eax
        retq
 
        retq
 
+        .comm   y,4,2
+
         .section       __DATA,__data
        .globl  x
        .align  2
         .section       __DATA,__data
        .globl  x
        .align  2
index 45734f4b7ba6fd4c81816347f352eca7def72b7b..0bed9df980027b218a3ff677ac5c1021d8d6f964 100644 (file)
@@ -347,6 +347,8 @@ static int linkAndVerify() {
   // Instantiate a dynamic linker.
   TrivialMemoryManager MemMgr;
   RuntimeDyld Dyld(&MemMgr);
   // 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())
 
   // 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();
 
   // Resolve all the relocations we can.
   Dyld.resolveRelocations();
 
-  RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
-                             llvm::dbgs());
   return checkAllExpressions(Checker);
 }
 
   return checkAllExpressions(Checker);
 }