LLVM  16.0.0git
MarkupFilter.cpp
Go to the documentation of this file.
1 //===-- lib/DebugInfo/Symbolize/MarkupFilter.cpp -------------------------===//
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 ///
9 /// \file
10 /// This file defines the implementation of a filter that replaces symbolizer
11 /// markup with human-readable expressions.
12 ///
13 /// See https://llvm.org/docs/SymbolizerMarkupFormat.html
14 ///
15 //===----------------------------------------------------------------------===//
16 
18 
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringSwitch.h"
26 #include "llvm/Demangle/Demangle.h"
27 #include "llvm/Object/ObjectFile.h"
28 #include "llvm/Support/Error.h"
29 #include "llvm/Support/Format.h"
31 #include "llvm/Support/WithColor.h"
33 #include <optional>
34 
35 using namespace llvm;
36 using namespace llvm::symbolize;
37 
39  std::optional<bool> ColorsEnabled)
40  : OS(OS), Symbolizer(Symbolizer),
41  ColorsEnabled(
42  ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {}
43 
45  this->Line = Line;
46  resetColor();
47 
48  Parser.parseLine(Line);
49  SmallVector<MarkupNode> DeferredNodes;
50  // See if the line is a contextual (i.e. contains a contextual element).
51  // In this case, anything after the contextual element is elided, or the whole
52  // line may be elided.
53  while (std::optional<MarkupNode> Node = Parser.nextNode()) {
54  // If this was a contextual line, then summarily stop processing.
55  if (tryContextualElement(*Node, DeferredNodes))
56  return;
57  // This node may yet be part of an elided contextual line.
58  DeferredNodes.push_back(*Node);
59  }
60 
61  // This was not a contextual line, so nothing in it should be elided.
62  endAnyModuleInfoLine();
63  for (const MarkupNode &Node : DeferredNodes)
64  filterNode(Node);
65 }
66 
68  Parser.flush();
69  while (std::optional<MarkupNode> Node = Parser.nextNode())
70  filterNode(*Node);
71  endAnyModuleInfoLine();
72  resetColor();
73  Modules.clear();
74  MMaps.clear();
75 }
76 
77 // See if the given node is a contextual element and handle it if so. This may
78 // either output or defer the element; in the former case, it will first emit
79 // any DeferredNodes.
80 //
81 // Returns true if the given element was a contextual element. In this case,
82 // DeferredNodes should be considered handled and should not be emitted. The
83 // rest of the containing line must also be ignored in case the element was
84 // deferred to a following line.
85 bool MarkupFilter::tryContextualElement(
86  const MarkupNode &Node, const SmallVector<MarkupNode> &DeferredNodes) {
87  if (tryMMap(Node, DeferredNodes))
88  return true;
89  if (tryReset(Node, DeferredNodes))
90  return true;
91  return tryModule(Node, DeferredNodes);
92 }
93 
94 bool MarkupFilter::tryMMap(const MarkupNode &Node,
95  const SmallVector<MarkupNode> &DeferredNodes) {
96  if (Node.Tag != "mmap")
97  return false;
98  std::optional<MMap> ParsedMMap = parseMMap(Node);
99  if (!ParsedMMap)
100  return true;
101 
102  if (const MMap *M = getOverlappingMMap(*ParsedMMap)) {
104  << formatv("overlapping mmap: #{0:x} [{1:x}-{2:x}]\n", M->Mod->ID,
105  M->Addr, M->Addr + M->Size - 1);
106  reportLocation(Node.Fields[0].begin());
107  return true;
108  }
109 
110  auto Res = MMaps.emplace(ParsedMMap->Addr, std::move(*ParsedMMap));
111  assert(Res.second && "Overlap check should ensure emplace succeeds.");
112  MMap &MMap = Res.first->second;
113 
114  if (!MIL || MIL->Mod != MMap.Mod) {
115  endAnyModuleInfoLine();
116  for (const MarkupNode &Node : DeferredNodes)
117  filterNode(Node);
118  beginModuleInfoLine(MMap.Mod);
119  OS << "; adds";
120  }
121  MIL->MMaps.push_back(&MMap);
122  return true;
123 }
124 
125 bool MarkupFilter::tryReset(const MarkupNode &Node,
126  const SmallVector<MarkupNode> &DeferredNodes) {
127  if (Node.Tag != "reset")
128  return false;
129  if (!checkNumFields(Node, 0))
130  return true;
131 
132  if (!Modules.empty() || !MMaps.empty()) {
133  endAnyModuleInfoLine();
134  for (const MarkupNode &Node : DeferredNodes)
135  filterNode(Node);
136  highlight();
137  OS << "[[[reset]]]" << lineEnding();
138  restoreColor();
139 
140  Modules.clear();
141  MMaps.clear();
142  }
143  return true;
144 }
145 
146 bool MarkupFilter::tryModule(const MarkupNode &Node,
147  const SmallVector<MarkupNode> &DeferredNodes) {
148  if (Node.Tag != "module")
149  return false;
150  std::optional<Module> ParsedModule = parseModule(Node);
151  if (!ParsedModule)
152  return true;
153 
154  auto Res = Modules.try_emplace(
155  ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule)));
156  if (!Res.second) {
157  WithColor::error(errs()) << "duplicate module ID\n";
158  reportLocation(Node.Fields[0].begin());
159  return true;
160  }
161  Module &Module = *Res.first->second;
162 
163  endAnyModuleInfoLine();
164  for (const MarkupNode &Node : DeferredNodes)
165  filterNode(Node);
166  beginModuleInfoLine(&Module);
167  OS << "; BuildID=";
168  printValue(toHex(Module.BuildID, /*LowerCase=*/true));
169  return true;
170 }
171 
172 void MarkupFilter::beginModuleInfoLine(const Module *M) {
173  highlight();
174  OS << "[[[ELF module";
175  printValue(formatv(" #{0:x} ", M->ID));
176  OS << '"';
177  printValue(M->Name);
178  OS << '"';
179  MIL = ModuleInfoLine{M};
180 }
181 
182 void MarkupFilter::endAnyModuleInfoLine() {
183  if (!MIL)
184  return;
185  llvm::stable_sort(MIL->MMaps, [](const MMap *A, const MMap *B) {
186  return A->Addr < B->Addr;
187  });
188  for (const MMap *M : MIL->MMaps) {
189  OS << (M == MIL->MMaps.front() ? ' ' : ',');
190  OS << '[';
191  printValue(formatv("{0:x}", M->Addr));
192  OS << '-';
193  printValue(formatv("{0:x}", M->Addr + M->Size - 1));
194  OS << "](";
195  printValue(M->Mode);
196  OS << ')';
197  }
198  OS << "]]]" << lineEnding();
199  restoreColor();
200  MIL.reset();
201 }
202 
203 // Handle a node that is known not to be a contextual element.
204 void MarkupFilter::filterNode(const MarkupNode &Node) {
205  if (!checkTag(Node))
206  return;
207  if (tryPresentation(Node))
208  return;
209  if (trySGR(Node))
210  return;
211 
212  OS << Node.Text;
213 }
214 
215 bool MarkupFilter::tryPresentation(const MarkupNode &Node) {
216  if (trySymbol(Node))
217  return true;
218  if (tryPC(Node))
219  return true;
220  if (tryBackTrace(Node))
221  return true;
222  return tryData(Node);
223 }
224 
225 bool MarkupFilter::trySymbol(const MarkupNode &Node) {
226  if (Node.Tag != "symbol")
227  return false;
228  if (!checkNumFields(Node, 1))
229  return true;
230 
231  highlight();
232  OS << llvm::demangle(Node.Fields.front().str());
233  restoreColor();
234  return true;
235 }
236 
237 bool MarkupFilter::tryPC(const MarkupNode &Node) {
238  if (Node.Tag != "pc")
239  return false;
240  if (!checkNumFieldsAtLeast(Node, 1))
241  return true;
242  if (!checkNumFieldsAtMost(Node, 2))
243  return true;
244 
245  std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
246  if (!Addr)
247  return true;
248 
249  // PC addresses that aren't part of a backtrace are assumed to be precise code
250  // locations.
251  PCType Type = PCType::PreciseCode;
252  if (Node.Fields.size() == 2) {
253  std::optional<PCType> ParsedType = parsePCType(Node.Fields[1]);
254  if (!ParsedType)
255  return true;
256  Type = *ParsedType;
257  }
258  *Addr = adjustAddr(*Addr, Type);
259 
260  const MMap *MMap = getContainingMMap(*Addr);
261  if (!MMap) {
262  WithColor::error() << "no mmap covers address\n";
263  reportLocation(Node.Fields[0].begin());
264  printRawElement(Node);
265  return true;
266  }
267 
268  Expected<DILineInfo> LI = Symbolizer.symbolizeCode(
269  MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
270  if (!LI) {
272  printRawElement(Node);
273  return true;
274  }
275  if (!*LI) {
276  printRawElement(Node);
277  return true;
278  }
279 
280  highlight();
281  printValue(LI->FunctionName);
282  OS << '[';
283  printValue(LI->FileName);
284  OS << ':';
285  printValue(Twine(LI->Line));
286  OS << ']';
287  restoreColor();
288  return true;
289 }
290 
291 bool MarkupFilter::tryBackTrace(const MarkupNode &Node) {
292  if (Node.Tag != "bt")
293  return false;
294  if (!checkNumFieldsAtLeast(Node, 2))
295  return true;
296  if (!checkNumFieldsAtMost(Node, 3))
297  return true;
298 
299  std::optional<uint64_t> FrameNumber = parseFrameNumber(Node.Fields[0]);
300  if (!FrameNumber)
301  return true;
302 
303  std::optional<uint64_t> Addr = parseAddr(Node.Fields[1]);
304  if (!Addr)
305  return true;
306 
307  // Backtrace addresses are assumed to be return addresses by default.
308  PCType Type = PCType::ReturnAddress;
309  if (Node.Fields.size() == 3) {
310  std::optional<PCType> ParsedType = parsePCType(Node.Fields[2]);
311  if (!ParsedType)
312  return true;
313  Type = *ParsedType;
314  }
315  *Addr = adjustAddr(*Addr, Type);
316 
317  const MMap *MMap = getContainingMMap(*Addr);
318  if (!MMap) {
319  WithColor::error() << "no mmap covers address\n";
320  reportLocation(Node.Fields[0].begin());
321  printRawElement(Node);
322  return true;
323  }
324  uint64_t MRA = MMap->getModuleRelativeAddr(*Addr);
325 
327  Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA});
328  if (!II) {
330  printRawElement(Node);
331  return true;
332  }
333 
334  highlight();
335  for (unsigned I = 0, E = II->getNumberOfFrames(); I != E; ++I) {
336  auto Header = formatv("{0, +6}", formatv("#{0}", FrameNumber)).sstr<16>();
337  // Don't highlight the # sign as a value.
338  size_t NumberIdx = Header.find("#") + 1;
339  OS << Header.substr(0, NumberIdx);
340  printValue(Header.substr(NumberIdx));
341  if (I == E - 1) {
342  OS << " ";
343  } else {
344  OS << '.';
345  printValue(formatv("{0, -2}", I + 1));
346  }
347  printValue(formatv(" {0:x16} ", *Addr));
348 
349  DILineInfo LI = II->getFrame(I);
350  if (LI) {
351  printValue(LI.FunctionName);
352  OS << ' ';
353  printValue(LI.FileName);
354  OS << ':';
355  printValue(Twine(LI.Line));
356  OS << ':';
357  printValue(Twine(LI.Column));
358  OS << ' ';
359  }
360  OS << '(';
361  printValue(MMap->Mod->Name);
362  OS << "+";
363  printValue(formatv("{0:x}", MRA));
364  OS << ')';
365  if (I != E - 1)
366  OS << lineEnding();
367  }
368  restoreColor();
369  return true;
370 }
371 
372 bool MarkupFilter::tryData(const MarkupNode &Node) {
373  if (Node.Tag != "data")
374  return false;
375  if (!checkNumFields(Node, 1))
376  return true;
377  std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
378  if (!Addr)
379  return true;
380 
381  const MMap *MMap = getContainingMMap(*Addr);
382  if (!MMap) {
383  WithColor::error() << "no mmap covers address\n";
384  reportLocation(Node.Fields[0].begin());
385  printRawElement(Node);
386  return true;
387  }
388 
390  MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
391  if (!Symbol) {
393  printRawElement(Node);
394  return true;
395  }
396 
397  highlight();
398  OS << Symbol->Name;
399  restoreColor();
400  return true;
401 }
402 
403 bool MarkupFilter::trySGR(const MarkupNode &Node) {
404  if (Node.Text == "\033[0m") {
405  resetColor();
406  return true;
407  }
408  if (Node.Text == "\033[1m") {
409  Bold = true;
410  if (ColorsEnabled)
411  OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
412  return true;
413  }
414  auto SGRColor = StringSwitch<std::optional<raw_ostream::Colors>>(Node.Text)
415  .Case("\033[30m", raw_ostream::Colors::BLACK)
416  .Case("\033[31m", raw_ostream::Colors::RED)
417  .Case("\033[32m", raw_ostream::Colors::GREEN)
418  .Case("\033[33m", raw_ostream::Colors::YELLOW)
419  .Case("\033[34m", raw_ostream::Colors::BLUE)
420  .Case("\033[35m", raw_ostream::Colors::MAGENTA)
421  .Case("\033[36m", raw_ostream::Colors::CYAN)
422  .Case("\033[37m", raw_ostream::Colors::WHITE)
423  .Default(std::nullopt);
424  if (SGRColor) {
425  Color = *SGRColor;
426  if (ColorsEnabled)
427  OS.changeColor(*Color);
428  return true;
429  }
430 
431  return false;
432 }
433 
434 // Begin highlighting text by picking a different color than the current color
435 // state.
436 void MarkupFilter::highlight() {
437  if (!ColorsEnabled)
438  return;
439  OS.changeColor(Color == raw_ostream::Colors::BLUE ? raw_ostream::Colors::CYAN
441  Bold);
442 }
443 
444 // Begin highlighting a field within a highlighted markup string.
445 void MarkupFilter::highlightValue() {
446  if (!ColorsEnabled)
447  return;
448  OS.changeColor(raw_ostream::Colors::GREEN, Bold);
449 }
450 
451 // Set the output stream's color to the current color and bold state of the SGR
452 // abstract machine.
453 void MarkupFilter::restoreColor() {
454  if (!ColorsEnabled)
455  return;
456  if (Color) {
457  OS.changeColor(*Color, Bold);
458  } else {
459  OS.resetColor();
460  if (Bold)
461  OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
462  }
463 }
464 
465 // Set the SGR and output stream's color and bold states back to the default.
466 void MarkupFilter::resetColor() {
467  if (!Color && !Bold)
468  return;
469  Color.reset();
470  Bold = false;
471  if (ColorsEnabled)
472  OS.resetColor();
473 }
474 
475 void MarkupFilter::printRawElement(const MarkupNode &Element) {
476  highlight();
477  OS << "[[[";
478  printValue(Element.Tag);
479  for (StringRef Field : Element.Fields) {
480  OS << ':';
481  printValue(Field);
482  }
483  OS << "]]]";
484  restoreColor();
485 }
486 
487 void MarkupFilter::printValue(Twine Value) {
488  highlightValue();
489  OS << Value;
490  highlight();
491 }
492 
493 // This macro helps reduce the amount of indirection done through Optional
494 // below, since the usual case upon returning a std::nullopt Optional is to
495 // return std::nullopt.
496 #define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR) \
497  auto NAME##Opt = (EXPR); \
498  if (!NAME##Opt) \
499  return std::nullopt; \
500  TYPE NAME = std::move(*NAME##Opt)
501 
502 std::optional<MarkupFilter::Module>
503 MarkupFilter::parseModule(const MarkupNode &Element) const {
504  if (!checkNumFieldsAtLeast(Element, 3))
505  return std::nullopt;
506  ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[0]));
507  StringRef Name = Element.Fields[1];
508  StringRef Type = Element.Fields[2];
509  if (Type != "elf") {
510  WithColor::error() << "unknown module type\n";
511  reportLocation(Type.begin());
512  return std::nullopt;
513  }
514  if (!checkNumFields(Element, 4))
515  return std::nullopt;
517  parseBuildID(Element.Fields[3]));
518  return Module{ID, Name.str(), std::move(BuildID)};
519 }
520 
521 std::optional<MarkupFilter::MMap>
522 MarkupFilter::parseMMap(const MarkupNode &Element) const {
523  if (!checkNumFieldsAtLeast(Element, 3))
524  return std::nullopt;
525  ASSIGN_OR_RETURN_NONE(uint64_t, Addr, parseAddr(Element.Fields[0]));
526  ASSIGN_OR_RETURN_NONE(uint64_t, Size, parseSize(Element.Fields[1]));
527  StringRef Type = Element.Fields[2];
528  if (Type != "load") {
529  WithColor::error() << "unknown mmap type\n";
530  reportLocation(Type.begin());
531  return std::nullopt;
532  }
533  if (!checkNumFields(Element, 6))
534  return std::nullopt;
535  ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[3]));
536  ASSIGN_OR_RETURN_NONE(std::string, Mode, parseMode(Element.Fields[4]));
537  auto It = Modules.find(ID);
538  if (It == Modules.end()) {
539  WithColor::error() << "unknown module ID\n";
540  reportLocation(Element.Fields[3].begin());
541  return std::nullopt;
542  }
543  ASSIGN_OR_RETURN_NONE(uint64_t, ModuleRelativeAddr,
544  parseAddr(Element.Fields[5]));
545  return MMap{Addr, Size, It->second.get(), std::move(Mode),
546  ModuleRelativeAddr};
547 }
548 
549 // Parse an address (%p in the spec).
550 std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str) const {
551  if (Str.empty()) {
552  reportTypeError(Str, "address");
553  return std::nullopt;
554  }
555  if (all_of(Str, [](char C) { return C == '0'; }))
556  return 0;
557  if (!Str.startswith("0x")) {
558  reportTypeError(Str, "address");
559  return std::nullopt;
560  }
561  uint64_t Addr;
562  if (Str.drop_front(2).getAsInteger(16, Addr)) {
563  reportTypeError(Str, "address");
564  return std::nullopt;
565  }
566  return Addr;
567 }
568 
569 // Parse a module ID (%i in the spec).
570 std::optional<uint64_t> MarkupFilter::parseModuleID(StringRef Str) const {
571  uint64_t ID;
572  if (Str.getAsInteger(0, ID)) {
573  reportTypeError(Str, "module ID");
574  return std::nullopt;
575  }
576  return ID;
577 }
578 
579 // Parse a size (%i in the spec).
580 std::optional<uint64_t> MarkupFilter::parseSize(StringRef Str) const {
581  uint64_t ID;
582  if (Str.getAsInteger(0, ID)) {
583  reportTypeError(Str, "size");
584  return std::nullopt;
585  }
586  return ID;
587 }
588 
589 // Parse a frame number (%i in the spec).
590 std::optional<uint64_t> MarkupFilter::parseFrameNumber(StringRef Str) const {
591  uint64_t ID;
592  if (Str.getAsInteger(10, ID)) {
593  reportTypeError(Str, "frame number");
594  return std::nullopt;
595  }
596  return ID;
597 }
598 
599 // Parse a build ID (%x in the spec).
600 std::optional<SmallVector<uint8_t>>
601 MarkupFilter::parseBuildID(StringRef Str) const {
602  std::string Bytes;
603  if (Str.empty() || Str.size() % 2 || !tryGetFromHex(Str, Bytes)) {
604  reportTypeError(Str, "build ID");
605  return std::nullopt;
606  }
607  ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
608  Bytes.size());
609  return SmallVector<uint8_t>(BuildID.begin(), BuildID.end());
610 }
611 
612 // Parses the mode string for an mmap element.
613 std::optional<std::string> MarkupFilter::parseMode(StringRef Str) const {
614  if (Str.empty()) {
615  reportTypeError(Str, "mode");
616  return std::nullopt;
617  }
618 
619  // Pop off each of r/R, w/W, and x/X from the front, in that order.
620  StringRef Remainder = Str;
621  if (!Remainder.empty() && tolower(Remainder.front()) == 'r')
622  Remainder = Remainder.drop_front();
623  if (!Remainder.empty() && tolower(Remainder.front()) == 'w')
624  Remainder = Remainder.drop_front();
625  if (!Remainder.empty() && tolower(Remainder.front()) == 'x')
626  Remainder = Remainder.drop_front();
627 
628  // If anything remains, then the string wasn't a mode.
629  if (!Remainder.empty()) {
630  reportTypeError(Str, "mode");
631  return std::nullopt;
632  }
633 
634  // Normalize the mode.
635  return Str.lower();
636 }
637 
638 std::optional<MarkupFilter::PCType>
639 MarkupFilter::parsePCType(StringRef Str) const {
640  std::optional<MarkupFilter::PCType> Type =
642  .Case("ra", MarkupFilter::PCType::ReturnAddress)
643  .Case("pc", MarkupFilter::PCType::PreciseCode)
644  .Default(std::nullopt);
645  if (!Type)
646  reportTypeError(Str, "PC type");
647  return Type;
648 }
649 
650 bool MarkupFilter::checkTag(const MarkupNode &Node) const {
651  if (any_of(Node.Tag, [](char C) { return C < 'a' || C > 'z'; })) {
652  WithColor::error(errs()) << "tags must be all lowercase characters\n";
653  reportLocation(Node.Tag.begin());
654  return false;
655  }
656  return true;
657 }
658 
659 bool MarkupFilter::checkNumFields(const MarkupNode &Element,
660  size_t Size) const {
661  if (Element.Fields.size() != Size) {
662  WithColor::error(errs()) << "expected " << Size << " field(s); found "
663  << Element.Fields.size() << "\n";
664  reportLocation(Element.Tag.end());
665  return false;
666  }
667  return true;
668 }
669 
670 bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element,
671  size_t Size) const {
672  if (Element.Fields.size() < Size) {
674  << "expected at least " << Size << " field(s); found "
675  << Element.Fields.size() << "\n";
676  reportLocation(Element.Tag.end());
677  return false;
678  }
679  return true;
680 }
681 
682 bool MarkupFilter::checkNumFieldsAtMost(const MarkupNode &Element,
683  size_t Size) const {
684  if (Element.Fields.size() > Size) {
686  << "expected at most " << Size << " field(s); found "
687  << Element.Fields.size() << "\n";
688  reportLocation(Element.Tag.end());
689  return false;
690  }
691  return true;
692 }
693 
694 void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const {
695  WithColor::error(errs()) << "expected " << TypeName << "; found '" << Str
696  << "'\n";
697  reportLocation(Str.begin());
698 }
699 
700 // Prints two lines that point out the given location in the current Line using
701 // a caret. The iterator must be within the bounds of the most recent line
702 // passed to beginLine().
703 void MarkupFilter::reportLocation(StringRef::iterator Loc) const {
704  errs() << Line;
705  WithColor(errs().indent(Loc - Line.begin()), HighlightColor::String) << '^';
706  errs() << '\n';
707 }
708 
709 // Checks for an existing mmap that overlaps the given one and returns a
710 // pointer to one of them.
711 const MarkupFilter::MMap *
712 MarkupFilter::getOverlappingMMap(const MMap &Map) const {
713  // If the given map contains the start of another mmap, they overlap.
714  auto I = MMaps.upper_bound(Map.Addr);
715  if (I != MMaps.end() && Map.contains(I->second.Addr))
716  return &I->second;
717 
718  // If no element starts inside the given mmap, the only possible overlap would
719  // be if the preceding mmap contains the start point of the given mmap.
720  if (I != MMaps.begin()) {
721  --I;
722  if (I->second.contains(Map.Addr))
723  return &I->second;
724  }
725  return nullptr;
726 }
727 
728 // Returns the MMap that contains the given address or nullptr if none.
729 const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const {
730  // Find the first mmap starting >= Addr.
731  auto I = MMaps.lower_bound(Addr);
732  if (I != MMaps.end() && I->second.contains(Addr))
733  return &I->second;
734 
735  // The previous mmap is the last one starting < Addr.
736  if (I == MMaps.begin())
737  return nullptr;
738  --I;
739  return I->second.contains(Addr) ? &I->second : nullptr;
740 }
741 
742 uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const {
743  // Decrementing return addresses by one moves them into the call instruction.
744  // The address doesn't have to be the start of the call instruction, just some
745  // byte on the inside. Subtracting one avoids needing detailed instruction
746  // length information here.
747  return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr;
748 }
749 
750 StringRef MarkupFilter::lineEnding() const {
751  return Line.endswith("\r\n") ? "\r\n" : "\n";
752 }
753 
755  return this->Addr <= Addr && Addr < this->Addr + Size;
756 }
757 
758 // Returns the module-relative address for a given virtual address.
759 uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr) const {
760  return Addr - this->Addr + ModuleRelativeAddr;
761 }
llvm::Check::Size
@ Size
Definition: FileCheck.h:77
llvm::StringSwitch::Case
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::symbolize
Definition: DIPrinter.h:30
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::StringRef::front
char front() const
front - Get the first character in the string.
Definition: StringRef.h:140
contains
return AArch64::GPR64RegClass contains(Reg)
llvm::symbolize::MarkupFilter::MarkupFilter
MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer, std::optional< bool > ColorsEnabled=std::nullopt)
Definition: MarkupFilter.cpp:38
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
Error.h
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::WithColor::defaultErrorHandler
static void defaultErrorHandler(Error Err)
Implement default handling for Error.
Definition: WithColor.cpp:158
llvm::WithColor
An RAII object that temporarily switches an output stream to a specific color.
Definition: WithColor.h:53
llvm::errs
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:891
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
STLExtras.h
Format.h
llvm::object::BuildID
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
Definition: BuildID.h:25
llvm::raw_ostream::Colors::SAVEDCOLOR
@ SAVEDCOLOR
llvm::WithColor::error
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition: WithColor.cpp:83
llvm::DILineInfo::FunctionName
std::string FunctionName
Definition: DIContext.h:38
llvm::symbolize::LLVMSymbolizer::symbolizeCode
Expected< DILineInfo > symbolizeCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:81
llvm::object::Parser
Definition: COFFModuleDefinition.cpp:139
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:251
llvm::all_of
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1734
llvm::DILineInfo::Column
uint32_t Column
Definition: DIContext.h:42
llvm::symbolize::MarkupNode::Fields
SmallVector< StringRef > Fields
If this represents an element with fields, a list of the field contents.
Definition: Markup.h:42
llvm::raw_ostream::Colors::CYAN
@ CYAN
llvm::msgpack::Type::Map
@ Map
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::raw_ostream::Colors::MAGENTA
@ MAGENTA
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::StringRef::iterator
const char * iterator
Definition: StringRef.h:54
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::raw_ostream::Colors::RED
@ RED
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
ASSIGN_OR_RETURN_NONE
#define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR)
llvm::symbolize::MarkupFilter::finish
void finish()
Records that the input stream has ended and writes any deferred output.
Definition: MarkupFilter.cpp:67
FormatVariadic.h
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::raw_ostream::Colors::BLUE
@ BLUE
llvm::demangle
std::string demangle(const std::string &MangledName)
Attempt to demangle a string using different demangling schemes.
Definition: Demangle.cpp:29
llvm::raw_ostream::Colors::WHITE
@ WHITE
llvm::StringRef::empty
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
Markup.h
llvm::DILineInfo::Line
uint32_t Line
Definition: DIContext.h:41
llvm::DenseMapBase::clear
void clear()
Definition: DenseMap.h:110
Debuginfod.h
uint64_t
llvm::StringRef::end
iterator end() const
Definition: StringRef.h:113
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:79
llvm::symbolize::toHex
static std::string toHex(uint64_t V)
Definition: DIPrinter.cpp:278
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:58
StringExtras.h
llvm::DILineInfo
A format-neutral container for source line information.
Definition: DIContext.h:32
llvm::DenseMapBase::find
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:150
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ObjectFile.h
llvm::symbolize::LLVMSymbolizer::symbolizeData
Expected< DIGlobal > symbolizeData(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:175
Mode
SI Whole Quad Mode
Definition: SIWholeQuadMode.cpp:264
llvm::symbolize::MarkupNode::Tag
StringRef Tag
If this represents an element, the tag. Otherwise, empty.
Definition: Markup.h:38
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
llvm::DenseMapBase::empty
bool empty() const
Definition: DenseMap.h:98
llvm::raw_ostream::Colors::YELLOW
@ YELLOW
llvm::symbolize::LLVMSymbolizer
Definition: Symbolize.h:50
Demangle.h
llvm::ArrayRef< uint8_t >
llvm::HighlightColor::String
@ String
llvm::any_of
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1741
Symbolize.h
llvm::symbolize::LLVMSymbolizer::symbolizeInlinedCode
Expected< DIInliningInfo > symbolizeInlinedCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:130
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm::raw_ostream::Colors::BLACK
@ BLACK
WithColor.h
MarkupFilter.h
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
DIContext.h
llvm::stable_sort
void stable_sort(R &&Range)
Definition: STLExtras.h:1947
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::AMDGPU::HSAMD::Kernel::Arg::Key::TypeName
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
Definition: AMDGPUMetadata.h:175
llvm::DenseMapBase::end
iterator end()
Definition: DenseMap.h:84
llvm::StringRef::endswith
bool endswith(StringRef Suffix) const
Definition: StringRef.h:276
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
StringSwitch.h
llvm::ARMBuildAttrs::Symbol
@ Symbol
Definition: ARMBuildAttributes.h:83
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:596
llvm::DILineInfo::FileName
std::string FileName
Definition: DIContext.h:37
llvm::DenseMapBase::try_emplace
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&... Args)
Definition: DenseMap.h:222
llvm::StringSwitch::Default
R Default(T Value)
Definition: StringSwitch.h:182
llvm::StringSwitch
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
llvm::symbolize::MarkupFilter::filter
void filter(StringRef Line)
Filters a line containing symbolizer markup and writes the human-readable results to the output strea...
Definition: MarkupFilter.cpp:44
llvm::raw_ostream::Colors::GREEN
@ GREEN
llvm::OptimizedStructLayoutField
A field in a structure.
Definition: OptimizedStructLayout.h:45
raw_ostream.h
llvm::StringRef::begin
iterator begin() const
Definition: StringRef.h:111
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::symbolize::MarkupNode
A node of symbolizer markup.
Definition: Markup.h:33
llvm::StringRef::drop_front
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:601