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/MC/MCContext.h"
13 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
14 #include "llvm/MC/MCInst.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/MSVCErrorWorkarounds.h"
17 #include "llvm/Support/Path.h"
22 #define DEBUG_TYPE "rtdyld"
28 // Helper class that implements the language evaluated by RuntimeDyldChecker.
29 class RuntimeDyldCheckerExprEval
{
31 RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl
&Checker
,
32 raw_ostream
&ErrStream
)
35 bool evaluate(StringRef Expr
) const {
36 // Expect equality expression of the form 'LHS = RHS'.
38 size_t EQIdx
= Expr
.find('=');
40 ParseContext
OutsideLoad(false);
43 StringRef LHSExpr
= Expr
.substr(0, EQIdx
).rtrim();
44 StringRef RemainingExpr
;
46 std::tie(LHSResult
, RemainingExpr
) =
47 evalComplexExpr(evalSimpleExpr(LHSExpr
, OutsideLoad
), OutsideLoad
);
48 if (LHSResult
.hasError())
49 return handleError(Expr
, LHSResult
);
50 if (RemainingExpr
!= "")
51 return handleError(Expr
, unexpectedToken(RemainingExpr
, LHSExpr
, ""));
54 StringRef RHSExpr
= Expr
.substr(EQIdx
+ 1).ltrim();
56 std::tie(RHSResult
, RemainingExpr
) =
57 evalComplexExpr(evalSimpleExpr(RHSExpr
, OutsideLoad
), OutsideLoad
);
58 if (RHSResult
.hasError())
59 return handleError(Expr
, RHSResult
);
60 if (RemainingExpr
!= "")
61 return handleError(Expr
, unexpectedToken(RemainingExpr
, RHSExpr
, ""));
63 if (LHSResult
.getValue() != RHSResult
.getValue()) {
64 Checker
.ErrStream
<< "Expression '" << Expr
<< "' is false: "
65 << format("0x%" PRIx64
, LHSResult
.getValue())
66 << " != " << format("0x%" PRIx64
, RHSResult
.getValue())
74 // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In
75 // particular, it needs to know whether a symbol is being evaluated in the
76 // context of a load, in which case we want the linker's local address for
77 // the symbol, or outside of a load, in which case we want the symbol's
78 // address in the remote target.
82 ParseContext(bool IsInsideLoad
) : IsInsideLoad(IsInsideLoad
) {}
85 const RuntimeDyldCheckerImpl
&Checker
;
87 enum class BinOpToken
: unsigned {
99 EvalResult() : Value(0), ErrorMsg("") {}
100 EvalResult(uint64_t Value
) : Value(Value
), ErrorMsg("") {}
101 EvalResult(std::string ErrorMsg
)
102 : Value(0), ErrorMsg(std::move(ErrorMsg
)) {}
103 uint64_t getValue() const { return Value
; }
104 bool hasError() const { return ErrorMsg
!= ""; }
105 const std::string
&getErrorMsg() const { return ErrorMsg
; }
109 std::string ErrorMsg
;
112 StringRef
getTokenForError(StringRef Expr
) const {
116 StringRef Token
, Remaining
;
117 if (isalpha(Expr
[0]))
118 std::tie(Token
, Remaining
) = parseSymbol(Expr
);
119 else if (isdigit(Expr
[0]))
120 std::tie(Token
, Remaining
) = parseNumberString(Expr
);
123 if (Expr
.startswith("<<") || Expr
.startswith(">>"))
125 Token
= Expr
.substr(0, TokLen
);
130 EvalResult
unexpectedToken(StringRef TokenStart
, StringRef SubExpr
,
131 StringRef ErrText
) const {
132 std::string
ErrorMsg("Encountered unexpected token '");
133 ErrorMsg
+= getTokenForError(TokenStart
);
135 ErrorMsg
+= "' while parsing subexpression '";
143 return EvalResult(std::move(ErrorMsg
));
146 bool handleError(StringRef Expr
, const EvalResult
&R
) const {
147 assert(R
.hasError() && "Not an error result.");
148 Checker
.ErrStream
<< "Error evaluating expression '" << Expr
149 << "': " << R
.getErrorMsg() << "\n";
153 std::pair
<BinOpToken
, StringRef
> parseBinOpToken(StringRef Expr
) const {
155 return std::make_pair(BinOpToken::Invalid
, "");
157 // Handle the two 2-character tokens.
158 if (Expr
.startswith("<<"))
159 return std::make_pair(BinOpToken::ShiftLeft
, Expr
.substr(2).ltrim());
160 if (Expr
.startswith(">>"))
161 return std::make_pair(BinOpToken::ShiftRight
, Expr
.substr(2).ltrim());
163 // Handle one-character tokens.
167 return std::make_pair(BinOpToken::Invalid
, Expr
);
169 Op
= BinOpToken::Add
;
172 Op
= BinOpToken::Sub
;
175 Op
= BinOpToken::BitwiseAnd
;
178 Op
= BinOpToken::BitwiseOr
;
182 return std::make_pair(Op
, Expr
.substr(1).ltrim());
185 EvalResult
computeBinOpResult(BinOpToken Op
, const EvalResult
&LHSResult
,
186 const EvalResult
&RHSResult
) const {
189 llvm_unreachable("Tried to evaluate unrecognized operation.");
190 case BinOpToken::Add
:
191 return EvalResult(LHSResult
.getValue() + RHSResult
.getValue());
192 case BinOpToken::Sub
:
193 return EvalResult(LHSResult
.getValue() - RHSResult
.getValue());
194 case BinOpToken::BitwiseAnd
:
195 return EvalResult(LHSResult
.getValue() & RHSResult
.getValue());
196 case BinOpToken::BitwiseOr
:
197 return EvalResult(LHSResult
.getValue() | RHSResult
.getValue());
198 case BinOpToken::ShiftLeft
:
199 return EvalResult(LHSResult
.getValue() << RHSResult
.getValue());
200 case BinOpToken::ShiftRight
:
201 return EvalResult(LHSResult
.getValue() >> RHSResult
.getValue());
205 // Parse a symbol and return a (string, string) pair representing the symbol
206 // name and expression remaining to be parsed.
207 std::pair
<StringRef
, StringRef
> parseSymbol(StringRef Expr
) const {
208 size_t FirstNonSymbol
= Expr
.find_first_not_of("0123456789"
209 "abcdefghijklmnopqrstuvwxyz"
210 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
212 return std::make_pair(Expr
.substr(0, FirstNonSymbol
),
213 Expr
.substr(FirstNonSymbol
).ltrim());
216 // Evaluate a call to decode_operand. Decode the instruction operand at the
217 // given symbol and get the value of the requested operand.
218 // Returns an error if the instruction cannot be decoded, or the requested
219 // operand is not an immediate.
220 // On success, returns a pair containing the value of the operand, plus
221 // the expression remaining to be evaluated.
222 std::pair
<EvalResult
, StringRef
> evalDecodeOperand(StringRef Expr
) const {
223 if (!Expr
.startswith("("))
224 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
225 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
227 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
229 if (!Checker
.isSymbolValid(Symbol
))
230 return std::make_pair(
231 EvalResult(("Cannot decode unknown symbol '" + Symbol
+ "'").str()),
234 if (!RemainingExpr
.startswith(","))
235 return std::make_pair(
236 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ','"), "");
237 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
239 EvalResult OpIdxExpr
;
240 std::tie(OpIdxExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
241 if (OpIdxExpr
.hasError())
242 return std::make_pair(OpIdxExpr
, "");
244 if (!RemainingExpr
.startswith(")"))
245 return std::make_pair(
246 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ')'"), "");
247 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
251 if (!decodeInst(Symbol
, Inst
, Size
))
252 return std::make_pair(
253 EvalResult(("Couldn't decode instruction at '" + Symbol
+ "'").str()),
256 unsigned OpIdx
= OpIdxExpr
.getValue();
257 if (OpIdx
>= Inst
.getNumOperands()) {
259 raw_string_ostream
ErrMsgStream(ErrMsg
);
260 ErrMsgStream
<< "Invalid operand index '" << format("%i", OpIdx
)
261 << "' for instruction '" << Symbol
262 << "'. Instruction has only "
263 << format("%i", Inst
.getNumOperands())
264 << " operands.\nInstruction is:\n ";
265 Inst
.dump_pretty(ErrMsgStream
, Checker
.InstPrinter
);
266 return std::make_pair(EvalResult(ErrMsgStream
.str()), "");
269 const MCOperand
&Op
= Inst
.getOperand(OpIdx
);
272 raw_string_ostream
ErrMsgStream(ErrMsg
);
273 ErrMsgStream
<< "Operand '" << format("%i", OpIdx
) << "' of instruction '"
274 << Symbol
<< "' is not an immediate.\nInstruction is:\n ";
275 Inst
.dump_pretty(ErrMsgStream
, Checker
.InstPrinter
);
277 return std::make_pair(EvalResult(ErrMsgStream
.str()), "");
280 return std::make_pair(EvalResult(Op
.getImm()), RemainingExpr
);
283 // Evaluate a call to next_pc.
284 // Decode the instruction at the given symbol and return the following program
286 // Returns an error if the instruction cannot be decoded.
287 // On success, returns a pair containing the next PC, plus of the
288 // expression remaining to be evaluated.
289 std::pair
<EvalResult
, StringRef
> evalNextPC(StringRef Expr
,
290 ParseContext PCtx
) const {
291 if (!Expr
.startswith("("))
292 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
293 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
295 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
297 if (!Checker
.isSymbolValid(Symbol
))
298 return std::make_pair(
299 EvalResult(("Cannot decode unknown symbol '" + Symbol
+ "'").str()),
302 if (!RemainingExpr
.startswith(")"))
303 return std::make_pair(
304 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ')'"), "");
305 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
309 if (!decodeInst(Symbol
, Inst
, InstSize
))
310 return std::make_pair(
311 EvalResult(("Couldn't decode instruction at '" + Symbol
+ "'").str()),
314 uint64_t SymbolAddr
= PCtx
.IsInsideLoad
315 ? Checker
.getSymbolLocalAddr(Symbol
)
316 : Checker
.getSymbolRemoteAddr(Symbol
);
317 uint64_t NextPC
= SymbolAddr
+ InstSize
;
319 return std::make_pair(EvalResult(NextPC
), RemainingExpr
);
322 // Evaluate a call to stub_addr/got_addr.
323 // Look up and return the address of the stub for the given
324 // (<file name>, <section name>, <symbol name>) tuple.
325 // On success, returns a pair containing the stub address, plus the expression
326 // remaining to be evaluated.
327 std::pair
<EvalResult
, StringRef
>
328 evalStubOrGOTAddr(StringRef Expr
, ParseContext PCtx
, bool IsStubAddr
) const {
329 if (!Expr
.startswith("("))
330 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
331 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
333 // Handle file-name specially, as it may contain characters that aren't
334 // legal for symbols.
335 StringRef StubContainerName
;
336 size_t ComaIdx
= RemainingExpr
.find(',');
337 StubContainerName
= RemainingExpr
.substr(0, ComaIdx
).rtrim();
338 RemainingExpr
= RemainingExpr
.substr(ComaIdx
).ltrim();
340 if (!RemainingExpr
.startswith(","))
341 return std::make_pair(
342 unexpectedToken(RemainingExpr
, Expr
, "expected ','"), "");
343 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
346 std::tie(Symbol
, RemainingExpr
) = parseSymbol(RemainingExpr
);
348 if (!RemainingExpr
.startswith(")"))
349 return std::make_pair(
350 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
351 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
354 std::string ErrorMsg
= "";
355 std::tie(StubAddr
, ErrorMsg
) = Checker
.getStubOrGOTAddrFor(
356 StubContainerName
, Symbol
, PCtx
.IsInsideLoad
, IsStubAddr
);
359 return std::make_pair(EvalResult(ErrorMsg
), "");
361 return std::make_pair(EvalResult(StubAddr
), RemainingExpr
);
364 std::pair
<EvalResult
, StringRef
> evalSectionAddr(StringRef Expr
,
365 ParseContext PCtx
) const {
366 if (!Expr
.startswith("("))
367 return std::make_pair(unexpectedToken(Expr
, Expr
, "expected '('"), "");
368 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
370 // Handle file-name specially, as it may contain characters that aren't
371 // legal for symbols.
373 size_t ComaIdx
= RemainingExpr
.find(',');
374 FileName
= RemainingExpr
.substr(0, ComaIdx
).rtrim();
375 RemainingExpr
= RemainingExpr
.substr(ComaIdx
).ltrim();
377 if (!RemainingExpr
.startswith(","))
378 return std::make_pair(
379 unexpectedToken(RemainingExpr
, Expr
, "expected ','"), "");
380 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
382 StringRef SectionName
;
383 std::tie(SectionName
, RemainingExpr
) = parseSymbol(RemainingExpr
);
385 if (!RemainingExpr
.startswith(")"))
386 return std::make_pair(
387 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
388 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
391 std::string ErrorMsg
= "";
392 std::tie(StubAddr
, ErrorMsg
) = Checker
.getSectionAddr(
393 FileName
, SectionName
, PCtx
.IsInsideLoad
);
396 return std::make_pair(EvalResult(ErrorMsg
), "");
398 return std::make_pair(EvalResult(StubAddr
), RemainingExpr
);
401 // Evaluate an identiefer expr, which may be a symbol, or a call to
402 // one of the builtin functions: get_insn_opcode or get_insn_length.
403 // Return the result, plus the expression remaining to be parsed.
404 std::pair
<EvalResult
, StringRef
> evalIdentifierExpr(StringRef Expr
,
405 ParseContext PCtx
) const {
407 StringRef RemainingExpr
;
408 std::tie(Symbol
, RemainingExpr
) = parseSymbol(Expr
);
410 // Check for builtin function calls.
411 if (Symbol
== "decode_operand")
412 return evalDecodeOperand(RemainingExpr
);
413 else if (Symbol
== "next_pc")
414 return evalNextPC(RemainingExpr
, PCtx
);
415 else if (Symbol
== "stub_addr")
416 return evalStubOrGOTAddr(RemainingExpr
, PCtx
, true);
417 else if (Symbol
== "got_addr")
418 return evalStubOrGOTAddr(RemainingExpr
, PCtx
, false);
419 else if (Symbol
== "section_addr")
420 return evalSectionAddr(RemainingExpr
, PCtx
);
422 if (!Checker
.isSymbolValid(Symbol
)) {
423 std::string
ErrMsg("No known address for symbol '");
426 if (Symbol
.startswith("L"))
427 ErrMsg
+= " (this appears to be an assembler local label - "
428 " perhaps drop the 'L'?)";
430 return std::make_pair(EvalResult(ErrMsg
), "");
433 // The value for the symbol depends on the context we're evaluating in:
434 // Inside a load this is the address in the linker's memory, outside a
435 // load it's the address in the target processes memory.
436 uint64_t Value
= PCtx
.IsInsideLoad
? Checker
.getSymbolLocalAddr(Symbol
)
437 : Checker
.getSymbolRemoteAddr(Symbol
);
439 // Looks like a plain symbol reference.
440 return std::make_pair(EvalResult(Value
), RemainingExpr
);
443 // Parse a number (hexadecimal or decimal) and return a (string, string)
444 // pair representing the number and the expression remaining to be parsed.
445 std::pair
<StringRef
, StringRef
> parseNumberString(StringRef Expr
) const {
446 size_t FirstNonDigit
= StringRef::npos
;
447 if (Expr
.startswith("0x")) {
448 FirstNonDigit
= Expr
.find_first_not_of("0123456789abcdefABCDEF", 2);
449 if (FirstNonDigit
== StringRef::npos
)
450 FirstNonDigit
= Expr
.size();
452 FirstNonDigit
= Expr
.find_first_not_of("0123456789");
453 if (FirstNonDigit
== StringRef::npos
)
454 FirstNonDigit
= Expr
.size();
456 return std::make_pair(Expr
.substr(0, FirstNonDigit
),
457 Expr
.substr(FirstNonDigit
));
460 // Evaluate a constant numeric expression (hexadecimal or decimal) and
461 // return a pair containing the result, and the expression remaining to be
463 std::pair
<EvalResult
, StringRef
> evalNumberExpr(StringRef Expr
) const {
465 StringRef RemainingExpr
;
466 std::tie(ValueStr
, RemainingExpr
) = parseNumberString(Expr
);
468 if (ValueStr
.empty() || !isdigit(ValueStr
[0]))
469 return std::make_pair(
470 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected number"), "");
472 ValueStr
.getAsInteger(0, Value
);
473 return std::make_pair(EvalResult(Value
), RemainingExpr
);
476 // Evaluate an expression of the form "(<expr>)" and return a pair
477 // containing the result of evaluating <expr>, plus the expression
478 // remaining to be parsed.
479 std::pair
<EvalResult
, StringRef
> evalParensExpr(StringRef Expr
,
480 ParseContext PCtx
) const {
481 assert(Expr
.startswith("(") && "Not a parenthesized expression");
482 EvalResult SubExprResult
;
483 StringRef RemainingExpr
;
484 std::tie(SubExprResult
, RemainingExpr
) =
485 evalComplexExpr(evalSimpleExpr(Expr
.substr(1).ltrim(), PCtx
), PCtx
);
486 if (SubExprResult
.hasError())
487 return std::make_pair(SubExprResult
, "");
488 if (!RemainingExpr
.startswith(")"))
489 return std::make_pair(
490 unexpectedToken(RemainingExpr
, Expr
, "expected ')'"), "");
491 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
492 return std::make_pair(SubExprResult
, RemainingExpr
);
495 // Evaluate an expression in one of the following forms:
497 // Return a pair containing the result, plus the expression remaining to be
499 std::pair
<EvalResult
, StringRef
> evalLoadExpr(StringRef Expr
) const {
500 assert(Expr
.startswith("*") && "Not a load expression");
501 StringRef RemainingExpr
= Expr
.substr(1).ltrim();
504 if (!RemainingExpr
.startswith("{"))
505 return std::make_pair(EvalResult("Expected '{' following '*'."), "");
506 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
507 EvalResult ReadSizeExpr
;
508 std::tie(ReadSizeExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
509 if (ReadSizeExpr
.hasError())
510 return std::make_pair(ReadSizeExpr
, RemainingExpr
);
511 uint64_t ReadSize
= ReadSizeExpr
.getValue();
512 if (ReadSize
< 1 || ReadSize
> 8)
513 return std::make_pair(EvalResult("Invalid size for dereference."), "");
514 if (!RemainingExpr
.startswith("}"))
515 return std::make_pair(EvalResult("Missing '}' for dereference."), "");
516 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
518 // Evaluate the expression representing the load address.
519 ParseContext
LoadCtx(true);
520 EvalResult LoadAddrExprResult
;
521 std::tie(LoadAddrExprResult
, RemainingExpr
) =
522 evalComplexExpr(evalSimpleExpr(RemainingExpr
, LoadCtx
), LoadCtx
);
524 if (LoadAddrExprResult
.hasError())
525 return std::make_pair(LoadAddrExprResult
, "");
527 uint64_t LoadAddr
= LoadAddrExprResult
.getValue();
529 // If there is no error but the content pointer is null then this is a
530 // zero-fill symbol/section.
532 return std::make_pair(0, RemainingExpr
);
534 return std::make_pair(
535 EvalResult(Checker
.readMemoryAtAddr(LoadAddr
, ReadSize
)),
539 // Evaluate a "simple" expression. This is any expression that _isn't_ an
540 // un-parenthesized binary expression.
542 // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
544 // Returns a pair containing the result of the evaluation, plus the
545 // expression remaining to be parsed.
546 std::pair
<EvalResult
, StringRef
> evalSimpleExpr(StringRef Expr
,
547 ParseContext PCtx
) const {
548 EvalResult SubExprResult
;
549 StringRef RemainingExpr
;
552 return std::make_pair(EvalResult("Unexpected end of expression"), "");
555 std::tie(SubExprResult
, RemainingExpr
) = evalParensExpr(Expr
, PCtx
);
556 else if (Expr
[0] == '*')
557 std::tie(SubExprResult
, RemainingExpr
) = evalLoadExpr(Expr
);
558 else if (isalpha(Expr
[0]) || Expr
[0] == '_')
559 std::tie(SubExprResult
, RemainingExpr
) = evalIdentifierExpr(Expr
, PCtx
);
560 else if (isdigit(Expr
[0]))
561 std::tie(SubExprResult
, RemainingExpr
) = evalNumberExpr(Expr
);
563 return std::make_pair(
564 unexpectedToken(Expr
, Expr
,
565 "expected '(', '*', identifier, or number"), "");
567 if (SubExprResult
.hasError())
568 return std::make_pair(SubExprResult
, RemainingExpr
);
570 // Evaluate bit-slice if present.
571 if (RemainingExpr
.startswith("["))
572 std::tie(SubExprResult
, RemainingExpr
) =
573 evalSliceExpr(std::make_pair(SubExprResult
, RemainingExpr
));
575 return std::make_pair(SubExprResult
, RemainingExpr
);
578 // Evaluate a bit-slice of an expression.
579 // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
580 // slice is the bits between high and low (inclusive) in the original
581 // expression, right shifted so that the "low" bit is in position 0 in the
583 // Returns a pair containing the result of the slice operation, plus the
584 // expression remaining to be parsed.
585 std::pair
<EvalResult
, StringRef
>
586 evalSliceExpr(const std::pair
<EvalResult
, StringRef
> &Ctx
) const {
587 EvalResult SubExprResult
;
588 StringRef RemainingExpr
;
589 std::tie(SubExprResult
, RemainingExpr
) = Ctx
;
591 assert(RemainingExpr
.startswith("[") && "Not a slice expr.");
592 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
594 EvalResult HighBitExpr
;
595 std::tie(HighBitExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
597 if (HighBitExpr
.hasError())
598 return std::make_pair(HighBitExpr
, RemainingExpr
);
600 if (!RemainingExpr
.startswith(":"))
601 return std::make_pair(
602 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ':'"), "");
603 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
605 EvalResult LowBitExpr
;
606 std::tie(LowBitExpr
, RemainingExpr
) = evalNumberExpr(RemainingExpr
);
608 if (LowBitExpr
.hasError())
609 return std::make_pair(LowBitExpr
, RemainingExpr
);
611 if (!RemainingExpr
.startswith("]"))
612 return std::make_pair(
613 unexpectedToken(RemainingExpr
, RemainingExpr
, "expected ']'"), "");
614 RemainingExpr
= RemainingExpr
.substr(1).ltrim();
616 unsigned HighBit
= HighBitExpr
.getValue();
617 unsigned LowBit
= LowBitExpr
.getValue();
618 uint64_t Mask
= ((uint64_t)1 << (HighBit
- LowBit
+ 1)) - 1;
619 uint64_t SlicedValue
= (SubExprResult
.getValue() >> LowBit
) & Mask
;
620 return std::make_pair(EvalResult(SlicedValue
), RemainingExpr
);
623 // Evaluate a "complex" expression.
624 // Takes an already evaluated subexpression and checks for the presence of a
625 // binary operator, computing the result of the binary operation if one is
626 // found. Used to make arithmetic expressions left-associative.
627 // Returns a pair containing the ultimate result of evaluating the
628 // expression, plus the expression remaining to be evaluated.
629 std::pair
<EvalResult
, StringRef
>
630 evalComplexExpr(const std::pair
<EvalResult
, StringRef
> &LHSAndRemaining
,
631 ParseContext PCtx
) const {
632 EvalResult LHSResult
;
633 StringRef RemainingExpr
;
634 std::tie(LHSResult
, RemainingExpr
) = LHSAndRemaining
;
636 // If there was an error, or there's nothing left to evaluate, return the
638 if (LHSResult
.hasError() || RemainingExpr
== "")
639 return std::make_pair(LHSResult
, RemainingExpr
);
641 // Otherwise check if this is a binary expressioan.
643 std::tie(BinOp
, RemainingExpr
) = parseBinOpToken(RemainingExpr
);
645 // If this isn't a recognized expression just return.
646 if (BinOp
== BinOpToken::Invalid
)
647 return std::make_pair(LHSResult
, RemainingExpr
);
649 // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
650 EvalResult RHSResult
;
651 std::tie(RHSResult
, RemainingExpr
) = evalSimpleExpr(RemainingExpr
, PCtx
);
653 // If there was an error evaluating the RHS, return it.
654 if (RHSResult
.hasError())
655 return std::make_pair(RHSResult
, RemainingExpr
);
657 // This is a binary expression - evaluate and try to continue as a
659 EvalResult
ThisResult(computeBinOpResult(BinOp
, LHSResult
, RHSResult
));
661 return evalComplexExpr(std::make_pair(ThisResult
, RemainingExpr
), PCtx
);
664 bool decodeInst(StringRef Symbol
, MCInst
&Inst
, uint64_t &Size
) const {
665 MCDisassembler
*Dis
= Checker
.Disassembler
;
666 StringRef SymbolMem
= Checker
.getSymbolContent(Symbol
);
667 ArrayRef
<uint8_t> SymbolBytes(SymbolMem
.bytes_begin(), SymbolMem
.size());
669 MCDisassembler::DecodeStatus S
=
670 Dis
->getInstruction(Inst
, Size
, SymbolBytes
, 0, nulls(), nulls());
672 return (S
== MCDisassembler::Success
);
677 RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(
678 IsSymbolValidFunction IsSymbolValid
, GetSymbolInfoFunction GetSymbolInfo
,
679 GetSectionInfoFunction GetSectionInfo
, GetStubInfoFunction GetStubInfo
,
680 GetGOTInfoFunction GetGOTInfo
, support::endianness Endianness
,
681 MCDisassembler
*Disassembler
, MCInstPrinter
*InstPrinter
,
682 raw_ostream
&ErrStream
)
683 : IsSymbolValid(std::move(IsSymbolValid
)),
684 GetSymbolInfo(std::move(GetSymbolInfo
)),
685 GetSectionInfo(std::move(GetSectionInfo
)),
686 GetStubInfo(std::move(GetStubInfo
)), GetGOTInfo(std::move(GetGOTInfo
)),
687 Endianness(Endianness
), Disassembler(Disassembler
),
688 InstPrinter(InstPrinter
), ErrStream(ErrStream
) {}
690 bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr
) const {
691 CheckExpr
= CheckExpr
.trim();
692 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
694 RuntimeDyldCheckerExprEval
P(*this, ErrStream
);
695 bool Result
= P
.evaluate(CheckExpr
);
697 LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr
<< "' "
698 << (Result
? "passed" : "FAILED") << ".\n");
702 bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix
,
703 MemoryBuffer
*MemBuf
) const {
704 bool DidAllTestsPass
= true;
705 unsigned NumRules
= 0;
707 const char *LineStart
= MemBuf
->getBufferStart();
710 while (LineStart
!= MemBuf
->getBufferEnd() && std::isspace(*LineStart
))
713 while (LineStart
!= MemBuf
->getBufferEnd() && *LineStart
!= '\0') {
714 const char *LineEnd
= LineStart
;
715 while (LineEnd
!= MemBuf
->getBufferEnd() && *LineEnd
!= '\r' &&
719 StringRef
Line(LineStart
, LineEnd
- LineStart
);
720 if (Line
.startswith(RulePrefix
)) {
721 DidAllTestsPass
&= check(Line
.substr(RulePrefix
.size()));
727 while (LineStart
!= MemBuf
->getBufferEnd() && std::isspace(*LineStart
))
730 return DidAllTestsPass
&& (NumRules
!= 0);
733 bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol
) const {
734 return IsSymbolValid(Symbol
);
737 uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol
) const {
738 auto SymInfo
= GetSymbolInfo(Symbol
);
740 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
744 if (SymInfo
->isZeroFill())
747 return static_cast<uint64_t>(
748 reinterpret_cast<uintptr_t>(SymInfo
->getContent().data()));
751 uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol
) const {
752 auto SymInfo
= GetSymbolInfo(Symbol
);
754 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
758 return SymInfo
->getTargetAddress();
761 uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr
,
762 unsigned Size
) const {
763 uintptr_t PtrSizedAddr
= static_cast<uintptr_t>(SrcAddr
);
764 assert(PtrSizedAddr
== SrcAddr
&& "Linker memory pointer out-of-range.");
765 void *Ptr
= reinterpret_cast<void*>(PtrSizedAddr
);
769 return support::endian::read
<uint8_t>(Ptr
, Endianness
);
771 return support::endian::read
<uint16_t>(Ptr
, Endianness
);
773 return support::endian::read
<uint32_t>(Ptr
, Endianness
);
775 return support::endian::read
<uint64_t>(Ptr
, Endianness
);
777 llvm_unreachable("Unsupported read size");
780 StringRef
RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol
) const {
781 auto SymInfo
= GetSymbolInfo(Symbol
);
783 logAllUnhandledErrors(SymInfo
.takeError(), errs(), "RTDyldChecker: ");
786 return SymInfo
->getContent();
789 std::pair
<uint64_t, std::string
> RuntimeDyldCheckerImpl::getSectionAddr(
790 StringRef FileName
, StringRef SectionName
, bool IsInsideLoad
) const {
792 auto SecInfo
= GetSectionInfo(FileName
, SectionName
);
796 raw_string_ostream
ErrMsgStream(ErrMsg
);
797 logAllUnhandledErrors(SecInfo
.takeError(), ErrMsgStream
,
800 return std::make_pair(0, std::move(ErrMsg
));
803 // If this address is being looked up in "load" mode, return the content
804 // pointer, otherwise return the target address.
809 if (SecInfo
->isZeroFill())
812 Addr
= pointerToJITTargetAddress(SecInfo
->getContent().data());
814 Addr
= SecInfo
->getTargetAddress();
816 return std::make_pair(Addr
, "");
819 std::pair
<uint64_t, std::string
> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
820 StringRef StubContainerName
, StringRef SymbolName
, bool IsInsideLoad
,
821 bool IsStubAddr
) const {
823 auto StubInfo
= IsStubAddr
? GetStubInfo(StubContainerName
, SymbolName
)
824 : GetGOTInfo(StubContainerName
, SymbolName
);
829 raw_string_ostream
ErrMsgStream(ErrMsg
);
830 logAllUnhandledErrors(StubInfo
.takeError(), ErrMsgStream
,
833 return std::make_pair((uint64_t)0, std::move(ErrMsg
));
839 if (StubInfo
->isZeroFill())
840 return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");
841 Addr
= pointerToJITTargetAddress(StubInfo
->getContent().data());
843 Addr
= StubInfo
->getTargetAddress();
845 return std::make_pair(Addr
, "");
848 RuntimeDyldChecker::RuntimeDyldChecker(
849 IsSymbolValidFunction IsSymbolValid
, GetSymbolInfoFunction GetSymbolInfo
,
850 GetSectionInfoFunction GetSectionInfo
, GetStubInfoFunction GetStubInfo
,
851 GetGOTInfoFunction GetGOTInfo
, support::endianness Endianness
,
852 MCDisassembler
*Disassembler
, MCInstPrinter
*InstPrinter
,
853 raw_ostream
&ErrStream
)
854 : Impl(::std::make_unique
<RuntimeDyldCheckerImpl
>(
855 std::move(IsSymbolValid
), std::move(GetSymbolInfo
),
856 std::move(GetSectionInfo
), std::move(GetStubInfo
),
857 std::move(GetGOTInfo
), Endianness
, Disassembler
, InstPrinter
,
860 RuntimeDyldChecker::~RuntimeDyldChecker() {}
862 bool RuntimeDyldChecker::check(StringRef CheckExpr
) const {
863 return Impl
->check(CheckExpr
);
866 bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix
,
867 MemoryBuffer
*MemBuf
) const {
868 return Impl
->checkAllRulesInBuffer(RulePrefix
, MemBuf
);
871 std::pair
<uint64_t, std::string
>
872 RuntimeDyldChecker::getSectionAddr(StringRef FileName
, StringRef SectionName
,
874 return Impl
->getSectionAddr(FileName
, SectionName
, LocalAddress
);