[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