LLVM  10.0.0svn
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/MC/MCContext.h"
14 #include "llvm/MC/MCInst.h"
15 #include "llvm/Support/Endian.h"
17 #include "llvm/Support/Path.h"
18 #include <cctype>
19 #include <memory>
20 #include <utility>
21 
22 #define DEBUG_TYPE "rtdyld"
23 
24 using namespace llvm;
25 
26 namespace llvm {
27 
28 // Helper class that implements the language evaluated by RuntimeDyldChecker.
30 public:
32  raw_ostream &ErrStream)
33  : Checker(Checker) {}
34 
35  bool evaluate(StringRef Expr) const {
36  // Expect equality expression of the form 'LHS = RHS'.
37  Expr = Expr.trim();
38  size_t EQIdx = Expr.find('=');
39 
40  ParseContext OutsideLoad(false);
41 
42  // Evaluate LHS.
43  StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim();
44  StringRef RemainingExpr;
45  EvalResult LHSResult;
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, ""));
52 
53  // Evaluate RHS.
54  StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim();
55  EvalResult RHSResult;
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, ""));
62 
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())
67  << "\n";
68  return false;
69  }
70  return true;
71  }
72 
73 private:
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.
79 
80  struct ParseContext {
81  bool IsInsideLoad;
82  ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {}
83  };
84 
85  const RuntimeDyldCheckerImpl &Checker;
86 
87  enum class BinOpToken : unsigned {
88  Invalid,
89  Add,
90  Sub,
91  BitwiseAnd,
92  BitwiseOr,
93  ShiftLeft,
94  ShiftRight
95  };
96 
97  class EvalResult {
98  public:
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; }
106 
107  private:
108  uint64_t Value;
109  std::string ErrorMsg;
110  };
111 
112  StringRef getTokenForError(StringRef Expr) const {
113  if (Expr.empty())
114  return "";
115 
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);
121  else {
122  unsigned TokLen = 1;
123  if (Expr.startswith("<<") || Expr.startswith(">>"))
124  TokLen = 2;
125  Token = Expr.substr(0, TokLen);
126  }
127  return Token;
128  }
129 
130  EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr,
131  StringRef ErrText) const {
132  std::string ErrorMsg("Encountered unexpected token '");
133  ErrorMsg += getTokenForError(TokenStart);
134  if (SubExpr != "") {
135  ErrorMsg += "' while parsing subexpression '";
136  ErrorMsg += SubExpr;
137  }
138  ErrorMsg += "'";
139  if (ErrText != "") {
140  ErrorMsg += " ";
141  ErrorMsg += ErrText;
142  }
143  return EvalResult(std::move(ErrorMsg));
144  }
145 
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";
150  return false;
151  }
152 
153  std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const {
154  if (Expr.empty())
155  return std::make_pair(BinOpToken::Invalid, "");
156 
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());
162 
163  // Handle one-character tokens.
164  BinOpToken Op;
165  switch (Expr[0]) {
166  default:
167  return std::make_pair(BinOpToken::Invalid, Expr);
168  case '+':
169  Op = BinOpToken::Add;
170  break;
171  case '-':
172  Op = BinOpToken::Sub;
173  break;
174  case '&':
175  Op = BinOpToken::BitwiseAnd;
176  break;
177  case '|':
178  Op = BinOpToken::BitwiseOr;
179  break;
180  }
181 
182  return std::make_pair(Op, Expr.substr(1).ltrim());
183  }
184 
185  EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult,
186  const EvalResult &RHSResult) const {
187  switch (Op) {
188  default:
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());
202  }
203  }
204 
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"
211  ":_.$");
212  return std::make_pair(Expr.substr(0, FirstNonSymbol),
213  Expr.substr(FirstNonSymbol).ltrim());
214  }
215 
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);
228 
229  if (!Checker.isSymbolValid(Symbol))
230  return std::make_pair(
231  EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
232  "");
233 
234  if (!RemainingExpr.startswith(","))
235  return std::make_pair(
236  unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), "");
237  RemainingExpr = RemainingExpr.substr(1).ltrim();
238 
239  EvalResult OpIdxExpr;
240  std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
241  if (OpIdxExpr.hasError())
242  return std::make_pair(OpIdxExpr, "");
243 
244  if (!RemainingExpr.startswith(")"))
245  return std::make_pair(
246  unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
247  RemainingExpr = RemainingExpr.substr(1).ltrim();
248 
249  MCInst Inst;
250  uint64_t Size;
251  if (!decodeInst(Symbol, Inst, Size))
252  return std::make_pair(
253  EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
254  "");
255 
256  unsigned OpIdx = OpIdxExpr.getValue();
257  if (OpIdx >= Inst.getNumOperands()) {
258  std::string ErrMsg;
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()), "");
267  }
268 
269  const MCOperand &Op = Inst.getOperand(OpIdx);
270  if (!Op.isImm()) {
271  std::string ErrMsg;
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);
276 
277  return std::make_pair(EvalResult(ErrMsgStream.str()), "");
278  }
279 
280  return std::make_pair(EvalResult(Op.getImm()), RemainingExpr);
281  }
282 
283  // Evaluate a call to next_pc.
284  // Decode the instruction at the given symbol and return the following program
285  // counter.
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);
296 
297  if (!Checker.isSymbolValid(Symbol))
298  return std::make_pair(
299  EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()),
300  "");
301 
302  if (!RemainingExpr.startswith(")"))
303  return std::make_pair(
304  unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), "");
305  RemainingExpr = RemainingExpr.substr(1).ltrim();
306 
307  MCInst Inst;
308  uint64_t InstSize;
309  if (!decodeInst(Symbol, Inst, InstSize))
310  return std::make_pair(
311  EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()),
312  "");
313 
314  uint64_t SymbolAddr = PCtx.IsInsideLoad
315  ? Checker.getSymbolLocalAddr(Symbol)
316  : Checker.getSymbolRemoteAddr(Symbol);
317  uint64_t NextPC = SymbolAddr + InstSize;
318 
319  return std::make_pair(EvalResult(NextPC), RemainingExpr);
320  }
321 
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();
332 
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();
339 
340  if (!RemainingExpr.startswith(","))
341  return std::make_pair(
342  unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
343  RemainingExpr = RemainingExpr.substr(1).ltrim();
344 
346  std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr);
347 
348  if (!RemainingExpr.startswith(")"))
349  return std::make_pair(
350  unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
351  RemainingExpr = RemainingExpr.substr(1).ltrim();
352 
353  uint64_t StubAddr;
354  std::string ErrorMsg = "";
355  std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor(
356  StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr);
357 
358  if (ErrorMsg != "")
359  return std::make_pair(EvalResult(ErrorMsg), "");
360 
361  return std::make_pair(EvalResult(StubAddr), RemainingExpr);
362  }
363 
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();
369 
370  // Handle file-name specially, as it may contain characters that aren't
371  // legal for symbols.
372  StringRef FileName;
373  size_t ComaIdx = RemainingExpr.find(',');
374  FileName = RemainingExpr.substr(0, ComaIdx).rtrim();
375  RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim();
376 
377  if (!RemainingExpr.startswith(","))
378  return std::make_pair(
379  unexpectedToken(RemainingExpr, Expr, "expected ','"), "");
380  RemainingExpr = RemainingExpr.substr(1).ltrim();
381 
383  std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr);
384 
385  if (!RemainingExpr.startswith(")"))
386  return std::make_pair(
387  unexpectedToken(RemainingExpr, Expr, "expected ')'"), "");
388  RemainingExpr = RemainingExpr.substr(1).ltrim();
389 
390  uint64_t StubAddr;
391  std::string ErrorMsg = "";
392  std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr(
393  FileName, SectionName, PCtx.IsInsideLoad);
394 
395  if (ErrorMsg != "")
396  return std::make_pair(EvalResult(ErrorMsg), "");
397 
398  return std::make_pair(EvalResult(StubAddr), RemainingExpr);
399  }
400 
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);
409 
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);
421 
422  if (!Checker.isSymbolValid(Symbol)) {
423  std::string ErrMsg("No known address for symbol '");
424  ErrMsg += Symbol;
425  ErrMsg += "'";
426  if (Symbol.startswith("L"))
427  ErrMsg += " (this appears to be an assembler local label - "
428  " perhaps drop the 'L'?)";
429 
430  return std::make_pair(EvalResult(ErrMsg), "");
431  }
432 
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);
438 
439  // Looks like a plain symbol reference.
440  return std::make_pair(EvalResult(Value), RemainingExpr);
441  }
442 
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();
451  } else {
452  FirstNonDigit = Expr.find_first_not_of("0123456789");
453  if (FirstNonDigit == StringRef::npos)
454  FirstNonDigit = Expr.size();
455  }
456  return std::make_pair(Expr.substr(0, FirstNonDigit),
457  Expr.substr(FirstNonDigit));
458  }
459 
460  // Evaluate a constant numeric expression (hexadecimal or decimal) and
461  // return a pair containing the result, and the expression remaining to be
462  // evaluated.
463  std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const {
464  StringRef ValueStr;
465  StringRef RemainingExpr;
466  std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr);
467 
468  if (ValueStr.empty() || !isdigit(ValueStr[0]))
469  return std::make_pair(
470  unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), "");
471  uint64_t Value;
472  ValueStr.getAsInteger(0, Value);
473  return std::make_pair(EvalResult(Value), RemainingExpr);
474  }
475 
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);
493  }
494 
495  // Evaluate an expression in one of the following forms:
496  // *{<number>}<expr>
497  // Return a pair containing the result, plus the expression remaining to be
498  // parsed.
499  std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const {
500  assert(Expr.startswith("*") && "Not a load expression");
501  StringRef RemainingExpr = Expr.substr(1).ltrim();
502 
503  // Parse read size.
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();
517 
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);
523 
524  if (LoadAddrExprResult.hasError())
525  return std::make_pair(LoadAddrExprResult, "");
526 
527  uint64_t LoadAddr = LoadAddrExprResult.getValue();
528 
529  // If there is no error but the content pointer is null then this is a
530  // zero-fill symbol/section.
531  if (LoadAddr == 0)
532  return std::make_pair(0, RemainingExpr);
533 
534  return std::make_pair(
535  EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)),
536  RemainingExpr);
537  }
538 
539  // Evaluate a "simple" expression. This is any expression that _isn't_ an
540  // un-parenthesized binary expression.
541  //
542  // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr.
543  //
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;
550 
551  if (Expr.empty())
552  return std::make_pair(EvalResult("Unexpected end of expression"), "");
553 
554  if (Expr[0] == '(')
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);
562  else
563  return std::make_pair(
564  unexpectedToken(Expr, Expr,
565  "expected '(', '*', identifier, or number"), "");
566 
567  if (SubExprResult.hasError())
568  return std::make_pair(SubExprResult, RemainingExpr);
569 
570  // Evaluate bit-slice if present.
571  if (RemainingExpr.startswith("["))
572  std::tie(SubExprResult, RemainingExpr) =
573  evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr));
574 
575  return std::make_pair(SubExprResult, RemainingExpr);
576  }
577 
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
582  // result.
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;
590 
591  assert(RemainingExpr.startswith("[") && "Not a slice expr.");
592  RemainingExpr = RemainingExpr.substr(1).ltrim();
593 
594  EvalResult HighBitExpr;
595  std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
596 
597  if (HighBitExpr.hasError())
598  return std::make_pair(HighBitExpr, RemainingExpr);
599 
600  if (!RemainingExpr.startswith(":"))
601  return std::make_pair(
602  unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), "");
603  RemainingExpr = RemainingExpr.substr(1).ltrim();
604 
605  EvalResult LowBitExpr;
606  std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr);
607 
608  if (LowBitExpr.hasError())
609  return std::make_pair(LowBitExpr, RemainingExpr);
610 
611  if (!RemainingExpr.startswith("]"))
612  return std::make_pair(
613  unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), "");
614  RemainingExpr = RemainingExpr.substr(1).ltrim();
615 
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);
621  }
622 
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;
635 
636  // If there was an error, or there's nothing left to evaluate, return the
637  // result.
638  if (LHSResult.hasError() || RemainingExpr == "")
639  return std::make_pair(LHSResult, RemainingExpr);
640 
641  // Otherwise check if this is a binary expressioan.
642  BinOpToken BinOp;
643  std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr);
644 
645  // If this isn't a recognized expression just return.
646  if (BinOp == BinOpToken::Invalid)
647  return std::make_pair(LHSResult, RemainingExpr);
648 
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);
652 
653  // If there was an error evaluating the RHS, return it.
654  if (RHSResult.hasError())
655  return std::make_pair(RHSResult, RemainingExpr);
656 
657  // This is a binary expression - evaluate and try to continue as a
658  // complex expr.
659  EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult));
660 
661  return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx);
662  }
663 
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());
668 
670  Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls(), nulls());
671 
672  return (S == MCDisassembler::Success);
673  }
674 };
675 }
676 
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) {}
689 
691  CheckExpr = CheckExpr.trim();
692  LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr
693  << "'...\n");
694  RuntimeDyldCheckerExprEval P(*this, ErrStream);
695  bool Result = P.evaluate(CheckExpr);
696  (void)Result;
697  LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' "
698  << (Result ? "passed" : "FAILED") << ".\n");
699  return Result;
700 }
701 
703  MemoryBuffer *MemBuf) const {
704  bool DidAllTestsPass = true;
705  unsigned NumRules = 0;
706 
707  const char *LineStart = MemBuf->getBufferStart();
708 
709  // Eat whitespace.
710  while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
711  ++LineStart;
712 
713  while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') {
714  const char *LineEnd = LineStart;
715  while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' &&
716  *LineEnd != '\n')
717  ++LineEnd;
718 
719  StringRef Line(LineStart, LineEnd - LineStart);
720  if (Line.startswith(RulePrefix)) {
721  DidAllTestsPass &= check(Line.substr(RulePrefix.size()));
722  ++NumRules;
723  }
724 
725  // Eat whitespace.
726  LineStart = LineEnd;
727  while (LineStart != MemBuf->getBufferEnd() && std::isspace(*LineStart))
728  ++LineStart;
729  }
730  return DidAllTestsPass && (NumRules != 0);
731 }
732 
733 bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
734  return IsSymbolValid(Symbol);
735 }
736 
737 uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const {
738  auto SymInfo = GetSymbolInfo(Symbol);
739  if (!SymInfo) {
740  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
741  return 0;
742  }
743 
744  if (SymInfo->isZeroFill())
745  return 0;
746 
747  return static_cast<uint64_t>(
748  reinterpret_cast<uintptr_t>(SymInfo->getContent().data()));
749 }
750 
751 uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
752  auto SymInfo = GetSymbolInfo(Symbol);
753  if (!SymInfo) {
754  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
755  return 0;
756  }
757 
758  return SymInfo->getTargetAddress();
759 }
760 
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);
766 
767  switch (Size) {
768  case 1:
769  return support::endian::read<uint8_t>(Ptr, Endianness);
770  case 2:
771  return support::endian::read<uint16_t>(Ptr, Endianness);
772  case 4:
773  return support::endian::read<uint32_t>(Ptr, Endianness);
774  case 8:
775  return support::endian::read<uint64_t>(Ptr, Endianness);
776  }
777  llvm_unreachable("Unsupported read size");
778 }
779 
780 StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
781  auto SymInfo = GetSymbolInfo(Symbol);
782  if (!SymInfo) {
783  logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
784  return StringRef();
785  }
786  return SymInfo->getContent();
787 }
788 
789 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
790  StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
791 
792  auto SecInfo = GetSectionInfo(FileName, SectionName);
793  if (!SecInfo) {
794  std::string ErrMsg;
795  {
796  raw_string_ostream ErrMsgStream(ErrMsg);
797  logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream,
798  "RTDyldChecker: ");
799  }
800  return std::make_pair(0, std::move(ErrMsg));
801  }
802 
803  // If this address is being looked up in "load" mode, return the content
804  // pointer, otherwise return the target address.
805 
806  uint64_t Addr = 0;
807 
808  if (IsInsideLoad) {
809  if (SecInfo->isZeroFill())
810  Addr = 0;
811  else
812  Addr = pointerToJITTargetAddress(SecInfo->getContent().data());
813  } else
814  Addr = SecInfo->getTargetAddress();
815 
816  return std::make_pair(Addr, "");
817 }
818 
819 std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor(
820  StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad,
821  bool IsStubAddr) const {
822 
823  auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName)
824  : GetGOTInfo(StubContainerName, SymbolName);
825 
826  if (!StubInfo) {
827  std::string ErrMsg;
828  {
829  raw_string_ostream ErrMsgStream(ErrMsg);
830  logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream,
831  "RTDyldChecker: ");
832  }
833  return std::make_pair((uint64_t)0, std::move(ErrMsg));
834  }
835 
836  uint64_t Addr = 0;
837 
838  if (IsInsideLoad) {
839  if (StubInfo->isZeroFill())
840  return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry");
841  Addr = pointerToJITTargetAddress(StubInfo->getContent().data());
842  } else
843  Addr = StubInfo->getTargetAddress();
844 
845  return std::make_pair(Addr, "");
846 }
847 
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,
858  ErrStream)) {}
859 
861 
862 bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
863  return Impl->check(CheckExpr);
864 }
865 
867  MemoryBuffer *MemBuf) const {
868  return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf);
869 }
870 
871 std::pair<uint64_t, std::string>
873  bool LocalAddress) {
874  return Impl->getSectionAddr(FileName, SectionName, LocalAddress);
875 }
bool isImm() const
Definition: MCInst.h:58
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
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
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:270
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:803
RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, raw_ostream &ErrStream)
Definition: BitVector.h:937
constexpr char SymbolName[]
Key for Kernel::Metadata::mSymbolName.
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:592
LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:140
std::function< Expected< MemoryRegionInfo >(StringRef GOTContainer, StringRef TargetName)> GetGOTInfoFunction
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
std::function< bool(StringRef Symbol)> IsSymbolValidFunction
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:831
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Definition: JITSymbol.h:51
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:249
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:299
unsigned getNumOperands() const
Definition: MCInst.h:181
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:519
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::enable_if< std::numeric_limits< T >::is_signed, bool >::type getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:492
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:179
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:41
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:60
This is an instance of a target assembly language printer that converts an MCInst to valid target ass...
Definition: MCInstPrinter.h:39
const unsigned char * bytes_begin() const
Definition: StringRef.h:119
static const size_t npos
Definition: StringRef.h:50
uint32_t Size
Definition: Profile.cpp:46
const char * getBufferStart() const
Definition: MemoryBuffer.h:59
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:503
LLVM Value Representation.
Definition: Value.h:73
raw_ostream & nulls()
This returns a reference to a raw_ostream which simply discards output.
std::underlying_type< E >::type 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
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:45
LLVM_NODISCARD StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
Definition: StringRef.h:817
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
#define LLVM_DEBUG(X)
Definition: Debug.h:122
virtual DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef< uint8_t > Bytes, uint64_t Address, raw_ostream &VStream, raw_ostream &CStream) const =0
Returns the disassembly of a single instruction.
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:34