1 //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
10 #include "RuntimeDyldCheckerImpl.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
15 #include "llvm/MC/MCInst.h"
16 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/MSVCErrorWorkarounds.h"
18 #include "llvm/Support/Path.h"
23 #define DEBUG_TYPE "rtdyld"
29 // Helper class that implements the language evaluated by RuntimeDyldChecker.
30 class RuntimeDyldCheckerExprEval
{
32 RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl
&Checker
,
33 raw_ostream
&ErrStream
)
36 bool evaluate(StringRef Expr
) const {
37 // Expect equality expression of the form 'LHS = RHS'.
39 size_t EQIdx
= Expr
.find('=');
41 ParseContext
OutsideLoad(false);
44 StringRef LHSExpr
= Expr
.substr(0, EQIdx
).rtrim();
45 StringRef RemainingExpr
;
47 std::tie(LHSResult
, RemainingExpr
) =
48 evalComplexExpr(evalSimpleExpr(LHSExpr
, OutsideLoad
), OutsideLoad
);
49 if (LHSResult
.hasError())
50 return handleError(Expr
, LHSResult
);
51 if (RemainingExpr
!= "")
52 return handleError(Expr
, unexpectedToken(RemainingExpr
, LHSExpr
, ""));
55 StringRef RHSExpr
= Expr
.substr(EQIdx
+ 1).ltrim();
57 std::tie(RHSResult
, RemainingExpr
) =
58 evalComplexExpr(evalSimpleExpr(RHSExpr
, OutsideLoad
), OutsideLoad
);
59 if (RHSResult
.hasError())
60 return handleError(Expr
, RHSResult
);
61 if (RemainingExpr
!= "")
62 return handleError(Expr
, unexpectedToken(RemainingExpr
, RHSExpr
, ""));
64 if (LHSResult
.getValue() != RHSResult
.getValue()) {
65 Checker
.ErrStream
<< "Expression '" << Expr
<< "' is false: "
66 << format("0x%" PRIx64
, LHSResult
.getValue())
67 << " != " << format("0x%" PRIx64
, RHSResult
.getValue())
75 // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In
76 // particular, it needs to know whether a symbol is being evaluated in the
77 // context of a load, in which case we want the linker's local address for
78 // the symbol, or outside of a load, in which case we want the symbol's
79 // address in the remote target.
83 ParseContext(bool IsInsideLoad
) : IsInsideLoad(IsInsideLoad
) {}
86 const RuntimeDyldCheckerImpl
&Checker
;
88 enum class BinOpToken
: unsigned {
100 EvalResult() : Value(0), ErrorMsg("") {}
101 EvalResult(uint64_t Value
) : Value(Value
), ErrorMsg("") {}
102 EvalResult(std::string ErrorMsg
)
103 : Value(0), ErrorMsg(std::move(ErrorMsg
)) {}
104 uint64_t getValue() const { return Value
; }
105 bool hasError() const { return ErrorMsg
!= ""; }
106 const std::string
&getErrorMsg() const { return ErrorMsg
; }
110 std::string ErrorMsg
;
113 StringRef
getTokenForError(StringRef Expr
) const {
117 StringRef Token
, Remaining
;
118 if (isalpha(Expr
[0]))
119 std::tie(Token
, Remaining
) = parseSymbol(Expr
);
120 else if (isdigit(Expr
[0]))
121 std::tie(Token
, Remaining
) = parseNumberString(Expr
);
124 if (Expr
.startswith("<<") || Expr
.startswith(">>"))
126 Token
= Expr
.substr(0, TokLen
);
131 EvalResult
unexpectedToken(StringRef TokenStart
, StringRef SubExpr
,
132 StringRef ErrText
) const {
133 std::string
ErrorMsg("Encountered unexpected token '");
134 ErrorMsg
+= getTokenForError(TokenStart
);
136 ErrorMsg
+= "' while parsing subexpression '";
144 return EvalResult(std::move(ErrorMsg
));
147 bool handleError(StringRef Expr
, const EvalResult
&R
) const {
148 assert(R
.hasError() && "Not an error result.");
149 Checker
.ErrStream
<< "Error evaluating expression '" << Expr
150 << "': " << R
.getErrorMsg() << "\n";
154 std::pair
<BinOpToken
, StringRef
> parseBinOpToken(StringRef Expr
) const {
156 return std::make_pair(BinOpToken::Invalid
, "");
158 // Handle the two 2-character tokens.
159 if (Expr
.startswith("<<"))
160 return std::make_pair(BinOpToken::ShiftLeft
, Expr
.substr(2).ltrim());
161 if (Expr
.startswith(">>"))
162 return std::make_pair(BinOpToken::ShiftRight
, Expr
.substr(2).ltrim());
164 // Handle one-character tokens.
168 return std::make_pair(BinOpToken::Invalid
, Expr
);
170 Op
= BinOpToken::Add
;
173 Op
= BinOpToken::Sub
;
176 Op
= BinOpToken::BitwiseAnd
;
179 Op
= BinOpToken::BitwiseOr
;
183 return std::make_pair(Op
, Expr
.substr(1).ltrim());
186 EvalResult
computeBinOpResult(BinOpToken Op
, const EvalResult
&LHSResult
,
187 const EvalResult
&RHSResult
) const {
190 llvm_unreachable("Tried to evaluate unrecognized operation.");
191 case BinOpToken::Add
:
192 return EvalResult(LHSResult
.getValue() + RHSResult
.getValue());
193 case BinOpToken::Sub
:
194 return EvalResult(LHSResult
.getValue() - RHSResult
.getValue());
195 case BinOpToken::BitwiseAnd
:
196 return EvalResult(LHSResult
.getValue() & RHSResult
.getValue());
197 case BinOpToken::BitwiseOr
:
198 return EvalResult(LHSResult
.getValue() | RHSResult
.getValue());
199 case BinOpToken::ShiftLeft
:
200 return EvalResult(LHSResult
.getValue() << RHSResult
.getValue());
201 case BinOpToken::ShiftRight
:
202 return EvalResult(LHSResult
.getValue() >> RHSResult
.getValue());
206 // Parse a symbol and return a (string, string) pair representing the symbol
207 // name and expression remaining to be parsed.
208 std::pair
<StringRef
, StringRef
> parseSymbol(StringRef Expr
) const {
209 size_t FirstNonSymbol
= Expr
.find_first_not_of("0123456789"
210 "abcdefghijklmnopqrstuvwxyz"
211 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
213 return std::make_pair(Expr
.substr(0, FirstNonSymbol
),
214 Expr
.substr(FirstNonSymbol
).ltrim());
217 // Evaluate a call to decode_operand. Decode the instruction operand at the
218 // given symbol and get the value of the requested operand.
219 // Returns an error if the instruction cannot be decoded, or the requested
220 // operand is not an immediate.
221 // On success, returns a pair containing the value of the operand, plus
222 // the expression remaining to be evaluated.
223 std::pair
<EvalResult
, StringRef
> evalDecodeOperand(StringRef Expr
) const {
224 if (!Expr
.startswith("("))
225 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
226 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
228 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
230 if (!Checker
.isSymbolValid(Symbol
))
231 return std::make_pair(
232 EvalResult(("Cannot decode unknown symbol '" + Symbol
+ "'").str()),
235 // if there is an offset number expr
238 std::tie(BinOp
, RemainingExpr
) = parseBinOpToken(RemainingExpr
);
240 case BinOpToken::Add
: {
242 std::tie(Number
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
243 Offset
= Number
.getValue();
246 case BinOpToken::Invalid
:
249 return std::make_pair(
250 unexpectedToken(RemainingExpr
, RemainingExpr
,
251 "expected '+' for offset or ',' if no offset"),
255 if (!RemainingExpr
.startswith(","))
256 return std::make_pair(
257 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ','"), "");
258 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
260 EvalResult OpIdxExpr
;
261 std::tie(OpIdxExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
262 if (OpIdxExpr
.hasError())
263 return std::make_pair(OpIdxExpr
, "");
265 if (!RemainingExpr
.startswith(")"))
266 return std::make_pair(
267 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ')'"), "");
268 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
272 if (!decodeInst(Symbol
, Inst
, Size
, Offset
))
273 return std::make_pair(
274 EvalResult(("Couldn't decode instruction at '" + Symbol
+ "'").str()),
277 unsigned OpIdx
= OpIdxExpr
.getValue();
278 if (OpIdx
>= Inst
.getNumOperands()) {
280 raw_string_ostream
ErrMsgStream(ErrMsg
);
281 ErrMsgStream
<< "Invalid operand index '" << format("%i", OpIdx
)
282 << "' for instruction '" << Symbol
283 << "'. Instruction has only "
284 << format("%i", Inst
.getNumOperands())
285 << " operands.\nInstruction is:\n ";
286 Inst
.dump_pretty(ErrMsgStream
, Checker
.InstPrinter
);
287 return std::make_pair(EvalResult(ErrMsgStream
.str()), "");
290 const MCOperand
&Op
= Inst
.getOperand(OpIdx
);
293 raw_string_ostream
ErrMsgStream(ErrMsg
);
294 ErrMsgStream
<< "Operand '" << format("%i", OpIdx
) << "' of instruction '"
295 << Symbol
<< "' is not an immediate.\nInstruction is:\n ";
296 Inst
.dump_pretty(ErrMsgStream
, Checker
.InstPrinter
);
298 return std::make_pair(EvalResult(ErrMsgStream
.str()), "");
301 return std::make_pair(EvalResult(Op
.getImm()), RemainingExpr
);
304 // Evaluate a call to next_pc.
305 // Decode the instruction at the given symbol and return the following program
307 // Returns an error if the instruction cannot be decoded.
308 // On success, returns a pair containing the next PC, plus of the
309 // expression remaining to be evaluated.
310 std::pair
<EvalResult
, StringRef
> evalNextPC(StringRef Expr
,
311 ParseContext PCtx
) const {
312 if (!Expr
.startswith("("))
313 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
314 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
316 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
318 if (!Checker
.isSymbolValid(Symbol
))
319 return std::make_pair(
320 EvalResult(("Cannot decode unknown symbol '" + Symbol
+ "'").str()),
323 if (!RemainingExpr
.startswith(")"))
324 return std::make_pair(
325 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ')'"), "");
326 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
330 if (!decodeInst(Symbol
, Inst
, InstSize
, 0))
331 return std::make_pair(
332 EvalResult(("Couldn't decode instruction at '" + Symbol
+ "'").str()),
335 uint64_t SymbolAddr
= PCtx
.IsInsideLoad
336 ? Checker
.getSymbolLocalAddr(Symbol
)
337 : Checker
.getSymbolRemoteAddr(Symbol
);
338 uint64_t NextPC
= SymbolAddr
+ InstSize
;
340 return std::make_pair(EvalResult(NextPC
), RemainingExpr
);
343 // Evaluate a call to stub_addr/got_addr.
344 // Look up and return the address of the stub for the given
345 // (<file name>, <section name>, <symbol name>) tuple.
346 // On success, returns a pair containing the stub address, plus the expression
347 // remaining to be evaluated.
348 std::pair
<EvalResult
, StringRef
>
349 evalStubOrGOTAddr(StringRef Expr
, ParseContext PCtx
, bool IsStubAddr
) const {
350 if (!Expr
.startswith("("))
351 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
352 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
354 // Handle file-name specially, as it may contain characters that aren't
355 // legal for symbols.
356 StringRef StubContainerName
;
357 size_t ComaIdx
= RemainingExpr
.find(',');
358 StubContainerName
= RemainingExpr
.substr(0, ComaIdx
).rtrim();
359 RemainingExpr
= RemainingExpr
.substr(ComaIdx
).ltrim();
361 if (!RemainingExpr
.startswith(","))
362 return std::make_pair(
363 unexpectedToken(RemainingExpr
, Expr
, "expected ','"), "");
364 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
367 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
369 if (!RemainingExpr
.startswith(")"))
370 return std::make_pair(
371 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
372 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
375 std::string ErrorMsg
;
376 std::tie(StubAddr
, ErrorMsg
) = Checker
.getStubOrGOTAddrFor(
377 StubContainerName
, Symbol
, PCtx
.IsInsideLoad
, IsStubAddr
);
380 return std::make_pair(EvalResult(ErrorMsg
), "");
382 return std::make_pair(EvalResult(StubAddr
), RemainingExpr
);
385 std::pair
<EvalResult
, StringRef
> evalSectionAddr(StringRef Expr
,
386 ParseContext PCtx
) const {
387 if (!Expr
.startswith("("))
388 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
389 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
391 // Handle file-name specially, as it may contain characters that aren't
392 // legal for symbols.
394 size_t ComaIdx
= RemainingExpr
.find(',');
395 FileName
= RemainingExpr
.substr(0, ComaIdx
).rtrim();
396 RemainingExpr
= RemainingExpr
.substr(ComaIdx
).ltrim();
398 if (!RemainingExpr
.startswith(","))
399 return std::make_pair(
400 unexpectedToken(RemainingExpr
, Expr
, "expected ','"), "");
401 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
403 StringRef SectionName
;
404 size_t CloseParensIdx
= RemainingExpr
.find(')');
405 SectionName
= RemainingExpr
.substr(0, CloseParensIdx
).rtrim();
406 RemainingExpr
= RemainingExpr
.substr(CloseParensIdx
).ltrim();
408 if (!RemainingExpr
.startswith(")"))
409 return std::make_pair(
410 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
411 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
414 std::string ErrorMsg
;
415 std::tie(StubAddr
, ErrorMsg
) = Checker
.getSectionAddr(
416 FileName
, SectionName
, PCtx
.IsInsideLoad
);
419 return std::make_pair(EvalResult(ErrorMsg
), "");
421 return std::make_pair(EvalResult(StubAddr
), RemainingExpr
);
424 // Evaluate an identiefer expr, which may be a symbol, or a call to
425 // one of the builtin functions: get_insn_opcode or get_insn_length.
426 // Return the result, plus the expression remaining to be parsed.
427 std::pair
<EvalResult
, StringRef
> evalIdentifierExpr(StringRef Expr
,
428 ParseContext PCtx
) const {
430 StringRef RemainingExpr
;
431 std::tie(Symbol
, RemainingExpr
) = parseSymbol(Expr
);
433 // Check for builtin function calls.
434 if (Symbol
== "decode_operand")
435 return evalDecodeOperand(RemainingExpr
);
436 else if (Symbol
== "next_pc")
437 return evalNextPC(RemainingExpr
, PCtx
);
438 else if (Symbol
== "stub_addr")
439 return evalStubOrGOTAddr(RemainingExpr
, PCtx
, true);
440 else if (Symbol
== "got_addr")
441 return evalStubOrGOTAddr(RemainingExpr
, PCtx
, false);
442 else if (Symbol
== "section_addr")
443 return evalSectionAddr(RemainingExpr
, PCtx
);
445 if (!Checker
.isSymbolValid(Symbol
)) {
446 std::string
ErrMsg("No known address for symbol '");
449 if (Symbol
.startswith("L"))
450 ErrMsg
+= " (this appears to be an assembler local label - "
451 " perhaps drop the 'L'?)";
453 return std::make_pair(EvalResult(ErrMsg
), "");
456 // The value for the symbol depends on the context we're evaluating in:
457 // Inside a load this is the address in the linker's memory, outside a
458 // load it's the address in the target processes memory.
459 uint64_t Value
= PCtx
.IsInsideLoad
? Checker
.getSymbolLocalAddr(Symbol
)
460 : Checker
.getSymbolRemoteAddr(Symbol
);
462 // Looks like a plain symbol reference.
463 return std::make_pair(EvalResult(Value
), RemainingExpr
);
466 // Parse a number (hexadecimal or decimal) and return a (string, string)
467 // pair representing the number and the expression remaining to be parsed.
468 std::pair
<StringRef
, StringRef
> parseNumberString(StringRef Expr
) const {
469 size_t FirstNonDigit
= StringRef::npos
;
470 if (Expr
.startswith("0x")) {
471 FirstNonDigit
= Expr
.find_first_not_of("0123456789abcdefABCDEF", 2);
472 if (FirstNonDigit
== StringRef::npos
)
473 FirstNonDigit
= Expr
.size();
475 FirstNonDigit
= Expr
.find_first_not_of("0123456789");
476 if (FirstNonDigit
== StringRef::npos
)
477 FirstNonDigit
= Expr
.size();
479 return std::make_pair(Expr
.substr(0, FirstNonDigit
),
480 Expr
.substr(FirstNonDigit
));
483 // Evaluate a constant numeric expression (hexadecimal or decimal) and
484 // return a pair containing the result, and the expression remaining to be
486 std::pair
<EvalResult
, StringRef
> evalNumberExpr(StringRef Expr
) const {
488 StringRef RemainingExpr
;
489 std::tie(ValueStr
, RemainingExpr
) = parseNumberString(Expr
);
491 if (ValueStr
.empty() || !isdigit(ValueStr
[0]))
492 return std::make_pair(
493 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected number"), "");
495 ValueStr
.getAsInteger(0, Value
);
496 return std::make_pair(EvalResult(Value
), RemainingExpr
);
499 // Evaluate an expression of the form "(<expr>)" and return a pair
500 // containing the result of evaluating <expr>, plus the expression
501 // remaining to be parsed.
502 std::pair
<EvalResult
, StringRef
> evalParensExpr(StringRef Expr
,
503 ParseContext PCtx
) const {
504 assert(Expr
.startswith("(") && "Not a parenthesized expression");
505 EvalResult SubExprResult
;
506 StringRef RemainingExpr
;
507 std::tie(SubExprResult
, RemainingExpr
) =
508 evalComplexExpr(evalSimpleExpr(Expr
.substr(1).ltrim(), PCtx
), PCtx
);
509 if (SubExprResult
.hasError())
510 return std::make_pair(SubExprResult
, "");
511 if (!RemainingExpr
.startswith(")"))
512 return std::make_pair(
513 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
514 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
515 return std::make_pair(SubExprResult
, RemainingExpr
);
518 // Evaluate an expression in one of the following forms:
520 // Return a pair containing the result, plus the expression remaining to be
522 std::pair
<EvalResult
, StringRef
> evalLoadExpr(StringRef Expr
) const {
523 assert(Expr
.startswith("*") && "Not a load expression");
524 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
527 if (!RemainingExpr
.startswith("{"))
528 return std::make_pair(EvalResult("Expected '{' following '*'."), "");
529 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
530 EvalResult ReadSizeExpr
;
531 std::tie(ReadSizeExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
532 if (ReadSizeExpr
.hasError())
533 return std::make_pair(ReadSizeExpr
, RemainingExpr
);
534 uint64_t ReadSize
= ReadSizeExpr
.getValue();
535 if (ReadSize
< 1 || ReadSize
> 8)
536 return std::make_pair(EvalResult("Invalid size for dereference."), "");
537 if (!RemainingExpr
.startswith("}"))
538 return std::make_pair(EvalResult("Missing '}' for dereference."), "");
539 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
541 // Evaluate the expression representing the load address.
542 ParseContext
LoadCtx(true);
543 EvalResult LoadAddrExprResult
;
544 std::tie(LoadAddrExprResult
, RemainingExpr
) =
545 evalComplexExpr(evalSimpleExpr(RemainingExpr
, LoadCtx
), LoadCtx
);
547 if (LoadAddrExprResult
.hasError())
548 return std::make_pair(LoadAddrExprResult
, "");
550 uint64_t LoadAddr
= LoadAddrExprResult
.getValue();
552 // If there is no error but the content pointer is null then this is a
553 // zero-fill symbol/section.
555 return std::make_pair(0, RemainingExpr
);
557 return std::make_pair(
558 EvalResult(Checker
.readMemoryAtAddr(LoadAddr
, ReadSize
)),
562 // Evaluate a "simple" expression. This is any expression that _isn't_ an
563 // un-parenthesized binary expression.
565 // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
567 // Returns a pair containing the result of the evaluation, plus the
568 // expression remaining to be parsed.
569 std::pair
<EvalResult
, StringRef
> evalSimpleExpr(StringRef Expr
,
570 ParseContext PCtx
) const {
571 EvalResult SubExprResult
;
572 StringRef RemainingExpr
;
575 return std::make_pair(EvalResult("Unexpected end of expression"), "");
578 std::tie(SubExprResult
, RemainingExpr
) = evalParensExpr(Expr
, PCtx
);
579 else if (Expr
[0] == '*')
580 std::tie(SubExprResult
, RemainingExpr
) = evalLoadExpr(Expr
);
581 else if (isalpha(Expr
[0]) || Expr
[0] == '_')
582 std::tie(SubExprResult
, RemainingExpr
) = evalIdentifierExpr(Expr
, PCtx
);
583 else if (isdigit(Expr
[0]))
584 std::tie(SubExprResult
, RemainingExpr
) = evalNumberExpr(Expr
);
586 return std::make_pair(
587 unexpectedToken(Expr
, Expr
,
588 "expected '(', '*', identifier, or number"), "");
590 if (SubExprResult
.hasError())
591 return std::make_pair(SubExprResult
, RemainingExpr
);
593 // Evaluate bit-slice if present.
594 if (RemainingExpr
.startswith("["))
595 std::tie(SubExprResult
, RemainingExpr
) =
596 evalSliceExpr(std::make_pair(SubExprResult
, RemainingExpr
));
598 return std::make_pair(SubExprResult
, RemainingExpr
);
601 // Evaluate a bit-slice of an expression.
602 // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
603 // slice is the bits between high and low (inclusive) in the original
604 // expression, right shifted so that the "low" bit is in position 0 in the
606 // Returns a pair containing the result of the slice operation, plus the
607 // expression remaining to be parsed.
608 std::pair
<EvalResult
, StringRef
>
609 evalSliceExpr(const std::pair
<EvalResult
, StringRef
> &Ctx
) const {
610 EvalResult SubExprResult
;
611 StringRef RemainingExpr
;
612 std::tie(SubExprResult
, RemainingExpr
) = Ctx
;
614 assert(RemainingExpr
.startswith("[") && "Not a slice expr.");
615 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
617 EvalResult HighBitExpr
;
618 std::tie(HighBitExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
620 if (HighBitExpr
.hasError())
621 return std::make_pair(HighBitExpr
, RemainingExpr
);
623 if (!RemainingExpr
.startswith(":"))
624 return std::make_pair(
625 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ':'"), "");
626 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
628 EvalResult LowBitExpr
;
629 std::tie(LowBitExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
631 if (LowBitExpr
.hasError())
632 return std::make_pair(LowBitExpr
, RemainingExpr
);
634 if (!RemainingExpr
.startswith("]"))
635 return std::make_pair(
636 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ']'"), "");
637 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
639 unsigned HighBit
= HighBitExpr
.getValue();
640 unsigned LowBit
= LowBitExpr
.getValue();
641 uint64_t Mask
= ((uint64_t)1 << (HighBit
- LowBit
+ 1)) - 1;
642 uint64_t SlicedValue
= (SubExprResult
.getValue() >> LowBit
) & Mask
;
643 return std::make_pair(EvalResult(SlicedValue
), RemainingExpr
);
646 // Evaluate a "complex" expression.
647 // Takes an already evaluated subexpression and checks for the presence of a
648 // binary operator, computing the result of the binary operation if one is
649 // found. Used to make arithmetic expressions left-associative.
650 // Returns a pair containing the ultimate result of evaluating the
651 // expression, plus the expression remaining to be evaluated.
652 std::pair
<EvalResult
, StringRef
>
653 evalComplexExpr(const std::pair
<EvalResult
, StringRef
> &LHSAndRemaining
,
654 ParseContext PCtx
) const {
655 EvalResult LHSResult
;
656 StringRef RemainingExpr
;
657 std::tie(LHSResult
, RemainingExpr
) = LHSAndRemaining
;
659 // If there was an error, or there's nothing left to evaluate, return the
661 if (LHSResult
.hasError() || RemainingExpr
== "")
662 return std::make_pair(LHSResult
, RemainingExpr
);
664 // Otherwise check if this is a binary expressioan.
666 std::tie(BinOp
, RemainingExpr
) = parseBinOpToken(RemainingExpr
);
668 // If this isn't a recognized expression just return.
669 if (BinOp
== BinOpToken::Invalid
)
670 return std::make_pair(LHSResult
, RemainingExpr
);
672 // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
673 EvalResult RHSResult
;
674 std::tie(RHSResult
, RemainingExpr
) = evalSimpleExpr(RemainingExpr
, PCtx
);
676 // If there was an error evaluating the RHS, return it.
677 if (RHSResult
.hasError())
678 return std::make_pair(RHSResult
, RemainingExpr
);
680 // This is a binary expression - evaluate and try to continue as a
682 EvalResult
ThisResult(computeBinOpResult(BinOp
, LHSResult
, RHSResult
));
684 return evalComplexExpr(std::make_pair(ThisResult
, RemainingExpr
), PCtx
);
687 bool decodeInst(StringRef Symbol
, MCInst
&Inst
, uint64_t &Size
,
688 int64_t Offset
) const {
689 MCDisassembler
*Dis
= Checker
.Disassembler
;
690 StringRef SymbolMem
= Checker
.getSymbolContent(Symbol
);
691 ArrayRef
<uint8_t> SymbolBytes(SymbolMem
.bytes_begin() + Offset
,
692 SymbolMem
.size() - Offset
);
694 MCDisassembler::DecodeStatus S
=
695 Dis
->getInstruction(Inst
, Size
, SymbolBytes
, 0, nulls());
697 return (S
== MCDisassembler::Success
);
702 RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(
703 IsSymbolValidFunction IsSymbolValid
, GetSymbolInfoFunction GetSymbolInfo
,
704 GetSectionInfoFunction GetSectionInfo
, GetStubInfoFunction GetStubInfo
,
705 GetGOTInfoFunction GetGOTInfo
, support::endianness Endianness
,
706 MCDisassembler
*Disassembler
, MCInstPrinter
*InstPrinter
,
707 raw_ostream
&ErrStream
)
708 : IsSymbolValid(std::move(IsSymbolValid
)),
709 GetSymbolInfo(std::move(GetSymbolInfo
)),
710 GetSectionInfo(std::move(GetSectionInfo
)),
711 GetStubInfo(std::move(GetStubInfo
)), GetGOTInfo(std::move(GetGOTInfo
)),
712 Endianness(Endianness
), Disassembler(Disassembler
),
713 InstPrinter(InstPrinter
), ErrStream(ErrStream
) {}
715 bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr
) const {
716 CheckExpr
= CheckExpr
.trim();
717 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
719 RuntimeDyldCheckerExprEval
P(*this, ErrStream
);
720 bool Result
= P
.evaluate(CheckExpr
);
722 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr
<< "' "
723 << (Result
? "passed" : "FAILED") << ".\n");
727 bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix
,
728 MemoryBuffer
*MemBuf
) const {
729 bool DidAllTestsPass
= true;
730 unsigned NumRules
= 0;
732 std::string CheckExpr
;
733 const char *LineStart
= MemBuf
->getBufferStart();
736 while (LineStart
!= MemBuf
->getBufferEnd() && isSpace(*LineStart
))
739 while (LineStart
!= MemBuf
->getBufferEnd() && *LineStart
!= '\0') {
740 const char *LineEnd
= LineStart
;
741 while (LineEnd
!= MemBuf
->getBufferEnd() && *LineEnd
!= '\r' &&
745 StringRef
Line(LineStart
, LineEnd
- LineStart
);
746 if (Line
.startswith(RulePrefix
))
747 CheckExpr
+= Line
.substr(RulePrefix
.size()).str();
749 // If there's a check expr string...
750 if (!CheckExpr
.empty()) {
751 // ... and it's complete then run it, otherwise remove the trailer '\'.
752 if (CheckExpr
.back() != '\\') {
753 DidAllTestsPass
&= check(CheckExpr
);
757 CheckExpr
.pop_back();
762 while (LineStart
!= MemBuf
->getBufferEnd() && isSpace(*LineStart
))
765 return DidAllTestsPass
&& (NumRules
!= 0);
768 bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol
) const {
769 return IsSymbolValid(Symbol
);
772 uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol
) const {
773 auto SymInfo
= GetSymbolInfo(Symbol
);
775 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
779 if (SymInfo
->isZeroFill())
782 return static_cast<uint64_t>(
783 reinterpret_cast<uintptr_t>(SymInfo
->getContent().data()));
786 uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol
) const {
787 auto SymInfo
= GetSymbolInfo(Symbol
);
789 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
793 return SymInfo
->getTargetAddress();
796 uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr
,
797 unsigned Size
) const {
798 uintptr_t PtrSizedAddr
= static_cast<uintptr_t>(SrcAddr
);
799 assert(PtrSizedAddr
== SrcAddr
&& "Linker memory pointer out-of-range.");
800 void *Ptr
= reinterpret_cast<void*>(PtrSizedAddr
);
804 return support::endian::read
<uint8_t>(Ptr
, Endianness
);
806 return support::endian::read
<uint16_t>(Ptr
, Endianness
);
808 return support::endian::read
<uint32_t>(Ptr
, Endianness
);
810 return support::endian::read
<uint64_t>(Ptr
, Endianness
);
812 llvm_unreachable("Unsupported read size");
815 StringRef
RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol
) const {
816 auto SymInfo
= GetSymbolInfo(Symbol
);
818 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
821 return {SymInfo
->getContent().data(), SymInfo
->getContent().size()};
824 std::pair
<uint64_t, std::string
> RuntimeDyldCheckerImpl::getSectionAddr(
825 StringRef FileName
, StringRef SectionName
, bool IsInsideLoad
) const {
827 auto SecInfo
= GetSectionInfo(FileName
, SectionName
);
831 raw_string_ostream
ErrMsgStream(ErrMsg
);
832 logAllUnhandledErrors(SecInfo
.takeError(), ErrMsgStream
,
835 return std::make_pair(0, std::move(ErrMsg
));
838 // If this address is being looked up in "load" mode, return the content
839 // pointer, otherwise return the target address.
844 if (SecInfo
->isZeroFill())
847 Addr
= pointerToJITTargetAddress(SecInfo
->getContent().data());
849 Addr
= SecInfo
->getTargetAddress();
851 return std::make_pair(Addr
, "");
854 std::pair
<uint64_t, std::string
> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
855 StringRef StubContainerName
, StringRef SymbolName
, bool IsInsideLoad
,
856 bool IsStubAddr
) const {
858 auto StubInfo
= IsStubAddr
? GetStubInfo(StubContainerName
, SymbolName
)
859 : GetGOTInfo(StubContainerName
, SymbolName
);
864 raw_string_ostream
ErrMsgStream(ErrMsg
);
865 logAllUnhandledErrors(StubInfo
.takeError(), ErrMsgStream
,
868 return std::make_pair((uint64_t)0, std::move(ErrMsg
));
874 if (StubInfo
->isZeroFill())
875 return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");
876 Addr
= pointerToJITTargetAddress(StubInfo
->getContent().data());
878 Addr
= StubInfo
->getTargetAddress();
880 return std::make_pair(Addr
, "");
883 RuntimeDyldChecker::RuntimeDyldChecker(
884 IsSymbolValidFunction IsSymbolValid
, GetSymbolInfoFunction GetSymbolInfo
,
885 GetSectionInfoFunction GetSectionInfo
, GetStubInfoFunction GetStubInfo
,
886 GetGOTInfoFunction GetGOTInfo
, support::endianness Endianness
,
887 MCDisassembler
*Disassembler
, MCInstPrinter
*InstPrinter
,
888 raw_ostream
&ErrStream
)
889 : Impl(::std::make_unique
<RuntimeDyldCheckerImpl
>(
890 std::move(IsSymbolValid
), std::move(GetSymbolInfo
),
891 std::move(GetSectionInfo
), std::move(GetStubInfo
),
892 std::move(GetGOTInfo
), Endianness
, Disassembler
, InstPrinter
,
895 RuntimeDyldChecker::~RuntimeDyldChecker() {}
897 bool RuntimeDyldChecker::check(StringRef CheckExpr
) const {
898 return Impl
->check(CheckExpr
);
901 bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix
,
902 MemoryBuffer
*MemBuf
) const {
903 return Impl
->checkAllRulesInBuffer(RulePrefix
, MemBuf
);
906 std::pair
<uint64_t, std::string
>
907 RuntimeDyldChecker::getSectionAddr(StringRef FileName
, StringRef SectionName
,
909 return Impl
->getSectionAddr(FileName
, SectionName
, LocalAddress
);