24 #define DEBUG_TYPE "rtdyld"
40 size_t EQIdx = Expr.
find(
'=');
42 ParseContext OutsideLoad(
false);
48 std::tie(LHSResult, RemainingExpr) =
49 evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad);
50 if (LHSResult.hasError())
51 return handleError(Expr, LHSResult);
52 if (RemainingExpr !=
"")
53 return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr,
""));
58 std::tie(RHSResult, RemainingExpr) =
59 evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad);
60 if (RHSResult.hasError())
61 return handleError(Expr, RHSResult);
62 if (RemainingExpr !=
"")
63 return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr,
""));
65 if (LHSResult.getValue() != RHSResult.getValue()) {
66 Checker.ErrStream <<
"Expression '" << Expr <<
"' is false: "
67 <<
format(
"0x%" PRIx64, LHSResult.getValue())
68 <<
" != " <<
format(
"0x%" PRIx64, RHSResult.getValue())
84 ParseContext(
bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}
89 enum class BinOpToken : unsigned {
101 EvalResult() :
Value(0) {}
103 EvalResult(std::string ErrorMsg)
106 bool hasError()
const {
return ErrorMsg !=
""; }
107 const std::string &getErrorMsg()
const {
return ErrorMsg; }
111 std::string ErrorMsg;
119 if (isalpha(Expr[0]))
120 std::tie(
Token, Remaining) = parseSymbol(Expr);
121 else if (isdigit(Expr[0]))
122 std::tie(
Token, Remaining) = parseNumberString(Expr);
134 std::string ErrorMsg(
"Encountered unexpected token '");
135 ErrorMsg += getTokenForError(TokenStart);
137 ErrorMsg +=
"' while parsing subexpression '";
148 bool handleError(
StringRef Expr,
const EvalResult &R)
const {
149 assert(
R.hasError() &&
"Not an error result.");
150 Checker.ErrStream <<
"Error evaluating expression '" << Expr
151 <<
"': " <<
R.getErrorMsg() <<
"\n";
155 std::pair<BinOpToken, StringRef> parseBinOpToken(
StringRef Expr)
const {
157 return std::make_pair(BinOpToken::Invalid,
"");
161 return std::make_pair(BinOpToken::ShiftLeft, Expr.
substr(2).
ltrim());
163 return std::make_pair(BinOpToken::ShiftRight, Expr.
substr(2).
ltrim());
169 return std::make_pair(BinOpToken::Invalid, Expr);
171 Op = BinOpToken::Add;
174 Op = BinOpToken::Sub;
177 Op = BinOpToken::BitwiseAnd;
180 Op = BinOpToken::BitwiseOr;
187 EvalResult computeBinOpResult(BinOpToken
Op,
const EvalResult &LHSResult,
188 const EvalResult &RHSResult)
const {
192 case BinOpToken::Add:
193 return EvalResult(LHSResult.getValue() + RHSResult.getValue());
194 case BinOpToken::Sub:
195 return EvalResult(LHSResult.getValue() - RHSResult.getValue());
196 case BinOpToken::BitwiseAnd:
197 return EvalResult(LHSResult.getValue() & RHSResult.getValue());
198 case BinOpToken::BitwiseOr:
199 return EvalResult(LHSResult.getValue() | RHSResult.getValue());
200 case BinOpToken::ShiftLeft:
201 return EvalResult(LHSResult.getValue() << RHSResult.getValue());
202 case BinOpToken::ShiftRight:
203 return EvalResult(LHSResult.getValue() >> RHSResult.getValue());
209 std::pair<StringRef, StringRef> parseSymbol(
StringRef Expr)
const {
211 "abcdefghijklmnopqrstuvwxyz"
212 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
214 return std::make_pair(Expr.
substr(0, FirstNonSymbol),
224 std::pair<EvalResult, StringRef> evalDecodeOperand(
StringRef Expr)
const {
226 return std::make_pair(unexpectedToken(Expr, Expr,
"expected '('"),
"");
229 std::tie(
Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
231 if (!Checker.isSymbolValid(
Symbol))
232 return std::make_pair(
233 EvalResult((
"Cannot decode unknown symbol '" +
Symbol +
"'").str()),
239 std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
241 case BinOpToken::Add: {
243 std::tie(Number, RemainingExpr) = evalNumberExpr(RemainingExpr);
247 case BinOpToken::Invalid:
250 return std::make_pair(
251 unexpectedToken(RemainingExpr, RemainingExpr,
252 "expected '+' for offset or ',' if no offset"),
257 return std::make_pair(
258 unexpectedToken(RemainingExpr, RemainingExpr,
"expected ','"),
"");
261 EvalResult OpIdxExpr;
262 std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
263 if (OpIdxExpr.hasError())
264 return std::make_pair(OpIdxExpr,
"");
267 return std::make_pair(
268 unexpectedToken(RemainingExpr, RemainingExpr,
"expected ')'"),
"");
273 if (!decodeInst(
Symbol, Inst, Size, Offset))
274 return std::make_pair(
275 EvalResult((
"Couldn't decode instruction at '" +
Symbol +
"'").str()),
278 unsigned OpIdx = OpIdxExpr.getValue();
282 ErrMsgStream <<
"Invalid operand index '" <<
format(
"%i", OpIdx)
283 <<
"' for instruction '" <<
Symbol
284 <<
"'. Instruction has only "
286 <<
" operands.\nInstruction is:\n ";
287 Inst.
dump_pretty(ErrMsgStream, Checker.InstPrinter);
288 return std::make_pair(EvalResult(ErrMsgStream.str()),
"");
295 ErrMsgStream <<
"Operand '" <<
format(
"%i", OpIdx) <<
"' of instruction '"
296 <<
Symbol <<
"' is not an immediate.\nInstruction is:\n ";
297 Inst.
dump_pretty(ErrMsgStream, Checker.InstPrinter);
299 return std::make_pair(EvalResult(ErrMsgStream.str()),
"");
302 return std::make_pair(EvalResult(
Op.getImm()), RemainingExpr);
311 std::pair<EvalResult, StringRef> evalNextPC(
StringRef Expr,
312 ParseContext PCtx)
const {
314 return std::make_pair(unexpectedToken(Expr, Expr,
"expected '('"),
"");
317 std::tie(
Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
319 if (!Checker.isSymbolValid(
Symbol))
320 return std::make_pair(
321 EvalResult((
"Cannot decode unknown symbol '" +
Symbol +
"'").str()),
325 return std::make_pair(
326 unexpectedToken(RemainingExpr, RemainingExpr,
"expected ')'"),
"");
331 if (!decodeInst(
Symbol, Inst, InstSize, 0))
332 return std::make_pair(
333 EvalResult((
"Couldn't decode instruction at '" +
Symbol +
"'").str()),
336 uint64_t SymbolAddr = PCtx.IsInsideLoad
337 ? Checker.getSymbolLocalAddr(
Symbol)
338 : Checker.getSymbolRemoteAddr(
Symbol);
339 uint64_t NextPC = SymbolAddr + InstSize;
341 return std::make_pair(EvalResult(NextPC), RemainingExpr);
349 std::pair<EvalResult, StringRef>
350 evalStubOrGOTAddr(
StringRef Expr, ParseContext PCtx,
bool IsStubAddr)
const {
352 return std::make_pair(unexpectedToken(Expr, Expr,
"expected '('"),
"");
358 size_t ComaIdx = RemainingExpr.
find(
',');
359 StubContainerName = RemainingExpr.
substr(0, ComaIdx).
rtrim();
360 RemainingExpr = RemainingExpr.
substr(ComaIdx).
ltrim();
363 return std::make_pair(
364 unexpectedToken(RemainingExpr, Expr,
"expected ','"),
"");
368 std::tie(
Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
371 return std::make_pair(
372 unexpectedToken(RemainingExpr, Expr,
"expected ')'"),
"");
376 std::string ErrorMsg;
377 std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
378 StubContainerName,
Symbol, PCtx.IsInsideLoad, IsStubAddr);
381 return std::make_pair(EvalResult(ErrorMsg),
"");
383 return std::make_pair(EvalResult(StubAddr), RemainingExpr);
386 std::pair<EvalResult, StringRef> evalSectionAddr(
StringRef Expr,
387 ParseContext PCtx)
const {
389 return std::make_pair(unexpectedToken(Expr, Expr,
"expected '('"),
"");
395 size_t ComaIdx = RemainingExpr.
find(
',');
396 FileName = RemainingExpr.
substr(0, ComaIdx).
rtrim();
397 RemainingExpr = RemainingExpr.
substr(ComaIdx).
ltrim();
400 return std::make_pair(
401 unexpectedToken(RemainingExpr, Expr,
"expected ','"),
"");
405 size_t CloseParensIdx = RemainingExpr.
find(
')');
407 RemainingExpr = RemainingExpr.
substr(CloseParensIdx).
ltrim();
410 return std::make_pair(
411 unexpectedToken(RemainingExpr, Expr,
"expected ')'"),
"");
415 std::string ErrorMsg;
416 std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(
420 return std::make_pair(EvalResult(ErrorMsg),
"");
422 return std::make_pair(EvalResult(StubAddr), RemainingExpr);
428 std::pair<EvalResult, StringRef> evalIdentifierExpr(
StringRef Expr,
429 ParseContext PCtx)
const {
432 std::tie(
Symbol, RemainingExpr) = parseSymbol(Expr);
435 if (
Symbol ==
"decode_operand")
436 return evalDecodeOperand(RemainingExpr);
437 else if (
Symbol ==
"next_pc")
438 return evalNextPC(RemainingExpr, PCtx);
439 else if (
Symbol ==
"stub_addr")
440 return evalStubOrGOTAddr(RemainingExpr, PCtx,
true);
441 else if (
Symbol ==
"got_addr")
442 return evalStubOrGOTAddr(RemainingExpr, PCtx,
false);
443 else if (
Symbol ==
"section_addr")
444 return evalSectionAddr(RemainingExpr, PCtx);
446 if (!Checker.isSymbolValid(
Symbol)) {
447 std::string ErrMsg(
"No known address for symbol '");
450 if (
Symbol.startswith(
"L"))
451 ErrMsg +=
" (this appears to be an assembler local label - "
452 " perhaps drop the 'L'?)";
454 return std::make_pair(EvalResult(ErrMsg),
"");
461 : Checker.getSymbolRemoteAddr(
Symbol);
464 return std::make_pair(EvalResult(
Value), RemainingExpr);
469 std::pair<StringRef, StringRef> parseNumberString(
StringRef Expr)
const {
474 FirstNonDigit = Expr.
size();
478 FirstNonDigit = Expr.
size();
480 return std::make_pair(Expr.
substr(0, FirstNonDigit),
481 Expr.
substr(FirstNonDigit));
487 std::pair<EvalResult, StringRef> evalNumberExpr(
StringRef Expr)
const {
490 std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
492 if (ValueStr.
empty() || !isdigit(ValueStr[0]))
493 return std::make_pair(
494 unexpectedToken(RemainingExpr, RemainingExpr,
"expected number"),
"");
497 return std::make_pair(EvalResult(
Value), RemainingExpr);
503 std::pair<EvalResult, StringRef> evalParensExpr(
StringRef Expr,
504 ParseContext PCtx)
const {
506 EvalResult SubExprResult;
508 std::tie(SubExprResult, RemainingExpr) =
509 evalComplexExpr(evalSimpleExpr(Expr.
substr(1).
ltrim(), PCtx), PCtx);
510 if (SubExprResult.hasError())
511 return std::make_pair(SubExprResult,
"");
513 return std::make_pair(
514 unexpectedToken(RemainingExpr, Expr,
"expected ')'"),
"");
516 return std::make_pair(SubExprResult, RemainingExpr);
523 std::pair<EvalResult, StringRef> evalLoadExpr(
StringRef Expr)
const {
529 return std::make_pair(EvalResult(
"Expected '{' following '*'."),
"");
531 EvalResult ReadSizeExpr;
532 std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
533 if (ReadSizeExpr.hasError())
534 return std::make_pair(ReadSizeExpr, RemainingExpr);
535 uint64_t ReadSize = ReadSizeExpr.getValue();
536 if (ReadSize < 1 || ReadSize > 8)
537 return std::make_pair(EvalResult(
"Invalid size for dereference."),
"");
539 return std::make_pair(EvalResult(
"Missing '}' for dereference."),
"");
543 ParseContext LoadCtx(
true);
544 EvalResult LoadAddrExprResult;
545 std::tie(LoadAddrExprResult, RemainingExpr) =
546 evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx);
548 if (LoadAddrExprResult.hasError())
549 return std::make_pair(LoadAddrExprResult,
"");
551 uint64_t LoadAddr = LoadAddrExprResult.getValue();
556 return std::make_pair(0, RemainingExpr);
558 return std::make_pair(
559 EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),
570 std::pair<EvalResult, StringRef> evalSimpleExpr(
StringRef Expr,
571 ParseContext PCtx)
const {
572 EvalResult SubExprResult;
576 return std::make_pair(EvalResult(
"Unexpected end of expression"),
"");
579 std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx);
580 else if (Expr[0] ==
'*')
581 std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
582 else if (isalpha(Expr[0]) || Expr[0] ==
'_')
583 std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);
584 else if (isdigit(Expr[0]))
585 std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
587 return std::make_pair(
588 unexpectedToken(Expr, Expr,
589 "expected '(', '*', identifier, or number"),
"");
591 if (SubExprResult.hasError())
592 return std::make_pair(SubExprResult, RemainingExpr);
596 std::tie(SubExprResult, RemainingExpr) =
597 evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
599 return std::make_pair(SubExprResult, RemainingExpr);
609 std::pair<EvalResult, StringRef>
610 evalSliceExpr(
const std::pair<EvalResult, StringRef> &Ctx)
const {
611 EvalResult SubExprResult;
613 std::tie(SubExprResult, RemainingExpr) = Ctx;
618 EvalResult HighBitExpr;
619 std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
621 if (HighBitExpr.hasError())
622 return std::make_pair(HighBitExpr, RemainingExpr);
625 return std::make_pair(
626 unexpectedToken(RemainingExpr, RemainingExpr,
"expected ':'"),
"");
629 EvalResult LowBitExpr;
630 std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
632 if (LowBitExpr.hasError())
633 return std::make_pair(LowBitExpr, RemainingExpr);
636 return std::make_pair(
637 unexpectedToken(RemainingExpr, RemainingExpr,
"expected ']'"),
"");
640 unsigned HighBit = HighBitExpr.getValue();
641 unsigned LowBit = LowBitExpr.getValue();
643 uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) &
Mask;
644 return std::make_pair(EvalResult(SlicedValue), RemainingExpr);
653 std::pair<EvalResult, StringRef>
654 evalComplexExpr(
const std::pair<EvalResult, StringRef> &LHSAndRemaining,
655 ParseContext PCtx)
const {
656 EvalResult LHSResult;
658 std::tie(LHSResult, RemainingExpr) = LHSAndRemaining;
662 if (LHSResult.hasError() || RemainingExpr ==
"")
663 return std::make_pair(LHSResult, RemainingExpr);
667 std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
670 if (BinOp == BinOpToken::Invalid)
671 return std::make_pair(LHSResult, RemainingExpr);
674 EvalResult RHSResult;
675 std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);
678 if (RHSResult.hasError())
679 return std::make_pair(RHSResult, RemainingExpr);
683 EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
685 return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);
689 int64_t Offset)
const {
693 SymbolMem.
size() - Offset);
704 IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
705 GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
709 : IsSymbolValid(
std::
move(IsSymbolValid)),
710 GetSymbolInfo(
std::
move(GetSymbolInfo)),
711 GetSectionInfo(
std::
move(GetSectionInfo)),
712 GetStubInfo(
std::
move(GetStubInfo)), GetGOTInfo(
std::
move(GetGOTInfo)),
714 InstPrinter(InstPrinter), ErrStream(ErrStream) {}
717 CheckExpr = CheckExpr.
trim();
718 LLVM_DEBUG(
dbgs() <<
"RuntimeDyldChecker: Checking '" << CheckExpr
721 bool Result =
P.evaluate(CheckExpr);
724 << (Result ?
"passed" :
"FAILED") <<
".\n");
730 bool DidAllTestsPass =
true;
731 unsigned NumRules = 0;
733 std::string CheckExpr;
737 while (LineStart != MemBuf->
getBufferEnd() && isSpace(*LineStart))
740 while (LineStart != MemBuf->
getBufferEnd() && *LineStart !=
'\0') {
741 const char *LineEnd = LineStart;
742 while (LineEnd != MemBuf->
getBufferEnd() && *LineEnd !=
'\r' &&
746 StringRef Line(LineStart, LineEnd - LineStart);
751 if (!CheckExpr.empty()) {
753 if (CheckExpr.back() !=
'\\') {
754 DidAllTestsPass &=
check(CheckExpr);
758 CheckExpr.pop_back();
763 while (LineStart != MemBuf->
getBufferEnd() && isSpace(*LineStart))
766 return DidAllTestsPass && (NumRules != 0);
770 return IsSymbolValid(
Symbol);
784 reinterpret_cast<uintptr_t
>(
SymInfo->getContent().data()));
794 return SymInfo->getTargetAddress();
798 unsigned Size)
const {
799 uintptr_t PtrSizedAddr =
static_cast<uintptr_t
>(SrcAddr);
800 assert(PtrSizedAddr == SrcAddr &&
"Linker memory pointer out-of-range.");
801 void *Ptr =
reinterpret_cast<void*
>(PtrSizedAddr);
805 return support::endian::read<uint8_t>(Ptr, Endianness);
807 return support::endian::read<uint16_t>(Ptr, Endianness);
809 return support::endian::read<uint32_t>(Ptr, Endianness);
811 return support::endian::read<uint64_t>(Ptr, Endianness);
822 return {
SymInfo->getContent().data(),
SymInfo->getContent().size()};
825 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
828 auto SecInfo = GetSectionInfo(FileName,
SectionName);
836 return std::make_pair(0,
std::move(ErrMsg));
845 if (SecInfo->isZeroFill())
850 Addr = SecInfo->getTargetAddress();
852 return std::make_pair(
Addr,
"");
855 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
857 bool IsStubAddr)
const {
859 auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName,
SymbolName)
875 if (StubInfo->isZeroFill())
876 return std::make_pair((
uint64_t)0,
"Detected zero-filled stub/GOT entry");
879 Addr = StubInfo->getTargetAddress();
881 return std::make_pair(
Addr,
"");
899 return Impl->check(CheckExpr);
904 return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
907 std::pair<uint64_t, std::string>
910 return Impl->getSectionAddr(FileName,
SectionName, LocalAddress);