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     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) {
271     WithColor::defaultErrorHandler(LI.takeError());
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 
326   Expected<DIInliningInfo> II =
327       Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA});
328   if (!II) {
329     WithColor::defaultErrorHandler(II.takeError());
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 
389   Expected<DIGlobal> Symbol = Symbolizer.symbolizeData(
390       MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
391   if (!Symbol) {
392     WithColor::defaultErrorHandler(Symbol.takeError());
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
440                                                     : raw_ostream::Colors::BLUE,
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;
516   ASSIGN_OR_RETURN_NONE(SmallVector<uint8_t>, BuildID,
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 =
641       StringSwitch<std::optional<MarkupFilter::PCType>>(Str)
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) {
673     WithColor::error(errs())
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) {
685     WithColor::error(errs())
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 
754 bool MarkupFilter::MMap::contains(uint64_t Addr) const {
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 }
762