LLVM  12.0.0git
RuntimeDyldChecker.cpp
Go to the documentation of this file.
1 //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "RuntimeDyldCheckerImpl.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCInst.h"
16 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/Path.h"
19 #include <cctype>
20 #include <memory>
21 #include <utility>
22 
23 #define DEBUG_TYPE "rtdyld"
24 
25 using namespace llvm;
26 
27 namespace llvm {
28 
29 // Helper class that implements the language evaluated by RuntimeDyldChecker.
31 public:
33  raw_ostream &ErrStream)
34  : Checker(Checker) {}
35 
36  bool evaluate(StringRef Expr) const {
37  // Expect equality expression of the form 'LHS = RHS'.
38  Expr = Expr.trim();
39  size_t EQIdx = Expr.find('=');
40 
41  ParseContext OutsideLoad(false);
42 
43  // Evaluate LHS.
44  StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
45  StringRef RemainingExpr;
46  EvalResult LHSResult;
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, ""));
53 
54  // Evaluate RHS.
55  StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();
56  EvalResult RHSResult;
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, ""));
63 
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())
68  << "\n";
69  return false;
70  }
71  return true;
72  }
73 
74 private:
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.
80 
81  struct ParseContext {
82  bool IsInsideLoad;
83  ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}
84  };
85 
86  const RuntimeDyldCheckerImpl &Checker;
87 
88  enum class BinOpToken : unsigned {
89  Invalid,
90  Add,
91  Sub,
92  BitwiseAnd,
93  BitwiseOr,
94  ShiftLeft,
95  ShiftRight
96  };
97 
98  class EvalResult {
99  public:
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; }
107 
108  private:
109  uint64_t Value;
110  std::string ErrorMsg;
111  };
112 
113  StringRef getTokenForError(StringRef Expr) const {
114  if (Expr.empty())
115  return "";
116 
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);
122  else {
123  unsigned TokLen = 1;
124  if (Expr.startswith("<<") || Expr.startswith(">>"))
125  TokLen = 2;
126  Token = Expr.substr(0, TokLen);
127  }
128  return Token;
129  }
130 
131  EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr,
132  StringRef ErrText) const {
133  std::string ErrorMsg("Encountered unexpected token '");
134  ErrorMsg += getTokenForError(TokenStart);
135  if (SubExpr != "") {
136  ErrorMsg += "' while parsing subexpression '";
137  ErrorMsg += SubExpr;
138  }
139  ErrorMsg += "'";
140  if (ErrText != "") {
141  ErrorMsg += " ";
142  ErrorMsg += ErrText;
143  }
144  return EvalResult(std::move(ErrorMsg));
145  }
146 
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";
151  return false;
152  }
153 
154  std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {
155  if (Expr.empty())
156  return std::make_pair(BinOpToken::Invalid, "");
157 
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());
163 
164  // Handle one-character tokens.
165  BinOpToken Op;
166  switch (Expr[0]) {
167  default:
168  return std::make_pair(BinOpToken::Invalid, Expr);
169  case '+':
170  Op = BinOpToken::Add;
171  break;
172  case '-':
173  Op = BinOpToken::Sub;
174  break;
175  case '&':
176  Op = BinOpToken::BitwiseAnd;
177  break;
178  case '|':
179  Op = BinOpToken::BitwiseOr;
180  break;
181  }
182 
183  return std::make_pair(Op, Expr.substr(1).ltrim());
184  }
185 
186  EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,
187  const EvalResult &RHSResult) const {
188  switch (Op) {
189  default:
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());
203  }
204  }
205 
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"
212  ":_.$");
213  return std::make_pair(Expr.substr(0, FirstNonSymbol),
214  Expr.substr(FirstNonSymbol).ltrim());
215  }
216 
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);
229 
230  if (!Checker.isSymbolValid(Symbol))
231  return std::make_pair(
232  EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
233  "");
234 
235  if (!RemainingExpr.startswith(","))
236  return std::make_pair(
237  unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
238  RemainingExpr = RemainingExpr.substr(1).ltrim();
239 
240  EvalResult OpIdxExpr;
241  std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
242  if (OpIdxExpr.hasError())
243  return std::make_pair(OpIdxExpr, "");
244 
245  if (!RemainingExpr.startswith(")"))
246  return std::make_pair(
247  unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
248  RemainingExpr = RemainingExpr.substr(1).ltrim();
249 
250  MCInst Inst;
251  uint64_t Size;
252  if (!decodeInst(Symbol, Inst, Size))
253  return std::make_pair(
254  EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
255  "");
256 
257  unsigned OpIdx = OpIdxExpr.getValue();
258  if (OpIdx >= Inst.getNumOperands()) {
259  std::string ErrMsg;
260  raw_string_ostream ErrMsgStream(ErrMsg);
261  ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx)
262  << "' for instruction '" << Symbol
263  << "'. Instruction has only "
264  << format("%i", Inst.getNumOperands())
265  << " operands.\nInstruction is:\n ";
266  Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
267  return std::make_pair(EvalResult(ErrMsgStream.str()), "");
268  }
269 
270  const MCOperand &Op = Inst.getOperand(OpIdx);
271  if (!Op.isImm()) {
272  std::string ErrMsg;
273  raw_string_ostream ErrMsgStream(ErrMsg);
274  ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '"
275  << Symbol << "' is not an immediate.\nInstruction is:\n ";
276  Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter);
277 
278  return std::make_pair(EvalResult(ErrMsgStream.str()), "");
279  }
280 
281  return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
282  }
283 
284  // Evaluate a call to next_pc.
285  // Decode the instruction at the given symbol and return the following program
286  // counter.
287  // Returns an error if the instruction cannot be decoded.
288  // On success, returns a pair containing the next PC, plus of the
289  // expression remaining to be evaluated.
290  std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr,
291  ParseContext PCtx) const {
292  if (!Expr.startswith("("))
293  return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
294  StringRef RemainingExpr = Expr.substr(1).ltrim();
296  std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
297 
298  if (!Checker.isSymbolValid(Symbol))
299  return std::make_pair(
300  EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
301  "");
302 
303  if (!RemainingExpr.startswith(")"))
304  return std::make_pair(
305  unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
306  RemainingExpr = RemainingExpr.substr(1).ltrim();
307 
308  MCInst Inst;
309  uint64_t InstSize;
310  if (!decodeInst(Symbol, Inst, InstSize))
311  return std::make_pair(
312  EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
313  "");
314 
315  uint64_t SymbolAddr = PCtx.IsInsideLoad
316  ? Checker.getSymbolLocalAddr(Symbol)
317  : Checker.getSymbolRemoteAddr(Symbol);
318  uint64_t NextPC = SymbolAddr + InstSize;
319 
320  return std::make_pair(EvalResult(NextPC), RemainingExpr);
321  }
322 
323  // Evaluate a call to stub_addr/got_addr.
324  // Look up and return the address of the stub for the given
325  // (<file name>, <section name>, <symbol name>) tuple.
326  // On success, returns a pair containing the stub address, plus the expression
327  // remaining to be evaluated.
328  std::pair<EvalResult, StringRef>
329  evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const {
330  if (!Expr.startswith("("))
331  return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
332  StringRef RemainingExpr = Expr.substr(1).ltrim();
333 
334  // Handle file-name specially, as it may contain characters that aren't
335  // legal for symbols.
336  StringRef StubContainerName;
337  size_t ComaIdx = RemainingExpr.find(',');
338  StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim();
339  RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
340 
341  if (!RemainingExpr.startswith(","))
342  return std::make_pair(
343  unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
344  RemainingExpr = RemainingExpr.substr(1).ltrim();
345 
347  std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
348 
349  if (!RemainingExpr.startswith(")"))
350  return std::make_pair(
351  unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
352  RemainingExpr = RemainingExpr.substr(1).ltrim();
353 
354  uint64_t StubAddr;
355  std::string ErrorMsg = "";
356  std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
357  StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr);
358 
359  if (ErrorMsg != "")
360  return std::make_pair(EvalResult(ErrorMsg), "");
361 
362  return std::make_pair(EvalResult(StubAddr), RemainingExpr);
363  }
364 
365  std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr,
366  ParseContext PCtx) const {
367  if (!Expr.startswith("("))
368  return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), "");
369  StringRef RemainingExpr = Expr.substr(1).ltrim();
370 
371  // Handle file-name specially, as it may contain characters that aren't
372  // legal for symbols.
373  StringRef FileName;
374  size_t ComaIdx = RemainingExpr.find(',');
375  FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
376  RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
377 
378  if (!RemainingExpr.startswith(","))
379  return std::make_pair(
380  unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
381  RemainingExpr = RemainingExpr.substr(1).ltrim();
382 
384  std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr);
385 
386  if (!RemainingExpr.startswith(")"))
387  return std::make_pair(
388  unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
389  RemainingExpr = RemainingExpr.substr(1).ltrim();
390 
391  uint64_t StubAddr;
392  std::string ErrorMsg = "";
393  std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(
394  FileName, SectionName, PCtx.IsInsideLoad);
395 
396  if (ErrorMsg != "")
397  return std::make_pair(EvalResult(ErrorMsg), "");
398 
399  return std::make_pair(EvalResult(StubAddr), RemainingExpr);
400  }
401 
402  // Evaluate an identiefer expr, which may be a symbol, or a call to
403  // one of the builtin functions: get_insn_opcode or get_insn_length.
404  // Return the result, plus the expression remaining to be parsed.
405  std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr,
406  ParseContext PCtx) const {
408  StringRef RemainingExpr;
409  std::tie(Symbol, RemainingExpr) = parseSymbol(Expr);
410 
411  // Check for builtin function calls.
412  if (Symbol == "decode_operand")
413  return evalDecodeOperand(RemainingExpr);
414  else if (Symbol == "next_pc")
415  return evalNextPC(RemainingExpr, PCtx);
416  else if (Symbol == "stub_addr")
417  return evalStubOrGOTAddr(RemainingExpr, PCtx, true);
418  else if (Symbol == "got_addr")
419  return evalStubOrGOTAddr(RemainingExpr, PCtx, false);
420  else if (Symbol == "section_addr")
421  return evalSectionAddr(RemainingExpr, PCtx);
422 
423  if (!Checker.isSymbolValid(Symbol)) {
424  std::string ErrMsg("No known address for symbol '");
425  ErrMsg += Symbol;
426  ErrMsg += "'";
427  if (Symbol.startswith("L"))
428  ErrMsg += " (this appears to be an assembler local label - "
429  " perhaps drop the 'L'?)";
430 
431  return std::make_pair(EvalResult(ErrMsg), "");
432  }
433 
434  // The value for the symbol depends on the context we're evaluating in:
435  // Inside a load this is the address in the linker's memory, outside a
436  // load it's the address in the target processes memory.
437  uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol)
438  : Checker.getSymbolRemoteAddr(Symbol);
439 
440  // Looks like a plain symbol reference.
441  return std::make_pair(EvalResult(Value), RemainingExpr);
442  }
443 
444  // Parse a number (hexadecimal or decimal) and return a (string, string)
445  // pair representing the number and the expression remaining to be parsed.
446  std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const {
447  size_t FirstNonDigit = StringRef::npos;
448  if (Expr.startswith("0x")) {
449  FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2);
450  if (FirstNonDigit == StringRef::npos)
451  FirstNonDigit = Expr.size();
452  } else {
453  FirstNonDigit = Expr.find_first_not_of("0123456789");
454  if (FirstNonDigit == StringRef::npos)
455  FirstNonDigit = Expr.size();
456  }
457  return std::make_pair(Expr.substr(0, FirstNonDigit),
458  Expr.substr(FirstNonDigit));
459  }
460 
461  // Evaluate a constant numeric expression (hexadecimal or decimal) and
462  // return a pair containing the result, and the expression remaining to be
463  // evaluated.
464  std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {
465  StringRef ValueStr;
466  StringRef RemainingExpr;
467  std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
468 
469  if (ValueStr.empty() || !isdigit(ValueStr[0]))
470  return std::make_pair(
471  unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), "");
472  uint64_t Value;
473  ValueStr.getAsInteger(0, Value);
474  return std::make_pair(EvalResult(Value), RemainingExpr);
475  }
476 
477  // Evaluate an expression of the form "(<expr>)" and return a pair
478  // containing the result of evaluating <expr>, plus the expression
479  // remaining to be parsed.
480  std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr,
481  ParseContext PCtx) const {
482  assert(Expr.startswith("(") && "Not a parenthesized expression");
483  EvalResult SubExprResult;
484  StringRef RemainingExpr;
485  std::tie(SubExprResult, RemainingExpr) =
486  evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx);
487  if (SubExprResult.hasError())
488  return std::make_pair(SubExprResult, "");
489  if (!RemainingExpr.startswith(")"))
490  return std::make_pair(
491  unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
492  RemainingExpr = RemainingExpr.substr(1).ltrim();
493  return std::make_pair(SubExprResult, RemainingExpr);
494  }
495 
496  // Evaluate an expression in one of the following forms:
497  // *{<number>}<expr>
498  // Return a pair containing the result, plus the expression remaining to be
499  // parsed.
500  std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
501  assert(Expr.startswith("*") && "Not a load expression");
502  StringRef RemainingExpr = Expr.substr(1).ltrim();
503 
504  // Parse read size.
505  if (!RemainingExpr.startswith("{"))
506  return std::make_pair(EvalResult("Expected '{' following '*'."), "");
507  RemainingExpr = RemainingExpr.substr(1).ltrim();
508  EvalResult ReadSizeExpr;
509  std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
510  if (ReadSizeExpr.hasError())
511  return std::make_pair(ReadSizeExpr, RemainingExpr);
512  uint64_t ReadSize = ReadSizeExpr.getValue();
513  if (ReadSize < 1 || ReadSize > 8)
514  return std::make_pair(EvalResult("Invalid size for dereference."), "");
515  if (!RemainingExpr.startswith("}"))
516  return std::make_pair(EvalResult("Missing '}' for dereference."), "");
517  RemainingExpr = RemainingExpr.substr(1).ltrim();
518 
519  // Evaluate the expression representing the load address.
520  ParseContext LoadCtx(true);
521  EvalResult LoadAddrExprResult;
522  std::tie(LoadAddrExprResult, RemainingExpr) =
523  evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx);
524 
525  if (LoadAddrExprResult.hasError())
526  return std::make_pair(LoadAddrExprResult, "");
527 
528  uint64_t LoadAddr = LoadAddrExprResult.getValue();
529 
530  // If there is no error but the content pointer is null then this is a
531  // zero-fill symbol/section.
532  if (LoadAddr == 0)
533  return std::make_pair(0, RemainingExpr);
534 
535  return std::make_pair(
536  EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),
537  RemainingExpr);
538  }
539 
540  // Evaluate a "simple" expression. This is any expression that _isn't_ an
541  // un-parenthesized binary expression.
542  //
543  // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
544  //
545  // Returns a pair containing the result of the evaluation, plus the
546  // expression remaining to be parsed.
547  std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr,
548  ParseContext PCtx) const {
549  EvalResult SubExprResult;
550  StringRef RemainingExpr;
551 
552  if (Expr.empty())
553  return std::make_pair(EvalResult("Unexpected end of expression"), "");
554 
555  if (Expr[0] == '(')
556  std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx);
557  else if (Expr[0] == '*')
558  std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr);
559  else if (isalpha(Expr[0]) || Expr[0] == '_')
560  std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx);
561  else if (isdigit(Expr[0]))
562  std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr);
563  else
564  return std::make_pair(
565  unexpectedToken(Expr, Expr,
566  "expected '(', '*', identifier, or number"), "");
567 
568  if (SubExprResult.hasError())
569  return std::make_pair(SubExprResult, RemainingExpr);
570 
571  // Evaluate bit-slice if present.
572  if (RemainingExpr.startswith("["))
573  std::tie(SubExprResult, RemainingExpr) =
574  evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
575 
576  return std::make_pair(SubExprResult, RemainingExpr);
577  }
578 
579  // Evaluate a bit-slice of an expression.
580  // A bit-slice has the form "<expr>[high:low]". The result of evaluating a
581  // slice is the bits between high and low (inclusive) in the original
582  // expression, right shifted so that the "low" bit is in position 0 in the
583  // result.
584  // Returns a pair containing the result of the slice operation, plus the
585  // expression remaining to be parsed.
586  std::pair<EvalResult, StringRef>
587  evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const {
588  EvalResult SubExprResult;
589  StringRef RemainingExpr;
590  std::tie(SubExprResult, RemainingExpr) = Ctx;
591 
592  assert(RemainingExpr.startswith("[") && "Not a slice expr.");
593  RemainingExpr = RemainingExpr.substr(1).ltrim();
594 
595  EvalResult HighBitExpr;
596  std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
597 
598  if (HighBitExpr.hasError())
599  return std::make_pair(HighBitExpr, RemainingExpr);
600 
601  if (!RemainingExpr.startswith(":"))
602  return std::make_pair(
603  unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");
604  RemainingExpr = RemainingExpr.substr(1).ltrim();
605 
606  EvalResult LowBitExpr;
607  std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
608 
609  if (LowBitExpr.hasError())
610  return std::make_pair(LowBitExpr, RemainingExpr);
611 
612  if (!RemainingExpr.startswith("]"))
613  return std::make_pair(
614  unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");
615  RemainingExpr = RemainingExpr.substr(1).ltrim();
616 
617  unsigned HighBit = HighBitExpr.getValue();
618  unsigned LowBit = LowBitExpr.getValue();
619  uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1;
620  uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask;
621  return std::make_pair(EvalResult(SlicedValue), RemainingExpr);
622  }
623 
624  // Evaluate a "complex" expression.
625  // Takes an already evaluated subexpression and checks for the presence of a
626  // binary operator, computing the result of the binary operation if one is
627  // found. Used to make arithmetic expressions left-associative.
628  // Returns a pair containing the ultimate result of evaluating the
629  // expression, plus the expression remaining to be evaluated.
630  std::pair<EvalResult, StringRef>
631  evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining,
632  ParseContext PCtx) const {
633  EvalResult LHSResult;
634  StringRef RemainingExpr;
635  std::tie(LHSResult, RemainingExpr) = LHSAndRemaining;
636 
637  // If there was an error, or there's nothing left to evaluate, return the
638  // result.
639  if (LHSResult.hasError() || RemainingExpr == "")
640  return std::make_pair(LHSResult, RemainingExpr);
641 
642  // Otherwise check if this is a binary expressioan.
643  BinOpToken BinOp;
644  std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
645 
646  // If this isn't a recognized expression just return.
647  if (BinOp == BinOpToken::Invalid)
648  return std::make_pair(LHSResult, RemainingExpr);
649 
650  // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop.
651  EvalResult RHSResult;
652  std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx);
653 
654  // If there was an error evaluating the RHS, return it.
655  if (RHSResult.hasError())
656  return std::make_pair(RHSResult, RemainingExpr);
657 
658  // This is a binary expression - evaluate and try to continue as a
659  // complex expr.
660  EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
661 
662  return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);
663  }
664 
665  bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const {
666  MCDisassembler *Dis = Checker.Disassembler;
667  StringRef SymbolMem = Checker.getSymbolContent(Symbol);
668  ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin(), SymbolMem.size());
669 
671  Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls());
672 
673  return (S == MCDisassembler::Success);
674  }
675 };
676 }
677 
679  IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
680  GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
681  GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
682  MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
683  raw_ostream &ErrStream)
684  : IsSymbolValid(std::move(IsSymbolValid)),
685  GetSymbolInfo(std::move(GetSymbolInfo)),
686  GetSectionInfo(std::move(GetSectionInfo)),
687  GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)),
688  Endianness(Endianness), Disassembler(Disassembler),
689  InstPrinter(InstPrinter), ErrStream(ErrStream) {}
690 
692  CheckExpr = CheckExpr.trim();
693  LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
694  << "'...\n");
695  RuntimeDyldCheckerExprEval P(*this, ErrStream);
696  bool Result = P.evaluate(CheckExpr);
697  (void)Result;
698  LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
699  << (Result ? "passed" : "FAILED") << ".\n");
700  return Result;
701 }
702 
704  MemoryBuffer *MemBuf) const {
705  bool DidAllTestsPass = true;
706  unsigned NumRules = 0;
707 
708  std::string CheckExpr;
709  const char *LineStart = MemBuf->getBufferStart();
710 
711  // Eat whitespace.
712  while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))
713  ++LineStart;
714 
715  while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') {
716  const char *LineEnd = LineStart;
717  while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&
718  *LineEnd != '\n')
719  ++LineEnd;
720 
721  StringRef Line(LineStart, LineEnd - LineStart);
722  if (Line.startswith(RulePrefix))
723  CheckExpr += Line.substr(RulePrefix.size()).str();
724 
725  // If there's a check expr string...
726  if (!CheckExpr.empty()) {
727  // ... and it's complete then run it, otherwise remove the trailer '\'.
728  if (CheckExpr.back() != '\\') {
729  DidAllTestsPass &= check(CheckExpr);
730  CheckExpr.clear();
731  ++NumRules;
732  } else
733  CheckExpr.pop_back();
734  }
735 
736  // Eat whitespace.
737  LineStart = LineEnd;
738  while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart))
739  ++LineStart;
740  }
741  return DidAllTestsPass && (NumRules != 0);
742 }
743 
744 bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
745  return IsSymbolValid(Symbol);
746 }
747 
748 uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const {
749  auto SymInfo = GetSymbolInfo(Symbol);
750  if (!SymInfo) {
751  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
752  return 0;
753  }
754 
755  if (SymInfo->isZeroFill())
756  return 0;
757 
758  return static_cast<uint64_t>(
759  reinterpret_cast<uintptr_t>(SymInfo->getContent().data()));
760 }
761 
762 uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
763  auto SymInfo = GetSymbolInfo(Symbol);
764  if (!SymInfo) {
765  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
766  return 0;
767  }
768 
769  return SymInfo->getTargetAddress();
770 }
771 
772 uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr,
773  unsigned Size) const {
774  uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr);
775  assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range.");
776  void *Ptr = reinterpret_cast<void*>(PtrSizedAddr);
777 
778  switch (Size) {
779  case 1:
780  return support::endian::read<uint8_t>(Ptr, Endianness);
781  case 2:
782  return support::endian::read<uint16_t>(Ptr, Endianness);
783  case 4:
784  return support::endian::read<uint32_t>(Ptr, Endianness);
785  case 8:
786  return support::endian::read<uint64_t>(Ptr, Endianness);
787  }
788  llvm_unreachable("Unsupported read size");
789 }
790 
791 StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
792  auto SymInfo = GetSymbolInfo(Symbol);
793  if (!SymInfo) {
794  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
795  return StringRef();
796  }
797  return SymInfo->getContent();
798 }
799 
800 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
801  StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
802 
803  auto SecInfo = GetSectionInfo(FileName, SectionName);
804  if (!SecInfo) {
805  std::string ErrMsg;
806  {
807  raw_string_ostream ErrMsgStream(ErrMsg);
808  logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream,
809  "RTDyldChecker: ");
810  }
811  return std::make_pair(0, std::move(ErrMsg));
812  }
813 
814  // If this address is being looked up in "load" mode, return the content
815  // pointer, otherwise return the target address.
816 
817  uint64_t Addr = 0;
818 
819  if (IsInsideLoad) {
820  if (SecInfo->isZeroFill())
821  Addr = 0;
822  else
823  Addr = pointerToJITTargetAddress(SecInfo->getContent().data());
824  } else
825  Addr = SecInfo->getTargetAddress();
826 
827  return std::make_pair(Addr, "");
828 }
829 
830 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
831  StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad,
832  bool IsStubAddr) const {
833 
834  auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName)
835  : GetGOTInfo(StubContainerName, SymbolName);
836 
837  if (!StubInfo) {
838  std::string ErrMsg;
839  {
840  raw_string_ostream ErrMsgStream(ErrMsg);
841  logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream,
842  "RTDyldChecker: ");
843  }
844  return std::make_pair((uint64_t)0, std::move(ErrMsg));
845  }
846 
847  uint64_t Addr = 0;
848 
849  if (IsInsideLoad) {
850  if (StubInfo->isZeroFill())
851  return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");
852  Addr = pointerToJITTargetAddress(StubInfo->getContent().data());
853  } else
854  Addr = StubInfo->getTargetAddress();
855 
856  return std::make_pair(Addr, "");
857 }
858 
860  IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo,
861  GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo,
862  GetGOTInfoFunction GetGOTInfo, support::endianness Endianness,
863  MCDisassembler *Disassembler, MCInstPrinter *InstPrinter,
864  raw_ostream &ErrStream)
865  : Impl(::std::make_unique<RuntimeDyldCheckerImpl>(
866  std::move(IsSymbolValid), std::move(GetSymbolInfo),
867  std::move(GetSectionInfo), std::move(GetStubInfo),
868  std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter,
869  ErrStream)) {}
870 
872 
873 bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
874  return Impl->check(CheckExpr);
875 }
876 
878  MemoryBuffer *MemBuf) const {
879  return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
880 }
881 
882 std::pair<uint64_t, std::string>
884  bool LocalAddress) {
885  return Impl->getSectionAddr(FileName, SectionName, LocalAddress);
886 }
bool isImm() const
Definition: MCInst.h:58
bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const
Scan the given memory buffer for lines beginning with the string in RulePrefix.
bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const
This class represents lattice values for constants.
Definition: AllocatorList.h:23
virtual DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef< uint8_t > Bytes, uint64_t Address, raw_ostream &CStream) const =0
Returns the disassembly of a single instruction.
DecodeStatus
Ternary decode status.
Superclass for all disassemblers.
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:289
void dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer=nullptr, StringRef Separator=" ") const
Dump the MCInst as prettily as possible using the additional MC structures, if given.
Definition: MCInst.cpp:72
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
constexpr support::endianness Endianness
The endianness of all multi-byte encoded values in MessagePack.
Definition: MsgPack.h:24
LLVM_NODISCARD StringRef ltrim(char Char) const
Return string with consecutive Char characters starting from the the left removed.
Definition: StringRef.h:823
RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, raw_ostream &ErrStream)
Definition: BitVector.h:959
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E&#39;s largest value.
Definition: BitmaskEnum.h:80
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:612
LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:156
static constexpr size_t npos
Definition: StringRef.h:59
std::function< Expected< MemoryRegionInfo >(StringRef GOTContainer, StringRef TargetName)> GetGOTInfoFunction
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:160
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
std::function< bool(StringRef Symbol)> IsSymbolValidFunction
std::enable_if_t< std::numeric_limits< T >::is_signed, bool > getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:511
int64_t getImm() const
Definition: MCInst.h:75
#define P(N)
std::function< Expected< MemoryRegionInfo >(StringRef SymbolName)> GetSymbolInfoFunction
std::pair< uint64_t, std::string > getSectionAddr(StringRef FileName, StringRef SectionName, bool LocalAddress)
Returns the address of the requested section (or an error message in the second element of the pair i...
LLVM_NODISCARD StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition: StringRef.h:851
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Convert a pointer to a JITTargetAddress.
Definition: JITSymbol.h:69
bool isSpace(char C)
Checks whether character C is whitespace in the "C" locale.
Definition: StringExtras.h:113
std::function< Expected< MemoryRegionInfo >(StringRef StubContainer, StringRef TargetName)> GetStubInfoFunction
LLVM_NODISCARD size_t find_first_not_of(char C, size_t From=0) const
Find the first character in the string that is not C or npos if not found.
Definition: StringRef.cpp:244
bool check(StringRef CheckExpr) const
Check a single expression against the attached RuntimeDyld instance.
LLVM_NODISCARD size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:318
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
unsigned getNumOperands() const
Definition: MCInst.h:182
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition: Error.cpp:61
std::string & str()
Flushes the stream contents to the target string and returns the string&#39;s reference.
Definition: raw_ostream.h:539
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:180
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:52
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
RuntimeDyldCheckerImpl(IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, llvm::raw_ostream &ErrStream)
RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, raw_ostream &ErrStream)
bool evaluate(StringRef Expr) const
const char * getBufferEnd() const
Definition: MemoryBuffer.h:68
This is an instance of a target assembly language printer that converts an MCInst to valid target ass...
Definition: MCInstPrinter.h:42
const unsigned char * bytes_begin() const
Definition: StringRef.h:135
uint32_t Size
Definition: Profile.cpp:46
const char * getBufferStart() const
Definition: MemoryBuffer.h:67
bool check(StringRef CheckExpr) const
SymInfo contains information about symbol: it&#39;s address and section index which is -1LL for absolute ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::function< Expected< MemoryRegionInfo >(StringRef FileName, StringRef SectionName)> GetSectionInfoFunction
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:521
LLVM Value Representation.
Definition: Value.h:74
raw_ostream & nulls()
This returns a reference to a raw_ostream which simply discards output.
const char SectionName[]
Definition: AMDGPUPTNote.h:23
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
LLVM_NODISCARD StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
Definition: StringRef.h:837
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
#define LLVM_DEBUG(X)
Definition: Debug.h:122
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:34