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