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 
17 #include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
18 
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include "llvm/DebugInfo/DIContext.h"
23 #include "llvm/DebugInfo/Symbolize/Markup.h"
24 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
25 #include "llvm/Debuginfod/Debuginfod.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"
30 #include "llvm/Support/FormatVariadic.h"
31 #include "llvm/Support/WithColor.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <optional>
34 
35 using namespace llvm;
36 using namespace llvm::symbolize;
37 
38 MarkupFilter::MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
39                            std::optional<bool> ColorsEnabled)
40     : OS(OS), Symbolizer(Symbolizer),
41       ColorsEnabled(
42           ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {}
43 
44 void MarkupFilter::filter(StringRef Line) {
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 
67 void MarkupFilter::finish() {
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)) {
103     WithColor::error(errs())
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     printRawElement(Node);
137     OS << lineEnding();
138 
139     Modules.clear();
140     MMaps.clear();
141   }
142   return true;
143 }
144 
145 bool MarkupFilter::tryModule(const MarkupNode &Node,
146                              const SmallVector<MarkupNode> &DeferredNodes) {
147   if (Node.Tag != "module")
148     return false;
149   std::optional<Module> ParsedModule = parseModule(Node);
150   if (!ParsedModule)
151     return true;
152 
153   auto Res = Modules.try_emplace(
154       ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule)));
155   if (!Res.second) {
156     WithColor::error(errs()) << "duplicate module ID\n";
157     reportLocation(Node.Fields[0].begin());
158     return true;
159   }
160   Module &Module = *Res.first->second;
161 
162   endAnyModuleInfoLine();
163   for (const MarkupNode &Node : DeferredNodes)
164     filterNode(Node);
165   beginModuleInfoLine(&Module);
166   OS << "; BuildID=";
167   printValue(toHex(Module.BuildID, /*LowerCase=*/true));
168   return true;
169 }
170 
171 void MarkupFilter::beginModuleInfoLine(const Module *M) {
172   highlight();
173   OS << "[[[ELF module";
174   printValue(formatv(" #{0:x} ", M->ID));
175   OS << '"';
176   printValue(M->Name);
177   OS << '"';
178   MIL = ModuleInfoLine{M};
179 }
180 
181 void MarkupFilter::endAnyModuleInfoLine() {
182   if (!MIL)
183     return;
184   llvm::stable_sort(MIL->MMaps, [](const MMap *A, const MMap *B) {
185     return A->Addr < B->Addr;
186   });
187   for (const MMap *M : MIL->MMaps) {
188     OS << (M == MIL->MMaps.front() ? ' ' : ',');
189     OS << '[';
190     printValue(formatv("{0:x}", M->Addr));
191     OS << '-';
192     printValue(formatv("{0:x}", M->Addr + M->Size - 1));
193     OS << "](";
194     printValue(M->Mode);
195     OS << ')';
196   }
197   OS << "]]]" << lineEnding();
198   restoreColor();
199   MIL.reset();
200 }
201 
202 // Handle a node that is known not to be a contextual element.
203 void MarkupFilter::filterNode(const MarkupNode &Node) {
204   if (!checkTag(Node))
205     return;
206   if (tryPresentation(Node))
207     return;
208   if (trySGR(Node))
209     return;
210 
211   OS << Node.Text;
212 }
213 
214 bool MarkupFilter::tryPresentation(const MarkupNode &Node) {
215   if (trySymbol(Node))
216     return true;
217   if (tryPC(Node))
218     return true;
219   if (tryBackTrace(Node))
220     return true;
221   return tryData(Node);
222 }
223 
224 bool MarkupFilter::trySymbol(const MarkupNode &Node) {
225   if (Node.Tag != "symbol")
226     return false;
227   if (!checkNumFields(Node, 1))
228     return true;
229 
230   highlight();
231   OS << llvm::demangle(Node.Fields.front().str());
232   restoreColor();
233   return true;
234 }
235 
236 bool MarkupFilter::tryPC(const MarkupNode &Node) {
237   if (Node.Tag != "pc")
238     return false;
239   if (!checkNumFieldsAtLeast(Node, 1))
240     return true;
241   warnNumFieldsAtMost(Node, 2);
242 
243   std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
244   if (!Addr)
245     return true;
246 
247   // PC addresses that aren't part of a backtrace are assumed to be precise code
248   // locations.
249   PCType Type = PCType::PreciseCode;
250   if (Node.Fields.size() == 2) {
251     std::optional<PCType> ParsedType = parsePCType(Node.Fields[1]);
252     if (!ParsedType)
253       return true;
254     Type = *ParsedType;
255   }
256   *Addr = adjustAddr(*Addr, Type);
257 
258   const MMap *MMap = getContainingMMap(*Addr);
259   if (!MMap) {
260     WithColor::error() << "no mmap covers address\n";
261     reportLocation(Node.Fields[0].begin());
262     printRawElement(Node);
263     return true;
264   }
265 
266   Expected<DILineInfo> LI = Symbolizer.symbolizeCode(
267       MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
268   if (!LI) {
269     WithColor::defaultErrorHandler(LI.takeError());
270     printRawElement(Node);
271     return true;
272   }
273   if (!*LI) {
274     printRawElement(Node);
275     return true;
276   }
277 
278   highlight();
279   printValue(LI->FunctionName);
280   OS << '[';
281   printValue(LI->FileName);
282   OS << ':';
283   printValue(Twine(LI->Line));
284   OS << ']';
285   restoreColor();
286   return true;
287 }
288 
289 bool MarkupFilter::tryBackTrace(const MarkupNode &Node) {
290   if (Node.Tag != "bt")
291     return false;
292   if (!checkNumFieldsAtLeast(Node, 2))
293     return true;
294   warnNumFieldsAtMost(Node, 3);
295 
296   std::optional<uint64_t> FrameNumber = parseFrameNumber(Node.Fields[0]);
297   if (!FrameNumber)
298     return true;
299 
300   std::optional<uint64_t> Addr = parseAddr(Node.Fields[1]);
301   if (!Addr)
302     return true;
303 
304   // Backtrace addresses are assumed to be return addresses by default.
305   PCType Type = PCType::ReturnAddress;
306   if (Node.Fields.size() == 3) {
307     std::optional<PCType> ParsedType = parsePCType(Node.Fields[2]);
308     if (!ParsedType)
309       return true;
310     Type = *ParsedType;
311   }
312   *Addr = adjustAddr(*Addr, Type);
313 
314   const MMap *MMap = getContainingMMap(*Addr);
315   if (!MMap) {
316     WithColor::error() << "no mmap covers address\n";
317     reportLocation(Node.Fields[0].begin());
318     printRawElement(Node);
319     return true;
320   }
321   uint64_t MRA = MMap->getModuleRelativeAddr(*Addr);
322 
323   Expected<DIInliningInfo> II =
324       Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA});
325   if (!II) {
326     WithColor::defaultErrorHandler(II.takeError());
327     printRawElement(Node);
328     return true;
329   }
330 
331   highlight();
332   for (unsigned I = 0, E = II->getNumberOfFrames(); I != E; ++I) {
333     auto Header = formatv("{0, +6}", formatv("#{0}", FrameNumber)).sstr<16>();
334     // Don't highlight the # sign as a value.
335     size_t NumberIdx = Header.find("#") + 1;
336     OS << Header.substr(0, NumberIdx);
337     printValue(Header.substr(NumberIdx));
338     if (I == E - 1) {
339       OS << "   ";
340     } else {
341       OS << '.';
342       printValue(formatv("{0, -2}", I + 1));
343     }
344     printValue(formatv(" {0:x16} ", *Addr));
345 
346     DILineInfo LI = II->getFrame(I);
347     if (LI) {
348       printValue(LI.FunctionName);
349       OS << ' ';
350       printValue(LI.FileName);
351       OS << ':';
352       printValue(Twine(LI.Line));
353       OS << ':';
354       printValue(Twine(LI.Column));
355       OS << ' ';
356     }
357     OS << '(';
358     printValue(MMap->Mod->Name);
359     OS << "+";
360     printValue(formatv("{0:x}", MRA));
361     OS << ')';
362     if (I != E - 1)
363       OS << lineEnding();
364   }
365   restoreColor();
366   return true;
367 }
368 
369 bool MarkupFilter::tryData(const MarkupNode &Node) {
370   if (Node.Tag != "data")
371     return false;
372   if (!checkNumFields(Node, 1))
373     return true;
374   std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
375   if (!Addr)
376     return true;
377 
378   const MMap *MMap = getContainingMMap(*Addr);
379   if (!MMap) {
380     WithColor::error() << "no mmap covers address\n";
381     reportLocation(Node.Fields[0].begin());
382     printRawElement(Node);
383     return true;
384   }
385 
386   Expected<DIGlobal> Symbol = Symbolizer.symbolizeData(
387       MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
388   if (!Symbol) {
389     WithColor::defaultErrorHandler(Symbol.takeError());
390     printRawElement(Node);
391     return true;
392   }
393 
394   highlight();
395   OS << Symbol->Name;
396   restoreColor();
397   return true;
398 }
399 
400 bool MarkupFilter::trySGR(const MarkupNode &Node) {
401   if (Node.Text == "\033[0m") {
402     resetColor();
403     return true;
404   }
405   if (Node.Text == "\033[1m") {
406     Bold = true;
407     if (ColorsEnabled)
408       OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
409     return true;
410   }
411   auto SGRColor = StringSwitch<std::optional<raw_ostream::Colors>>(Node.Text)
412                       .Case("\033[30m", raw_ostream::Colors::BLACK)
413                       .Case("\033[31m", raw_ostream::Colors::RED)
414                       .Case("\033[32m", raw_ostream::Colors::GREEN)
415                       .Case("\033[33m", raw_ostream::Colors::YELLOW)
416                       .Case("\033[34m", raw_ostream::Colors::BLUE)
417                       .Case("\033[35m", raw_ostream::Colors::MAGENTA)
418                       .Case("\033[36m", raw_ostream::Colors::CYAN)
419                       .Case("\033[37m", raw_ostream::Colors::WHITE)
420                       .Default(std::nullopt);
421   if (SGRColor) {
422     Color = *SGRColor;
423     if (ColorsEnabled)
424       OS.changeColor(*Color);
425     return true;
426   }
427 
428   return false;
429 }
430 
431 // Begin highlighting text by picking a different color than the current color
432 // state.
433 void MarkupFilter::highlight() {
434   if (!ColorsEnabled)
435     return;
436   OS.changeColor(Color == raw_ostream::Colors::BLUE ? raw_ostream::Colors::CYAN
437                                                     : raw_ostream::Colors::BLUE,
438                  Bold);
439 }
440 
441 // Begin highlighting a field within a highlighted markup string.
442 void MarkupFilter::highlightValue() {
443   if (!ColorsEnabled)
444     return;
445   OS.changeColor(raw_ostream::Colors::GREEN, Bold);
446 }
447 
448 // Set the output stream's color to the current color and bold state of the SGR
449 // abstract machine.
450 void MarkupFilter::restoreColor() {
451   if (!ColorsEnabled)
452     return;
453   if (Color) {
454     OS.changeColor(*Color, Bold);
455   } else {
456     OS.resetColor();
457     if (Bold)
458       OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
459   }
460 }
461 
462 // Set the SGR and output stream's color and bold states back to the default.
463 void MarkupFilter::resetColor() {
464   if (!Color && !Bold)
465     return;
466   Color.reset();
467   Bold = false;
468   if (ColorsEnabled)
469     OS.resetColor();
470 }
471 
472 void MarkupFilter::printRawElement(const MarkupNode &Element) {
473   highlight();
474   OS << "[[[";
475   printValue(Element.Tag);
476   for (StringRef Field : Element.Fields) {
477     OS << ':';
478     printValue(Field);
479   }
480   OS << "]]]";
481   restoreColor();
482 }
483 
484 void MarkupFilter::printValue(Twine Value) {
485   highlightValue();
486   OS << Value;
487   highlight();
488 }
489 
490 // This macro helps reduce the amount of indirection done through Optional
491 // below, since the usual case upon returning a std::nullopt Optional is to
492 // return std::nullopt.
493 #define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR)                                \
494   auto NAME##Opt = (EXPR);                                                     \
495   if (!NAME##Opt)                                                              \
496     return std::nullopt;                                                       \
497   TYPE NAME = std::move(*NAME##Opt)
498 
499 std::optional<MarkupFilter::Module>
500 MarkupFilter::parseModule(const MarkupNode &Element) const {
501   if (!checkNumFieldsAtLeast(Element, 3))
502     return std::nullopt;
503   ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[0]));
504   StringRef Name = Element.Fields[1];
505   StringRef Type = Element.Fields[2];
506   if (Type != "elf") {
507     WithColor::error() << "unknown module type\n";
508     reportLocation(Type.begin());
509     return std::nullopt;
510   }
511   if (!checkNumFields(Element, 4))
512     return std::nullopt;
513   SmallVector<uint8_t> BuildID = parseBuildID(Element.Fields[3]);
514   if (BuildID.empty())
515     return std::nullopt;
516   return Module{ID, Name.str(), std::move(BuildID)};
517 }
518 
519 std::optional<MarkupFilter::MMap>
520 MarkupFilter::parseMMap(const MarkupNode &Element) const {
521   if (!checkNumFieldsAtLeast(Element, 3))
522     return std::nullopt;
523   ASSIGN_OR_RETURN_NONE(uint64_t, Addr, parseAddr(Element.Fields[0]));
524   ASSIGN_OR_RETURN_NONE(uint64_t, Size, parseSize(Element.Fields[1]));
525   StringRef Type = Element.Fields[2];
526   if (Type != "load") {
527     WithColor::error() << "unknown mmap type\n";
528     reportLocation(Type.begin());
529     return std::nullopt;
530   }
531   if (!checkNumFields(Element, 6))
532     return std::nullopt;
533   ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[3]));
534   ASSIGN_OR_RETURN_NONE(std::string, Mode, parseMode(Element.Fields[4]));
535   auto It = Modules.find(ID);
536   if (It == Modules.end()) {
537     WithColor::error() << "unknown module ID\n";
538     reportLocation(Element.Fields[3].begin());
539     return std::nullopt;
540   }
541   ASSIGN_OR_RETURN_NONE(uint64_t, ModuleRelativeAddr,
542                         parseAddr(Element.Fields[5]));
543   return MMap{Addr, Size, It->second.get(), std::move(Mode),
544               ModuleRelativeAddr};
545 }
546 
547 // Parse an address (%p in the spec).
548 std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str) const {
549   if (Str.empty()) {
550     reportTypeError(Str, "address");
551     return std::nullopt;
552   }
553   if (all_of(Str, [](char C) { return C == '0'; }))
554     return 0;
555   if (!Str.startswith("0x")) {
556     reportTypeError(Str, "address");
557     return std::nullopt;
558   }
559   uint64_t Addr;
560   if (Str.drop_front(2).getAsInteger(16, Addr)) {
561     reportTypeError(Str, "address");
562     return std::nullopt;
563   }
564   return Addr;
565 }
566 
567 // Parse a module ID (%i in the spec).
568 std::optional<uint64_t> MarkupFilter::parseModuleID(StringRef Str) const {
569   uint64_t ID;
570   if (Str.getAsInteger(0, ID)) {
571     reportTypeError(Str, "module ID");
572     return std::nullopt;
573   }
574   return ID;
575 }
576 
577 // Parse a size (%i in the spec).
578 std::optional<uint64_t> MarkupFilter::parseSize(StringRef Str) const {
579   uint64_t ID;
580   if (Str.getAsInteger(0, ID)) {
581     reportTypeError(Str, "size");
582     return std::nullopt;
583   }
584   return ID;
585 }
586 
587 // Parse a frame number (%i in the spec).
588 std::optional<uint64_t> MarkupFilter::parseFrameNumber(StringRef Str) const {
589   uint64_t ID;
590   if (Str.getAsInteger(10, ID)) {
591     reportTypeError(Str, "frame number");
592     return std::nullopt;
593   }
594   return ID;
595 }
596 
597 // Parse a build ID (%x in the spec).
598 object::BuildID MarkupFilter::parseBuildID(StringRef Str) const {
599   object::BuildID BID = llvm::object::parseBuildID(Str);
600   if (BID.empty())
601     reportTypeError(Str, "build ID");
602   return BID;
603 }
604 
605 // Parses the mode string for an mmap element.
606 std::optional<std::string> MarkupFilter::parseMode(StringRef Str) const {
607   if (Str.empty()) {
608     reportTypeError(Str, "mode");
609     return std::nullopt;
610   }
611 
612   // Pop off each of r/R, w/W, and x/X from the front, in that order.
613   StringRef Remainder = Str;
614   if (!Remainder.empty() && tolower(Remainder.front()) == 'r')
615     Remainder = Remainder.drop_front();
616   if (!Remainder.empty() && tolower(Remainder.front()) == 'w')
617     Remainder = Remainder.drop_front();
618   if (!Remainder.empty() && tolower(Remainder.front()) == 'x')
619     Remainder = Remainder.drop_front();
620 
621   // If anything remains, then the string wasn't a mode.
622   if (!Remainder.empty()) {
623     reportTypeError(Str, "mode");
624     return std::nullopt;
625   }
626 
627   // Normalize the mode.
628   return Str.lower();
629 }
630 
631 std::optional<MarkupFilter::PCType>
632 MarkupFilter::parsePCType(StringRef Str) const {
633   std::optional<MarkupFilter::PCType> Type =
634       StringSwitch<std::optional<MarkupFilter::PCType>>(Str)
635           .Case("ra", MarkupFilter::PCType::ReturnAddress)
636           .Case("pc", MarkupFilter::PCType::PreciseCode)
637           .Default(std::nullopt);
638   if (!Type)
639     reportTypeError(Str, "PC type");
640   return Type;
641 }
642 
643 bool MarkupFilter::checkTag(const MarkupNode &Node) const {
644   if (any_of(Node.Tag, [](char C) { return C < 'a' || C > 'z'; })) {
645     WithColor::error(errs()) << "tags must be all lowercase characters\n";
646     reportLocation(Node.Tag.begin());
647     return false;
648   }
649   return true;
650 }
651 
652 bool MarkupFilter::checkNumFields(const MarkupNode &Element,
653                                   size_t Size) const {
654   if (Element.Fields.size() != Size) {
655     bool Warn = Element.Fields.size() > Size;
656     WithColor(errs(), Warn ? HighlightColor::Warning : HighlightColor::Error)
657         << (Warn ? "warning: " : "error: ") << "expected " << Size
658         << " field(s); found " << Element.Fields.size() << "\n";
659     reportLocation(Element.Tag.end());
660     return Warn;
661   }
662   return true;
663 }
664 
665 bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element,
666                                          size_t Size) const {
667   if (Element.Fields.size() < Size) {
668     WithColor::error(errs())
669         << "expected at least " << Size << " field(s); found "
670         << Element.Fields.size() << "\n";
671     reportLocation(Element.Tag.end());
672     return false;
673   }
674   return true;
675 }
676 
677 void MarkupFilter::warnNumFieldsAtMost(const MarkupNode &Element,
678                                        size_t Size) const {
679   if (Element.Fields.size() <= Size)
680     return;
681   WithColor::warning(errs())
682       << "expected at most " << Size << " field(s); found "
683       << Element.Fields.size() << "\n";
684   reportLocation(Element.Tag.end());
685 }
686 
687 void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const {
688   WithColor::error(errs()) << "expected " << TypeName << "; found '" << Str
689                            << "'\n";
690   reportLocation(Str.begin());
691 }
692 
693 // Prints two lines that point out the given location in the current Line using
694 // a caret. The iterator must be within the bounds of the most recent line
695 // passed to beginLine().
696 void MarkupFilter::reportLocation(StringRef::iterator Loc) const {
697   errs() << Line;
698   WithColor(errs().indent(Loc - Line.begin()), HighlightColor::String) << '^';
699   errs() << '\n';
700 }
701 
702 // Checks for an existing mmap that overlaps the given one and returns a
703 // pointer to one of them.
704 const MarkupFilter::MMap *
705 MarkupFilter::getOverlappingMMap(const MMap &Map) const {
706   // If the given map contains the start of another mmap, they overlap.
707   auto I = MMaps.upper_bound(Map.Addr);
708   if (I != MMaps.end() && Map.contains(I->second.Addr))
709     return &I->second;
710 
711   // If no element starts inside the given mmap, the only possible overlap would
712   // be if the preceding mmap contains the start point of the given mmap.
713   if (I != MMaps.begin()) {
714     --I;
715     if (I->second.contains(Map.Addr))
716       return &I->second;
717   }
718   return nullptr;
719 }
720 
721 // Returns the MMap that contains the given address or nullptr if none.
722 const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const {
723   // Find the first mmap starting >= Addr.
724   auto I = MMaps.lower_bound(Addr);
725   if (I != MMaps.end() && I->second.contains(Addr))
726     return &I->second;
727 
728   // The previous mmap is the last one starting < Addr.
729   if (I == MMaps.begin())
730     return nullptr;
731   --I;
732   return I->second.contains(Addr) ? &I->second : nullptr;
733 }
734 
735 uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const {
736   // Decrementing return addresses by one moves them into the call instruction.
737   // The address doesn't have to be the start of the call instruction, just some
738   // byte on the inside. Subtracting one avoids needing detailed instruction
739   // length information here.
740   return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr;
741 }
742 
743 StringRef MarkupFilter::lineEnding() const {
744   return Line.endswith("\r\n") ? "\r\n" : "\n";
745 }
746 
747 bool MarkupFilter::MMap::contains(uint64_t Addr) const {
748   return this->Addr <= Addr && Addr < this->Addr + Size;
749 }
750 
751 // Returns the module-relative address for a given virtual address.
752 uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr) const {
753   return Addr - this->Addr + ModuleRelativeAddr;
754 }
755