1e1c1138aSLang Hames //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===//
2e1c1138aSLang Hames //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e1c1138aSLang Hames //
7e1c1138aSLang Hames //===----------------------------------------------------------------------===//
8e1c1138aSLang Hames 
982de7d32SBenjamin Kramer #include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
10d9903888SChandler Carruth #include "RuntimeDyldCheckerImpl.h"
1182de7d32SBenjamin Kramer #include "llvm/ADT/STLExtras.h"
12d10c995bSSam McCall #include "llvm/ADT/StringExtras.h"
13e1c1138aSLang Hames #include "llvm/MC/MCContext.h"
14f57c1977SBenjamin Kramer #include "llvm/MC/MCDisassembler/MCDisassembler.h"
15e1c1138aSLang Hames #include "llvm/MC/MCInst.h"
16941f247dSLang Hames #include "llvm/Support/Endian.h"
17ffa72ef9SLang Hames #include "llvm/Support/MSVCErrorWorkarounds.h"
18*e72c195fSserge-sans-paille #include "llvm/Support/MemoryBuffer.h"
19480763f8SLang Hames #include "llvm/Support/Path.h"
203b7ffd63SLang Hames #include <cctype>
21e1c1138aSLang Hames #include <memory>
2282de7d32SBenjamin Kramer #include <utility>
23e1c1138aSLang Hames 
24e1c1138aSLang Hames #define DEBUG_TYPE "rtdyld"
25e1c1138aSLang Hames 
26e1c1138aSLang Hames using namespace llvm;
27e1c1138aSLang Hames 
28e1c1138aSLang Hames namespace llvm {
29e1c1138aSLang Hames 
30e1c1138aSLang Hames // Helper class that implements the language evaluated by RuntimeDyldChecker.
31e1c1138aSLang Hames class RuntimeDyldCheckerExprEval {
32e1c1138aSLang Hames public:
RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl & Checker,raw_ostream & ErrStream)33f7acdddeSLang Hames   RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker,
34f7acdddeSLang Hames                              raw_ostream &ErrStream)
35f7acdddeSLang Hames       : Checker(Checker) {}
36e1c1138aSLang Hames 
evaluate(StringRef Expr) const37e1c1138aSLang Hames   bool evaluate(StringRef Expr) const {
38e1c1138aSLang Hames     // Expect equality expression of the form 'LHS = RHS'.
39e1c1138aSLang Hames     Expr = Expr.trim();
40e1c1138aSLang Hames     size_t EQIdx = Expr.find('=');
41e1c1138aSLang Hames 
42f7acdddeSLang Hames     ParseContext OutsideLoad(false);
43f7acdddeSLang Hames 
44e1c1138aSLang Hames     // Evaluate LHS.
45e1c1138aSLang Hames     StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
46e1c1138aSLang Hames     StringRef RemainingExpr;
47e1c1138aSLang Hames     EvalResult LHSResult;
48e1c1138aSLang Hames     std::tie(LHSResult, RemainingExpr) =
49f7acdddeSLang Hames         evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad);
50e1c1138aSLang Hames     if (LHSResult.hasError())
51e1c1138aSLang Hames       return handleError(Expr, LHSResult);
52e1c1138aSLang Hames     if (RemainingExpr != "")
53e1c1138aSLang Hames       return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, ""));
54e1c1138aSLang Hames 
55e1c1138aSLang Hames     // Evaluate RHS.
56e1c1138aSLang Hames     StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();
57e1c1138aSLang Hames     EvalResult RHSResult;
58e1c1138aSLang Hames     std::tie(RHSResult, RemainingExpr) =
59f7acdddeSLang Hames         evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad);
60e1c1138aSLang Hames     if (RHSResult.hasError())
61e1c1138aSLang Hames       return handleError(Expr, RHSResult);
62e1c1138aSLang Hames     if (RemainingExpr != "")
63e1c1138aSLang Hames       return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, ""));
64e1c1138aSLang Hames 
65e1c1138aSLang Hames     if (LHSResult.getValue() != RHSResult.getValue()) {
66f7acdddeSLang Hames       Checker.ErrStream << "Expression '" << Expr << "' is false: "
67b2eb492dSLang Hames                         << format("0x%" PRIx64, LHSResult.getValue())
68b2eb492dSLang Hames                         << " != " << format("0x%" PRIx64, RHSResult.getValue())
69f7acdddeSLang Hames                         << "\n";
70e1c1138aSLang Hames       return false;
71e1c1138aSLang Hames     }
72e1c1138aSLang Hames     return true;
73e1c1138aSLang Hames   }
74e1c1138aSLang Hames 
75e1c1138aSLang Hames private:
76f7acdddeSLang Hames   // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In
77f7acdddeSLang Hames   // particular, it needs to know whether a symbol is being evaluated in the
78f7acdddeSLang Hames   // context of a load, in which case we want the linker's local address for
79f7acdddeSLang Hames   // the symbol, or outside of a load, in which case we want the symbol's
80f7acdddeSLang Hames   // address in the remote target.
81e1c1138aSLang Hames 
82f7acdddeSLang Hames   struct ParseContext {
83f7acdddeSLang Hames     bool IsInsideLoad;
ParseContextllvm::RuntimeDyldCheckerExprEval::ParseContext84f7acdddeSLang Hames     ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}
85f7acdddeSLang Hames   };
86f7acdddeSLang Hames 
87f7acdddeSLang Hames   const RuntimeDyldCheckerImpl &Checker;
88f7acdddeSLang Hames 
89f7acdddeSLang Hames   enum class BinOpToken : unsigned {
90f7acdddeSLang Hames     Invalid,
91f7acdddeSLang Hames     Add,
92f7acdddeSLang Hames     Sub,
93f7acdddeSLang Hames     BitwiseAnd,
94f7acdddeSLang Hames     BitwiseOr,
95f7acdddeSLang Hames     ShiftLeft,
96f7acdddeSLang Hames     ShiftRight
97f7acdddeSLang Hames   };
98e1c1138aSLang Hames 
99e1c1138aSLang Hames   class EvalResult {
100e1c1138aSLang Hames   public:
EvalResult()101f4ffcab1SKazu Hirata     EvalResult() : Value(0) {}
EvalResult(uint64_t Value)102f4ffcab1SKazu Hirata     EvalResult(uint64_t Value) : Value(Value) {}
EvalResult(std::string ErrorMsg)10382de7d32SBenjamin Kramer     EvalResult(std::string ErrorMsg)
10482de7d32SBenjamin Kramer         : Value(0), ErrorMsg(std::move(ErrorMsg)) {}
getValue() const105e1c1138aSLang Hames     uint64_t getValue() const { return Value; }
hasError() const106e1c1138aSLang Hames     bool hasError() const { return ErrorMsg != ""; }
getErrorMsg() const107e1c1138aSLang Hames     const std::string &getErrorMsg() const { return ErrorMsg; }
108f7acdddeSLang Hames 
109e1c1138aSLang Hames   private:
110e1c1138aSLang Hames     uint64_t Value;
111e1c1138aSLang Hames     std::string ErrorMsg;
112e1c1138aSLang Hames   };
113e1c1138aSLang Hames 
getTokenForError(StringRef Expr) const114e1c1138aSLang Hames   StringRef getTokenForError(StringRef Expr) const {
115e1c1138aSLang Hames     if (Expr.empty())
116e1c1138aSLang Hames       return "";
117e1c1138aSLang Hames 
118e1c1138aSLang Hames     StringRef Token, Remaining;
119e1c1138aSLang Hames     if (isalpha(Expr[0]))
120e1c1138aSLang Hames       std::tie(Token, Remaining) = parseSymbol(Expr);
121e1c1138aSLang Hames     else if (isdigit(Expr[0]))
122e1c1138aSLang Hames       std::tie(Token, Remaining) = parseNumberString(Expr);
123e1c1138aSLang Hames     else {
124e1c1138aSLang Hames       unsigned TokLen = 1;
125e1c1138aSLang Hames       if (Expr.startswith("<<") || Expr.startswith(">>"))
126e1c1138aSLang Hames         TokLen = 2;
127e1c1138aSLang Hames       Token = Expr.substr(0, TokLen);
128e1c1138aSLang Hames     }
129e1c1138aSLang Hames     return Token;
130e1c1138aSLang Hames   }
131e1c1138aSLang Hames 
unexpectedToken(StringRef TokenStart,StringRef SubExpr,StringRef ErrText) const132f7acdddeSLang Hames   EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr,
133e1c1138aSLang Hames                              StringRef ErrText) const {
134e1c1138aSLang Hames     std::string ErrorMsg("Encountered unexpected token '");
135e1c1138aSLang Hames     ErrorMsg += getTokenForError(TokenStart);
136e1c1138aSLang Hames     if (SubExpr != "") {
137e1c1138aSLang Hames       ErrorMsg += "' while parsing subexpression '";
138e1c1138aSLang Hames       ErrorMsg += SubExpr;
139e1c1138aSLang Hames     }
140e1c1138aSLang Hames     ErrorMsg += "'";
141e1c1138aSLang Hames     if (ErrText != "") {
142e1c1138aSLang Hames       ErrorMsg += " ";
143e1c1138aSLang Hames       ErrorMsg += ErrText;
144e1c1138aSLang Hames     }
145e1c1138aSLang Hames     return EvalResult(std::move(ErrorMsg));
146e1c1138aSLang Hames   }
147e1c1138aSLang Hames 
handleError(StringRef Expr,const EvalResult & R) const148e1c1138aSLang Hames   bool handleError(StringRef Expr, const EvalResult &R) const {
149e1c1138aSLang Hames     assert(R.hasError() && "Not an error result.");
150f7acdddeSLang Hames     Checker.ErrStream << "Error evaluating expression '" << Expr
151f7acdddeSLang Hames                       << "': " << R.getErrorMsg() << "\n";
152e1c1138aSLang Hames     return false;
153e1c1138aSLang Hames   }
154e1c1138aSLang Hames 
parseBinOpToken(StringRef Expr) const155e1c1138aSLang Hames   std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {
156e1c1138aSLang Hames     if (Expr.empty())
157e1c1138aSLang Hames       return std::make_pair(BinOpToken::Invalid, "");
158e1c1138aSLang Hames 
159e1c1138aSLang Hames     // Handle the two 2-character tokens.
160e1c1138aSLang Hames     if (Expr.startswith("<<"))
161f7acdddeSLang Hames       return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim());
162e1c1138aSLang Hames     if (Expr.startswith(">>"))
163f7acdddeSLang Hames       return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim());
164e1c1138aSLang Hames 
165e1c1138aSLang Hames     // Handle one-character tokens.
166e1c1138aSLang Hames     BinOpToken Op;
167e1c1138aSLang Hames     switch (Expr[0]) {
168f7acdddeSLang Hames     default:
169f7acdddeSLang Hames       return std::make_pair(BinOpToken::Invalid, Expr);
170f7acdddeSLang Hames     case '+':
171f7acdddeSLang Hames       Op = BinOpToken::Add;
172f7acdddeSLang Hames       break;
173f7acdddeSLang Hames     case '-':
174f7acdddeSLang Hames       Op = BinOpToken::Sub;
175f7acdddeSLang Hames       break;
176f7acdddeSLang Hames     case '&':
177f7acdddeSLang Hames       Op = BinOpToken::BitwiseAnd;
178f7acdddeSLang Hames       break;
179f7acdddeSLang Hames     case '|':
180f7acdddeSLang Hames       Op = BinOpToken::BitwiseOr;
181f7acdddeSLang Hames       break;
182e1c1138aSLang Hames     }
183e1c1138aSLang Hames 
184e1c1138aSLang Hames     return std::make_pair(Op, Expr.substr(1).ltrim());
185e1c1138aSLang Hames   }
186e1c1138aSLang Hames 
computeBinOpResult(BinOpToken Op,const EvalResult & LHSResult,const EvalResult & RHSResult) const187e1c1138aSLang Hames   EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,
188e1c1138aSLang Hames                                 const EvalResult &RHSResult) const {
189e1c1138aSLang Hames     switch (Op) {
190f7acdddeSLang Hames     default:
191f7acdddeSLang Hames       llvm_unreachable("Tried to evaluate unrecognized operation.");
192e1c1138aSLang Hames     case BinOpToken::Add:
193e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() + RHSResult.getValue());
194e1c1138aSLang Hames     case BinOpToken::Sub:
195e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() - RHSResult.getValue());
196e1c1138aSLang Hames     case BinOpToken::BitwiseAnd:
197e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() & RHSResult.getValue());
198e1c1138aSLang Hames     case BinOpToken::BitwiseOr:
199e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() | RHSResult.getValue());
200e1c1138aSLang Hames     case BinOpToken::ShiftLeft:
201e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() << RHSResult.getValue());
202e1c1138aSLang Hames     case BinOpToken::ShiftRight:
203e1c1138aSLang Hames       return EvalResult(LHSResult.getValue() >> RHSResult.getValue());
204e1c1138aSLang Hames     }
205e1c1138aSLang Hames   }
206e1c1138aSLang Hames 
207e1c1138aSLang Hames   // Parse a symbol and return a (string, string) pair representing the symbol
208e1c1138aSLang Hames   // name and expression remaining to be parsed.
parseSymbol(StringRef Expr) const209e1c1138aSLang Hames   std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const {
210f7acdddeSLang Hames     size_t FirstNonSymbol = Expr.find_first_not_of("0123456789"
211e1c1138aSLang Hames                                                    "abcdefghijklmnopqrstuvwxyz"
212e1c1138aSLang Hames                                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
213eb99df8eSLang Hames                                                    ":_.$");
214e1c1138aSLang Hames     return std::make_pair(Expr.substr(0, FirstNonSymbol),
215e1c1138aSLang Hames                           Expr.substr(FirstNonSymbol).ltrim());
216e1c1138aSLang Hames   }
217e1c1138aSLang Hames 
218e1c1138aSLang Hames   // Evaluate a call to decode_operand. Decode the instruction operand at the
219e1c1138aSLang Hames   // given symbol and get the value of the requested operand.
220e1c1138aSLang Hames   // Returns an error if the instruction cannot be decoded, or the requested
221e1c1138aSLang Hames   // operand is not an immediate.
222f2fbf437SSimon Pilgrim   // On success, returns a pair containing the value of the operand, plus
223e1c1138aSLang Hames   // the expression remaining to be evaluated.
evalDecodeOperand(StringRef Expr) const224e1c1138aSLang Hames   std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const {
225e1c1138aSLang Hames     if (!Expr.startswith("("))
226e1c1138aSLang Hames       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
227e1c1138aSLang Hames     StringRef RemainingExpr = Expr.substr(1).ltrim();
228e1c1138aSLang Hames     StringRef Symbol;
229e1c1138aSLang Hames     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
230e1c1138aSLang Hames 
23116086b98SLang Hames     if (!Checker.isSymbolValid(Symbol))
232f7acdddeSLang Hames       return std::make_pair(
233f7acdddeSLang Hames           EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
234e1c1138aSLang Hames           "");
235e1c1138aSLang Hames 
236f4e418acSluxufan     // if there is an offset number expr
237f4e418acSluxufan     int64_t Offset = 0;
238f4e418acSluxufan     BinOpToken BinOp;
239f4e418acSluxufan     std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
240f4e418acSluxufan     switch (BinOp) {
241f4e418acSluxufan     case BinOpToken::Add: {
242f4e418acSluxufan       EvalResult Number;
243f4e418acSluxufan       std::tie(Number, RemainingExpr) = evalNumberExpr(RemainingExpr);
244f4e418acSluxufan       Offset = Number.getValue();
245f4e418acSluxufan       break;
246f4e418acSluxufan     }
247f4e418acSluxufan     case BinOpToken::Invalid:
248f4e418acSluxufan       break;
249f4e418acSluxufan     default:
250f4e418acSluxufan       return std::make_pair(
251f4e418acSluxufan           unexpectedToken(RemainingExpr, RemainingExpr,
252f4e418acSluxufan                           "expected '+' for offset or ',' if no offset"),
253f4e418acSluxufan           "");
254f4e418acSluxufan     }
255f4e418acSluxufan 
256e1c1138aSLang Hames     if (!RemainingExpr.startswith(","))
257f7acdddeSLang Hames       return std::make_pair(
258f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
259e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
260e1c1138aSLang Hames 
261e1c1138aSLang Hames     EvalResult OpIdxExpr;
262e1c1138aSLang Hames     std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
263e1c1138aSLang Hames     if (OpIdxExpr.hasError())
264e1c1138aSLang Hames       return std::make_pair(OpIdxExpr, "");
265e1c1138aSLang Hames 
266e1c1138aSLang Hames     if (!RemainingExpr.startswith(")"))
267f7acdddeSLang Hames       return std::make_pair(
268f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
269e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
270e1c1138aSLang Hames 
271e1c1138aSLang Hames     MCInst Inst;
272e1c1138aSLang Hames     uint64_t Size;
273f4e418acSluxufan     if (!decodeInst(Symbol, Inst, Size, Offset))
274f7acdddeSLang Hames       return std::make_pair(
275f7acdddeSLang Hames           EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
276e1c1138aSLang Hames           "");
277e1c1138aSLang Hames 
278e1c1138aSLang Hames     unsigned OpIdx = OpIdxExpr.getValue();
2794a26c0ccSLang Hames     if (OpIdx >= Inst.getNumOperands()) {
2804a26c0ccSLang Hames       std::string ErrMsg;
2814a26c0ccSLang Hames       raw_string_ostream ErrMsgStream(ErrMsg);
2824a26c0ccSLang Hames       ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx)
2838b205306SLang Hames                    << "' for instruction '" << Symbol
2848b205306SLang Hames                    << "'. Instruction has only "
2858b205306SLang Hames                    << format("%i", Inst.getNumOperands())
2868b205306SLang Hames                    << " operands.\nInstruction is:\n  ";
2870e1fe184SSean Silva       Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
2884a26c0ccSLang Hames       return std::make_pair(EvalResult(ErrMsgStream.str()), "");
2894a26c0ccSLang Hames     }
290e1c1138aSLang Hames 
291e1c1138aSLang Hames     const MCOperand &Op = Inst.getOperand(OpIdx);
292e1c1138aSLang Hames     if (!Op.isImm()) {
2934a26c0ccSLang Hames       std::string ErrMsg;
2944a26c0ccSLang Hames       raw_string_ostream ErrMsgStream(ErrMsg);
295f7acdddeSLang Hames       ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '"
296f7acdddeSLang Hames                    << Symbol << "' is not an immediate.\nInstruction is:\n  ";
2970e1fe184SSean Silva       Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
2984a26c0ccSLang Hames 
2994a26c0ccSLang Hames       return std::make_pair(EvalResult(ErrMsgStream.str()), "");
300e1c1138aSLang Hames     }
301e1c1138aSLang Hames 
302e1c1138aSLang Hames     return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
303e1c1138aSLang Hames   }
304e1c1138aSLang Hames 
305f7acdddeSLang Hames   // Evaluate a call to next_pc.
306f7acdddeSLang Hames   // Decode the instruction at the given symbol and return the following program
307f7acdddeSLang Hames   // counter.
308e1c1138aSLang Hames   // Returns an error if the instruction cannot be decoded.
309f7acdddeSLang Hames   // On success, returns a pair containing the next PC, plus of the
310e1c1138aSLang Hames   // expression remaining to be evaluated.
evalNextPC(StringRef Expr,ParseContext PCtx) const311f7acdddeSLang Hames   std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr,
312f7acdddeSLang Hames                                               ParseContext PCtx) const {
313e1c1138aSLang Hames     if (!Expr.startswith("("))
314e1c1138aSLang Hames       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
315e1c1138aSLang Hames     StringRef RemainingExpr = Expr.substr(1).ltrim();
316e1c1138aSLang Hames     StringRef Symbol;
317e1c1138aSLang Hames     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
318e1c1138aSLang Hames 
31916086b98SLang Hames     if (!Checker.isSymbolValid(Symbol))
320f7acdddeSLang Hames       return std::make_pair(
321f7acdddeSLang Hames           EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
322e1c1138aSLang Hames           "");
323e1c1138aSLang Hames 
324e1c1138aSLang Hames     if (!RemainingExpr.startswith(")"))
325f7acdddeSLang Hames       return std::make_pair(
326f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
327e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
328e1c1138aSLang Hames 
329e1c1138aSLang Hames     MCInst Inst;
330f7acdddeSLang Hames     uint64_t InstSize;
331f4e418acSluxufan     if (!decodeInst(Symbol, Inst, InstSize, 0))
332f7acdddeSLang Hames       return std::make_pair(
333f7acdddeSLang Hames           EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
334e1c1138aSLang Hames           "");
335f7acdddeSLang Hames 
336f7acdddeSLang Hames     uint64_t SymbolAddr = PCtx.IsInsideLoad
337b1186036SLang Hames                               ? Checker.getSymbolLocalAddr(Symbol)
338f7acdddeSLang Hames                               : Checker.getSymbolRemoteAddr(Symbol);
339f7acdddeSLang Hames     uint64_t NextPC = SymbolAddr + InstSize;
340e1c1138aSLang Hames 
341e1c1138aSLang Hames     return std::make_pair(EvalResult(NextPC), RemainingExpr);
342e1c1138aSLang Hames   }
343e1c1138aSLang Hames 
344c7c1f215SLang Hames   // Evaluate a call to stub_addr/got_addr.
345f7acdddeSLang Hames   // Look up and return the address of the stub for the given
346f7acdddeSLang Hames   // (<file name>, <section name>, <symbol name>) tuple.
347f7acdddeSLang Hames   // On success, returns a pair containing the stub address, plus the expression
348f7acdddeSLang Hames   // remaining to be evaluated.
349c7c1f215SLang Hames   std::pair<EvalResult, StringRef>
evalStubOrGOTAddr(StringRef Expr,ParseContext PCtx,bool IsStubAddr) const350c7c1f215SLang Hames   evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const {
351f7acdddeSLang Hames     if (!Expr.startswith("("))
352f7acdddeSLang Hames       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
353f7acdddeSLang Hames     StringRef RemainingExpr = Expr.substr(1).ltrim();
354f7acdddeSLang Hames 
355f7acdddeSLang Hames     // Handle file-name specially, as it may contain characters that aren't
356f7acdddeSLang Hames     // legal for symbols.
357c7c1f215SLang Hames     StringRef StubContainerName;
358f7acdddeSLang Hames     size_t ComaIdx = RemainingExpr.find(',');
359c7c1f215SLang Hames     StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim();
360f7acdddeSLang Hames     RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
361f7acdddeSLang Hames 
362f7acdddeSLang Hames     if (!RemainingExpr.startswith(","))
363f7acdddeSLang Hames       return std::make_pair(
364f7acdddeSLang Hames           unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
365f7acdddeSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
366f7acdddeSLang Hames 
367f7acdddeSLang Hames     StringRef Symbol;
368f7acdddeSLang Hames     std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
369f7acdddeSLang Hames 
370f7acdddeSLang Hames     if (!RemainingExpr.startswith(")"))
371f7acdddeSLang Hames       return std::make_pair(
372f7acdddeSLang Hames           unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
373f7acdddeSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
374f7acdddeSLang Hames 
375f7acdddeSLang Hames     uint64_t StubAddr;
37612fc9ca3SKazu Hirata     std::string ErrorMsg;
377c7c1f215SLang Hames     std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
378c7c1f215SLang Hames         StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr);
379f7acdddeSLang Hames 
380f7acdddeSLang Hames     if (ErrorMsg != "")
381f7acdddeSLang Hames       return std::make_pair(EvalResult(ErrorMsg), "");
382f7acdddeSLang Hames 
383f7acdddeSLang Hames     return std::make_pair(EvalResult(StubAddr), RemainingExpr);
384f7acdddeSLang Hames   }
385f7acdddeSLang Hames 
evalSectionAddr(StringRef Expr,ParseContext PCtx) const386587ee6abSLang Hames   std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr,
387587ee6abSLang Hames                                                    ParseContext PCtx) const {
388587ee6abSLang Hames     if (!Expr.startswith("("))
389587ee6abSLang Hames       return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
390587ee6abSLang Hames     StringRef RemainingExpr = Expr.substr(1).ltrim();
391587ee6abSLang Hames 
392587ee6abSLang Hames     // Handle file-name specially, as it may contain characters that aren't
393587ee6abSLang Hames     // legal for symbols.
394587ee6abSLang Hames     StringRef FileName;
395587ee6abSLang Hames     size_t ComaIdx = RemainingExpr.find(',');
396587ee6abSLang Hames     FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
397587ee6abSLang Hames     RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
398587ee6abSLang Hames 
399587ee6abSLang Hames     if (!RemainingExpr.startswith(","))
400587ee6abSLang Hames       return std::make_pair(
401587ee6abSLang Hames           unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
402587ee6abSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
403587ee6abSLang Hames 
404587ee6abSLang Hames     StringRef SectionName;
40519e402d2SLang Hames     size_t CloseParensIdx = RemainingExpr.find(')');
40619e402d2SLang Hames     SectionName = RemainingExpr.substr(0, CloseParensIdx).rtrim();
40719e402d2SLang Hames     RemainingExpr = RemainingExpr.substr(CloseParensIdx).ltrim();
408587ee6abSLang Hames 
409587ee6abSLang Hames     if (!RemainingExpr.startswith(")"))
410587ee6abSLang Hames       return std::make_pair(
411587ee6abSLang Hames           unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
412587ee6abSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
413587ee6abSLang Hames 
414587ee6abSLang Hames     uint64_t StubAddr;
41512fc9ca3SKazu Hirata     std::string ErrorMsg;
416587ee6abSLang Hames     std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(
417587ee6abSLang Hames         FileName, SectionName, PCtx.IsInsideLoad);
418587ee6abSLang Hames 
419587ee6abSLang Hames     if (ErrorMsg != "")
420587ee6abSLang Hames       return std::make_pair(EvalResult(ErrorMsg), "");
421587ee6abSLang Hames 
422587ee6abSLang Hames     return std::make_pair(EvalResult(StubAddr), RemainingExpr);
423587ee6abSLang Hames   }
424587ee6abSLang Hames 
425e1c1138aSLang Hames   // Evaluate an identiefer expr, which may be a symbol, or a call to
426e1c1138aSLang Hames   // one of the builtin functions: get_insn_opcode or get_insn_length.
427e1c1138aSLang Hames   // Return the result, plus the expression remaining to be parsed.
evalIdentifierExpr(StringRef Expr,ParseContext PCtx) const428f7acdddeSLang Hames   std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr,
429f7acdddeSLang Hames                                                       ParseContext PCtx) const {
430e1c1138aSLang Hames     StringRef Symbol;
431e1c1138aSLang Hames     StringRef RemainingExpr;
432e1c1138aSLang Hames     std::tie(Symbol, RemainingExpr) = parseSymbol(Expr);
433e1c1138aSLang Hames 
434e1c1138aSLang Hames     // Check for builtin function calls.
435e1c1138aSLang Hames     if (Symbol == "decode_operand")
436e1c1138aSLang Hames       return evalDecodeOperand(RemainingExpr);
437e1c1138aSLang Hames     else if (Symbol == "next_pc")
438f7acdddeSLang Hames       return evalNextPC(RemainingExpr, PCtx);
439f7acdddeSLang Hames     else if (Symbol == "stub_addr")
440c7c1f215SLang Hames       return evalStubOrGOTAddr(RemainingExpr, PCtx, true);
441c7c1f215SLang Hames     else if (Symbol == "got_addr")
442c7c1f215SLang Hames       return evalStubOrGOTAddr(RemainingExpr, PCtx, false);
443587ee6abSLang Hames     else if (Symbol == "section_addr")
444587ee6abSLang Hames       return evalSectionAddr(RemainingExpr, PCtx);
445e1c1138aSLang Hames 
44616086b98SLang Hames     if (!Checker.isSymbolValid(Symbol)) {
44716086b98SLang Hames       std::string ErrMsg("No known address for symbol '");
44816086b98SLang Hames       ErrMsg += Symbol;
44916086b98SLang Hames       ErrMsg += "'";
45016086b98SLang Hames       if (Symbol.startswith("L"))
45116086b98SLang Hames         ErrMsg += " (this appears to be an assembler local label - "
45216086b98SLang Hames                   " perhaps drop the 'L'?)";
45316086b98SLang Hames 
45416086b98SLang Hames       return std::make_pair(EvalResult(ErrMsg), "");
45516086b98SLang Hames     }
45616086b98SLang Hames 
457f7acdddeSLang Hames     // The value for the symbol depends on the context we're evaluating in:
458f7acdddeSLang Hames     // Inside a load this is the address in the linker's memory, outside a
459f7acdddeSLang Hames     // load it's the address in the target processes memory.
460b1186036SLang Hames     uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol)
461f7acdddeSLang Hames                                        : Checker.getSymbolRemoteAddr(Symbol);
462f7acdddeSLang Hames 
463e1c1138aSLang Hames     // Looks like a plain symbol reference.
464f7acdddeSLang Hames     return std::make_pair(EvalResult(Value), RemainingExpr);
465e1c1138aSLang Hames   }
466e1c1138aSLang Hames 
467e1c1138aSLang Hames   // Parse a number (hexadecimal or decimal) and return a (string, string)
468e1c1138aSLang Hames   // pair representing the number and the expression remaining to be parsed.
parseNumberString(StringRef Expr) const469e1c1138aSLang Hames   std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {
470e1c1138aSLang Hames     size_t FirstNonDigit = StringRef::npos;
471e1c1138aSLang Hames     if (Expr.startswith("0x")) {
472e1c1138aSLang Hames       FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);
473e1c1138aSLang Hames       if (FirstNonDigit == StringRef::npos)
474e1c1138aSLang Hames         FirstNonDigit = Expr.size();
475e1c1138aSLang Hames     } else {
476e1c1138aSLang Hames       FirstNonDigit = Expr.find_first_not_of("0123456789");
477e1c1138aSLang Hames       if (FirstNonDigit == StringRef::npos)
478e1c1138aSLang Hames         FirstNonDigit = Expr.size();
479e1c1138aSLang Hames     }
480e1c1138aSLang Hames     return std::make_pair(Expr.substr(0, FirstNonDigit),
481e1c1138aSLang Hames                           Expr.substr(FirstNonDigit));
482e1c1138aSLang Hames   }
483e1c1138aSLang Hames 
484f2fbf437SSimon Pilgrim   // Evaluate a constant numeric expression (hexadecimal or decimal) and
485e1c1138aSLang Hames   // return a pair containing the result, and the expression remaining to be
486e1c1138aSLang Hames   // evaluated.
evalNumberExpr(StringRef Expr) const487e1c1138aSLang Hames   std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {
488e1c1138aSLang Hames     StringRef ValueStr;
489e1c1138aSLang Hames     StringRef RemainingExpr;
490e1c1138aSLang Hames     std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
491e1c1138aSLang Hames 
492e1c1138aSLang Hames     if (ValueStr.empty() || !isdigit(ValueStr[0]))
493f7acdddeSLang Hames       return std::make_pair(
494f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), "");
495e1c1138aSLang Hames     uint64_t Value;
496e1c1138aSLang Hames     ValueStr.getAsInteger(0, Value);
497e1c1138aSLang Hames     return std::make_pair(EvalResult(Value), RemainingExpr);
498e1c1138aSLang Hames   }
499e1c1138aSLang Hames 
500e1c1138aSLang Hames   // Evaluate an expression of the form "(<expr>)" and return a pair
501e1c1138aSLang Hames   // containing the result of evaluating <expr>, plus the expression
502e1c1138aSLang Hames   // remaining to be parsed.
evalParensExpr(StringRef Expr,ParseContext PCtx) const503f7acdddeSLang Hames   std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr,
504f7acdddeSLang Hames                                                   ParseContext PCtx) const {
505e1c1138aSLang Hames     assert(Expr.startswith("(") && "Not a parenthesized expression");
506e1c1138aSLang Hames     EvalResult SubExprResult;
507e1c1138aSLang Hames     StringRef RemainingExpr;
508e1c1138aSLang Hames     std::tie(SubExprResult, RemainingExpr) =
509f7acdddeSLang Hames         evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx);
510e1c1138aSLang Hames     if (SubExprResult.hasError())
511e1c1138aSLang Hames       return std::make_pair(SubExprResult, "");
512e1c1138aSLang Hames     if (!RemainingExpr.startswith(")"))
513f7acdddeSLang Hames       return std::make_pair(
514f7acdddeSLang Hames           unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
515e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
516e1c1138aSLang Hames     return std::make_pair(SubExprResult, RemainingExpr);
517e1c1138aSLang Hames   }
518e1c1138aSLang Hames 
519e1c1138aSLang Hames   // Evaluate an expression in one of the following forms:
520f7acdddeSLang Hames   //   *{<number>}<expr>
521e1c1138aSLang Hames   // Return a pair containing the result, plus the expression remaining to be
522e1c1138aSLang Hames   // parsed.
evalLoadExpr(StringRef Expr) const523e1c1138aSLang Hames   std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
524e1c1138aSLang Hames     assert(Expr.startswith("*") && "Not a load expression");
525e1c1138aSLang Hames     StringRef RemainingExpr = Expr.substr(1).ltrim();
526f7acdddeSLang Hames 
527e1c1138aSLang Hames     // Parse read size.
528e1c1138aSLang Hames     if (!RemainingExpr.startswith("{"))
529e1c1138aSLang Hames       return std::make_pair(EvalResult("Expected '{' following '*'."), "");
530e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
531e1c1138aSLang Hames     EvalResult ReadSizeExpr;
532e1c1138aSLang Hames     std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
533e1c1138aSLang Hames     if (ReadSizeExpr.hasError())
534e1c1138aSLang Hames       return std::make_pair(ReadSizeExpr, RemainingExpr);
535e1c1138aSLang Hames     uint64_t ReadSize = ReadSizeExpr.getValue();
536e1c1138aSLang Hames     if (ReadSize < 1 || ReadSize > 8)
537e1c1138aSLang Hames       return std::make_pair(EvalResult("Invalid size for dereference."), "");
538e1c1138aSLang Hames     if (!RemainingExpr.startswith("}"))
539e1c1138aSLang Hames       return std::make_pair(EvalResult("Missing '}' for dereference."), "");
540e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
541e1c1138aSLang Hames 
542f7acdddeSLang Hames     // Evaluate the expression representing the load address.
543f7acdddeSLang Hames     ParseContext LoadCtx(true);
544f7acdddeSLang Hames     EvalResult LoadAddrExprResult;
545f7acdddeSLang Hames     std::tie(LoadAddrExprResult, RemainingExpr) =
546f7acdddeSLang Hames         evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx);
547e1c1138aSLang Hames 
548f7acdddeSLang Hames     if (LoadAddrExprResult.hasError())
549f7acdddeSLang Hames       return std::make_pair(LoadAddrExprResult, "");
550e1c1138aSLang Hames 
551f7acdddeSLang Hames     uint64_t LoadAddr = LoadAddrExprResult.getValue();
552e1c1138aSLang Hames 
55323085ec3SLang Hames     // If there is no error but the content pointer is null then this is a
55423085ec3SLang Hames     // zero-fill symbol/section.
55523085ec3SLang Hames     if (LoadAddr == 0)
55623085ec3SLang Hames       return std::make_pair(0, RemainingExpr);
55723085ec3SLang Hames 
558e1c1138aSLang Hames     return std::make_pair(
559f7acdddeSLang Hames         EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),
560e1c1138aSLang Hames         RemainingExpr);
561e1c1138aSLang Hames   }
562e1c1138aSLang Hames 
563e1c1138aSLang Hames   // Evaluate a "simple" expression. This is any expression that _isn't_ an
564e1c1138aSLang Hames   // un-parenthesized binary expression.
565e1c1138aSLang Hames   //
566e1c1138aSLang Hames   // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
567e1c1138aSLang Hames   //
568e1c1138aSLang Hames   // Returns a pair containing the result of the evaluation, plus the
569e1c1138aSLang Hames   // expression remaining to be parsed.
evalSimpleExpr(StringRef Expr,ParseContext PCtx) const570f7acdddeSLang Hames   std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr,
571f7acdddeSLang Hames                                                   ParseContext PCtx) const {
572e1c1138aSLang Hames     EvalResult SubExprResult;
573e1c1138aSLang Hames     StringRef RemainingExpr;
574e1c1138aSLang Hames 
575e1c1138aSLang Hames     if (Expr.empty())
576e1c1138aSLang Hames       return std::make_pair(EvalResult("Unexpected end of expression"), "");
577e1c1138aSLang Hames 
578e1c1138aSLang Hames     if (Expr[0] == '(')
579f7acdddeSLang Hames       std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx);
580e1c1138aSLang Hames     else if (Expr[0] == '*')
581e1c1138aSLang Hames       std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
582c90a85ffSLang Hames     else if (isalpha(Expr[0]) || Expr[0] == '_')
583f7acdddeSLang Hames       std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);
584e1c1138aSLang Hames     else if (isdigit(Expr[0]))
585e1c1138aSLang Hames       std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
586587ee6abSLang Hames     else
587587ee6abSLang Hames       return std::make_pair(
588587ee6abSLang Hames           unexpectedToken(Expr, Expr,
589587ee6abSLang Hames                           "expected '(', '*', identifier, or number"), "");
590e1c1138aSLang Hames 
591e1c1138aSLang Hames     if (SubExprResult.hasError())
592e1c1138aSLang Hames       return std::make_pair(SubExprResult, RemainingExpr);
593e1c1138aSLang Hames 
594e1c1138aSLang Hames     // Evaluate bit-slice if present.
595e1c1138aSLang Hames     if (RemainingExpr.startswith("["))
596e1c1138aSLang Hames       std::tie(SubExprResult, RemainingExpr) =
597e1c1138aSLang Hames           evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
598e1c1138aSLang Hames 
599e1c1138aSLang Hames     return std::make_pair(SubExprResult, RemainingExpr);
600e1c1138aSLang Hames   }
601e1c1138aSLang Hames 
602e1c1138aSLang Hames   // Evaluate a bit-slice of an expression.
603e1c1138aSLang Hames   // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
604e1c1138aSLang Hames   // slice is the bits between high and low (inclusive) in the original
605e1c1138aSLang Hames   // expression, right shifted so that the "low" bit is in position 0 in the
606e1c1138aSLang Hames   // result.
607e1c1138aSLang Hames   // Returns a pair containing the result of the slice operation, plus the
608e1c1138aSLang Hames   // expression remaining to be parsed.
609f7acdddeSLang Hames   std::pair<EvalResult, StringRef>
evalSliceExpr(const std::pair<EvalResult,StringRef> & Ctx) const6101afc1de4SBenjamin Kramer   evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const {
611e1c1138aSLang Hames     EvalResult SubExprResult;
612e1c1138aSLang Hames     StringRef RemainingExpr;
613e1c1138aSLang Hames     std::tie(SubExprResult, RemainingExpr) = Ctx;
614e1c1138aSLang Hames 
615e1c1138aSLang Hames     assert(RemainingExpr.startswith("[") && "Not a slice expr.");
616e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
617e1c1138aSLang Hames 
618e1c1138aSLang Hames     EvalResult HighBitExpr;
619e1c1138aSLang Hames     std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
620e1c1138aSLang Hames 
621e1c1138aSLang Hames     if (HighBitExpr.hasError())
622e1c1138aSLang Hames       return std::make_pair(HighBitExpr, RemainingExpr);
623e1c1138aSLang Hames 
624e1c1138aSLang Hames     if (!RemainingExpr.startswith(":"))
625f7acdddeSLang Hames       return std::make_pair(
626f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");
627e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
628e1c1138aSLang Hames 
629e1c1138aSLang Hames     EvalResult LowBitExpr;
630e1c1138aSLang Hames     std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
631e1c1138aSLang Hames 
632e1c1138aSLang Hames     if (LowBitExpr.hasError())
633e1c1138aSLang Hames       return std::make_pair(LowBitExpr, RemainingExpr);
634e1c1138aSLang Hames 
635e1c1138aSLang Hames     if (!RemainingExpr.startswith("]"))
636f7acdddeSLang Hames       return std::make_pair(
637f7acdddeSLang Hames           unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");
638e1c1138aSLang Hames     RemainingExpr = RemainingExpr.substr(1).ltrim();
639e1c1138aSLang Hames 
640e1c1138aSLang Hames     unsigned HighBit = HighBitExpr.getValue();
641e1c1138aSLang Hames     unsigned LowBit = LowBitExpr.getValue();
642e1c1138aSLang Hames     uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1;
643e1c1138aSLang Hames     uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask;
644e1c1138aSLang Hames     return std::make_pair(EvalResult(SlicedValue), RemainingExpr);
645e1c1138aSLang Hames   }
646e1c1138aSLang Hames 
647e1c1138aSLang Hames   // Evaluate a "complex" expression.
648e1c1138aSLang Hames   // Takes an already evaluated subexpression and checks for the presence of a
649e1c1138aSLang Hames   // binary operator, computing the result of the binary operation if one is
650e1c1138aSLang Hames   // found. Used to make arithmetic expressions left-associative.
651e1c1138aSLang Hames   // Returns a pair containing the ultimate result of evaluating the
652e1c1138aSLang Hames   // expression, plus the expression remaining to be evaluated.
653f7acdddeSLang Hames   std::pair<EvalResult, StringRef>
evalComplexExpr(const std::pair<EvalResult,StringRef> & LHSAndRemaining,ParseContext PCtx) const6541afc1de4SBenjamin Kramer   evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining,
655f7acdddeSLang Hames                   ParseContext PCtx) const {
656e1c1138aSLang Hames     EvalResult LHSResult;
657e1c1138aSLang Hames     StringRef RemainingExpr;
658f7acdddeSLang Hames     std::tie(LHSResult, RemainingExpr) = LHSAndRemaining;
659e1c1138aSLang Hames 
660e1c1138aSLang Hames     // If there was an error, or there's nothing left to evaluate, return the
661e1c1138aSLang Hames     // result.
662e1c1138aSLang Hames     if (LHSResult.hasError() || RemainingExpr == "")
663e1c1138aSLang Hames       return std::make_pair(LHSResult, RemainingExpr);
664e1c1138aSLang Hames 
665e1c1138aSLang Hames     // Otherwise check if this is a binary expressioan.
666e1c1138aSLang Hames     BinOpToken BinOp;
667e1c1138aSLang Hames     std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
668e1c1138aSLang Hames 
669e1c1138aSLang Hames     // If this isn't a recognized expression just return.
670e1c1138aSLang Hames     if (BinOp == BinOpToken::Invalid)
671e1c1138aSLang Hames       return std::make_pair(LHSResult, RemainingExpr);
672e1c1138aSLang Hames 
673e1c1138aSLang Hames     // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
674e1c1138aSLang Hames     EvalResult RHSResult;
675f7acdddeSLang Hames     std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);
676e1c1138aSLang Hames 
677e1c1138aSLang Hames     // If there was an error evaluating the RHS, return it.
678e1c1138aSLang Hames     if (RHSResult.hasError())
679e1c1138aSLang Hames       return std::make_pair(RHSResult, RemainingExpr);
680e1c1138aSLang Hames 
681e1c1138aSLang Hames     // This is a binary expression - evaluate and try to continue as a
682e1c1138aSLang Hames     // complex expr.
683e1c1138aSLang Hames     EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
684e1c1138aSLang Hames 
685f7acdddeSLang Hames     return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);
686e1c1138aSLang Hames   }
687e1c1138aSLang Hames 
decodeInst(StringRef Symbol,MCInst & Inst,uint64_t & Size,int64_t Offset) const688f4e418acSluxufan   bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size,
689f4e418acSluxufan                   int64_t Offset) const {
690e1c1138aSLang Hames     MCDisassembler *Dis = Checker.Disassembler;
691941f247dSLang Hames     StringRef SymbolMem = Checker.getSymbolContent(Symbol);
692f4e418acSluxufan     ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin() + Offset,
693f4e418acSluxufan                                   SymbolMem.size() - Offset);
694e1c1138aSLang Hames 
695e1c1138aSLang Hames     MCDisassembler::DecodeStatus S =
6966fdd6a7bSFangrui Song         Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls());
697e1c1138aSLang Hames 
698e1c1138aSLang Hames     return (S == MCDisassembler::Success);
699e1c1138aSLang Hames   }
700e1c1138aSLang Hames };
701f4e418acSluxufan } // namespace llvm
702e1c1138aSLang Hames 
RuntimeDyldCheckerImpl(IsSymbolValidFunction IsSymbolValid,GetSymbolInfoFunction GetSymbolInfo,GetSectionInfoFunction GetSectionInfo,GetStubInfoFunction GetStubInfo,GetGOTInfoFunction GetGOTInfo,support::endianness Endianness,MCDisassembler * Disassembler,MCInstPrinter * InstPrinter,raw_ostream & ErrStream)703941f247dSLang Hames RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(
704c7c1f215SLang Hames     IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
705c7c1f215SLang Hames     GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
706c7c1f215SLang Hames     GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
707c7c1f215SLang Hames     MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
708f7acdddeSLang Hames     raw_ostream &ErrStream)
709941f247dSLang Hames     : IsSymbolValid(std::move(IsSymbolValid)),
710c7c1f215SLang Hames       GetSymbolInfo(std::move(GetSymbolInfo)),
711c7c1f215SLang Hames       GetSectionInfo(std::move(GetSectionInfo)),
712c7c1f215SLang Hames       GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)),
713941f247dSLang Hames       Endianness(Endianness), Disassembler(Disassembler),
714941f247dSLang Hames       InstPrinter(InstPrinter), ErrStream(ErrStream) {}
715f7acdddeSLang Hames 
check(StringRef CheckExpr) const716f7acdddeSLang Hames bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const {
717e1c1138aSLang Hames   CheckExpr = CheckExpr.trim();
718d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
719d34e60caSNicola Zaghen                     << "'...\n");
720e1c1138aSLang Hames   RuntimeDyldCheckerExprEval P(*this, ErrStream);
721e1c1138aSLang Hames   bool Result = P.evaluate(CheckExpr);
722e1c1138aSLang Hames   (void)Result;
723d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
724e1c1138aSLang Hames                     << (Result ? "passed" : "FAILED") << ".\n");
725e1c1138aSLang Hames   return Result;
726e1c1138aSLang Hames }
727e1c1138aSLang Hames 
checkAllRulesInBuffer(StringRef RulePrefix,MemoryBuffer * MemBuf) const728f7acdddeSLang Hames bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,
729e1c1138aSLang Hames                                                    MemoryBuffer *MemBuf) const {
730e1c1138aSLang Hames   bool DidAllTestsPass = true;
731e1c1138aSLang Hames   unsigned NumRules = 0;
732e1c1138aSLang Hames 
733aed57125SLang Hames   std::string CheckExpr;
734e1c1138aSLang Hames   const char *LineStart = MemBuf->getBufferStart();
735e1c1138aSLang Hames 
736e1c1138aSLang Hames   // Eat whitespace.
737d10c995bSSam McCall   while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))
738e1c1138aSLang Hames     ++LineStart;
739e1c1138aSLang Hames 
740e1c1138aSLang Hames   while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') {
741e1c1138aSLang Hames     const char *LineEnd = LineStart;
742f7acdddeSLang Hames     while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&
743f7acdddeSLang Hames            *LineEnd != '\n')
744e1c1138aSLang Hames       ++LineEnd;
745e1c1138aSLang Hames 
746e1c1138aSLang Hames     StringRef Line(LineStart, LineEnd - LineStart);
747aed57125SLang Hames     if (Line.startswith(RulePrefix))
748aed57125SLang Hames       CheckExpr += Line.substr(RulePrefix.size()).str();
749aed57125SLang Hames 
750aed57125SLang Hames     // If there's a check expr string...
751aed57125SLang Hames     if (!CheckExpr.empty()) {
752aed57125SLang Hames       // ... and it's complete then run it, otherwise remove the trailer '\'.
753aed57125SLang Hames       if (CheckExpr.back() != '\\') {
754aed57125SLang Hames         DidAllTestsPass &= check(CheckExpr);
755aed57125SLang Hames         CheckExpr.clear();
756e1c1138aSLang Hames         ++NumRules;
757aed57125SLang Hames       } else
758aed57125SLang Hames         CheckExpr.pop_back();
759e1c1138aSLang Hames     }
760e1c1138aSLang Hames 
761e1c1138aSLang Hames     // Eat whitespace.
762e1c1138aSLang Hames     LineStart = LineEnd;
763d10c995bSSam McCall     while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))
764e1c1138aSLang Hames       ++LineStart;
765e1c1138aSLang Hames   }
766e1c1138aSLang Hames   return DidAllTestsPass && (NumRules != 0);
767e1c1138aSLang Hames }
768e1c1138aSLang Hames 
isSymbolValid(StringRef Symbol) const769f7acdddeSLang Hames bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
770941f247dSLang Hames   return IsSymbolValid(Symbol);
771e1c1138aSLang Hames }
772e1c1138aSLang Hames 
getSymbolLocalAddr(StringRef Symbol) const773b1186036SLang Hames uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const {
774c7c1f215SLang Hames   auto SymInfo = GetSymbolInfo(Symbol);
775c7c1f215SLang Hames   if (!SymInfo) {
776c7c1f215SLang Hames     logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
777941f247dSLang Hames     return 0;
778941f247dSLang Hames   }
77923085ec3SLang Hames 
78023085ec3SLang Hames   if (SymInfo->isZeroFill())
78123085ec3SLang Hames     return 0;
78223085ec3SLang Hames 
783c7c1f215SLang Hames   return static_cast<uint64_t>(
78423085ec3SLang Hames       reinterpret_cast<uintptr_t>(SymInfo->getContent().data()));
785e1c1138aSLang Hames }
786e1c1138aSLang Hames 
getSymbolRemoteAddr(StringRef Symbol) const787f7acdddeSLang Hames uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
788c7c1f215SLang Hames   auto SymInfo = GetSymbolInfo(Symbol);
789c7c1f215SLang Hames   if (!SymInfo) {
790c7c1f215SLang Hames     logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
791b72f4845SLang Hames     return 0;
792b72f4845SLang Hames   }
793941f247dSLang Hames 
79423085ec3SLang Hames   return SymInfo->getTargetAddress();
795f7acdddeSLang Hames }
796f7acdddeSLang Hames 
readMemoryAtAddr(uint64_t SrcAddr,unsigned Size) const797f7acdddeSLang Hames uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr,
798e1c1138aSLang Hames                                                   unsigned Size) const {
799f7acdddeSLang Hames   uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr);
800f7acdddeSLang Hames   assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range.");
801941f247dSLang Hames   void *Ptr = reinterpret_cast<void*>(PtrSizedAddr);
802941f247dSLang Hames 
803941f247dSLang Hames   switch (Size) {
804941f247dSLang Hames   case 1:
805941f247dSLang Hames     return support::endian::read<uint8_t>(Ptr, Endianness);
806941f247dSLang Hames   case 2:
807941f247dSLang Hames     return support::endian::read<uint16_t>(Ptr, Endianness);
808941f247dSLang Hames   case 4:
809941f247dSLang Hames     return support::endian::read<uint32_t>(Ptr, Endianness);
810941f247dSLang Hames   case 8:
811941f247dSLang Hames     return support::endian::read<uint64_t>(Ptr, Endianness);
812941f247dSLang Hames   }
813941f247dSLang Hames   llvm_unreachable("Unsupported read size");
814e1c1138aSLang Hames }
815e1c1138aSLang Hames 
getSymbolContent(StringRef Symbol) const816941f247dSLang Hames StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
817c7c1f215SLang Hames   auto SymInfo = GetSymbolInfo(Symbol);
818c7c1f215SLang Hames   if (!SymInfo) {
819c7c1f215SLang Hames     logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
820941f247dSLang Hames     return StringRef();
821cce313b0SLang Hames   }
8220269a407SLang Hames   return {SymInfo->getContent().data(), SymInfo->getContent().size()};
823587ee6abSLang Hames }
824587ee6abSLang Hames 
getSectionAddr(StringRef FileName,StringRef SectionName,bool IsInsideLoad) const825587ee6abSLang Hames std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
826587ee6abSLang Hames     StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
827587ee6abSLang Hames 
828c7c1f215SLang Hames   auto SecInfo = GetSectionInfo(FileName, SectionName);
829c7c1f215SLang Hames   if (!SecInfo) {
830941f247dSLang Hames     std::string ErrMsg;
831587ee6abSLang Hames     {
832941f247dSLang Hames       raw_string_ostream ErrMsgStream(ErrMsg);
833c7c1f215SLang Hames       logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream,
834c7c1f215SLang Hames                             "RTDyldChecker: ");
835c7c1f215SLang Hames     }
836c7c1f215SLang Hames     return std::make_pair(0, std::move(ErrMsg));
837c7c1f215SLang Hames   }
838c7c1f215SLang Hames 
839c7c1f215SLang Hames   // If this address is being looked up in "load" mode, return the content
840c7c1f215SLang Hames   // pointer, otherwise return the target address.
841c7c1f215SLang Hames 
842c7c1f215SLang Hames   uint64_t Addr = 0;
843c7c1f215SLang Hames 
84423085ec3SLang Hames   if (IsInsideLoad) {
84523085ec3SLang Hames     if (SecInfo->isZeroFill())
84623085ec3SLang Hames       Addr = 0;
847c7c1f215SLang Hames     else
84823085ec3SLang Hames       Addr = pointerToJITTargetAddress(SecInfo->getContent().data());
84923085ec3SLang Hames   } else
85023085ec3SLang Hames     Addr = SecInfo->getTargetAddress();
851c7c1f215SLang Hames 
852c7c1f215SLang Hames   return std::make_pair(Addr, "");
853c7c1f215SLang Hames }
854c7c1f215SLang Hames 
getStubOrGOTAddrFor(StringRef StubContainerName,StringRef SymbolName,bool IsInsideLoad,bool IsStubAddr) const855c7c1f215SLang Hames std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
856c7c1f215SLang Hames     StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad,
857c7c1f215SLang Hames     bool IsStubAddr) const {
858c7c1f215SLang Hames 
859c7c1f215SLang Hames   auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName)
860c7c1f215SLang Hames                              : GetGOTInfo(StubContainerName, SymbolName);
861c7c1f215SLang Hames 
862c7c1f215SLang Hames   if (!StubInfo) {
863c7c1f215SLang Hames     std::string ErrMsg;
864c7c1f215SLang Hames     {
865c7c1f215SLang Hames       raw_string_ostream ErrMsgStream(ErrMsg);
866c7c1f215SLang Hames       logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream,
867941f247dSLang Hames                             "RTDyldChecker: ");
868941f247dSLang Hames     }
869941f247dSLang Hames     return std::make_pair((uint64_t)0, std::move(ErrMsg));
870587ee6abSLang Hames   }
871587ee6abSLang Hames 
872c7c1f215SLang Hames   uint64_t Addr = 0;
873c7c1f215SLang Hames 
87423085ec3SLang Hames   if (IsInsideLoad) {
87523085ec3SLang Hames     if (StubInfo->isZeroFill())
87623085ec3SLang Hames       return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");
87723085ec3SLang Hames     Addr = pointerToJITTargetAddress(StubInfo->getContent().data());
87823085ec3SLang Hames   } else
87923085ec3SLang Hames     Addr = StubInfo->getTargetAddress();
880c7c1f215SLang Hames 
881c7c1f215SLang Hames   return std::make_pair(Addr, "");
882f7acdddeSLang Hames }
883f7acdddeSLang Hames 
RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,GetSymbolInfoFunction GetSymbolInfo,GetSectionInfoFunction GetSectionInfo,GetStubInfoFunction GetStubInfo,GetGOTInfoFunction GetGOTInfo,support::endianness Endianness,MCDisassembler * Disassembler,MCInstPrinter * InstPrinter,raw_ostream & ErrStream)884941f247dSLang Hames RuntimeDyldChecker::RuntimeDyldChecker(
885c7c1f215SLang Hames     IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
886c7c1f215SLang Hames     GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
887c7c1f215SLang Hames     GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
888c7c1f215SLang Hames     MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
889f7acdddeSLang Hames     raw_ostream &ErrStream)
8900eaee545SJonas Devlieghere     : Impl(::std::make_unique<RuntimeDyldCheckerImpl>(
891c7c1f215SLang Hames           std::move(IsSymbolValid), std::move(GetSymbolInfo),
892c7c1f215SLang Hames           std::move(GetSectionInfo), std::move(GetStubInfo),
893c7c1f215SLang Hames           std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter,
894c7c1f215SLang Hames           ErrStream)) {}
895f7acdddeSLang Hames 
8963a3cb929SKazu Hirata RuntimeDyldChecker::~RuntimeDyldChecker() = default;
897f7acdddeSLang Hames 
check(StringRef CheckExpr) const898f7acdddeSLang Hames bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
899f7acdddeSLang Hames   return Impl->check(CheckExpr);
900f7acdddeSLang Hames }
901f7acdddeSLang Hames 
checkAllRulesInBuffer(StringRef RulePrefix,MemoryBuffer * MemBuf) const902f7acdddeSLang Hames bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix,
903f7acdddeSLang Hames                                                MemoryBuffer *MemBuf) const {
904f7acdddeSLang Hames   return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
905e1c1138aSLang Hames }
906778ef5b2SLang Hames 
907778ef5b2SLang Hames std::pair<uint64_t, std::string>
getSectionAddr(StringRef FileName,StringRef SectionName,bool LocalAddress)908778ef5b2SLang Hames RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName,
909b1186036SLang Hames                                    bool LocalAddress) {
910b1186036SLang Hames   return Impl->getSectionAddr(FileName, SectionName, LocalAddress);
911778ef5b2SLang Hames }
912