181ad6265SDimitry Andric //===-- lib/DebugInfo/Symbolize/MarkupFilter.cpp -------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file
1081ad6265SDimitry Andric /// This file defines the implementation of a filter that replaces symbolizer
1181ad6265SDimitry Andric /// markup with human-readable expressions.
1281ad6265SDimitry Andric ///
13fcaf7f86SDimitry Andric /// See https://llvm.org/docs/SymbolizerMarkupFormat.html
14fcaf7f86SDimitry Andric ///
1581ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1681ad6265SDimitry Andric 
1781ad6265SDimitry Andric #include "llvm/DebugInfo/Symbolize/MarkupFilter.h"
1881ad6265SDimitry Andric 
1981ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
20fcaf7f86SDimitry Andric #include "llvm/ADT/StringExtras.h"
2181ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
22a4a491e2SDimitry Andric #include "llvm/DebugInfo/DIContext.h"
23fcaf7f86SDimitry Andric #include "llvm/DebugInfo/Symbolize/Markup.h"
24a4a491e2SDimitry Andric #include "llvm/DebugInfo/Symbolize/Symbolize.h"
25fcaf7f86SDimitry Andric #include "llvm/Debuginfod/Debuginfod.h"
2681ad6265SDimitry Andric #include "llvm/Demangle/Demangle.h"
27fcaf7f86SDimitry Andric #include "llvm/Object/ObjectFile.h"
28fcaf7f86SDimitry Andric #include "llvm/Support/Error.h"
29a4a491e2SDimitry Andric #include "llvm/Support/Format.h"
30fcaf7f86SDimitry Andric #include "llvm/Support/FormatVariadic.h"
3181ad6265SDimitry Andric #include "llvm/Support/WithColor.h"
3281ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
33bdd1243dSDimitry Andric #include <optional>
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric using namespace llvm;
3681ad6265SDimitry Andric using namespace llvm::symbolize;
3781ad6265SDimitry Andric 
MarkupFilter(raw_ostream & OS,LLVMSymbolizer & Symbolizer,std::optional<bool> ColorsEnabled)38a4a491e2SDimitry Andric MarkupFilter::MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer,
39bdd1243dSDimitry Andric                            std::optional<bool> ColorsEnabled)
40a4a491e2SDimitry Andric     : OS(OS), Symbolizer(Symbolizer),
41a4a491e2SDimitry Andric       ColorsEnabled(
42a4a491e2SDimitry Andric           ColorsEnabled.value_or(WithColor::defaultAutoDetectFunction()(OS))) {}
4381ad6265SDimitry Andric 
filter(std::string && InputLine)445f757f3fSDimitry Andric void MarkupFilter::filter(std::string &&InputLine) {
455f757f3fSDimitry Andric   Line = std::move(InputLine);
4681ad6265SDimitry Andric   resetColor();
47fcaf7f86SDimitry Andric 
48fcaf7f86SDimitry Andric   Parser.parseLine(Line);
49fcaf7f86SDimitry Andric   SmallVector<MarkupNode> DeferredNodes;
50fcaf7f86SDimitry Andric   // See if the line is a contextual (i.e. contains a contextual element).
51fcaf7f86SDimitry Andric   // In this case, anything after the contextual element is elided, or the whole
52fcaf7f86SDimitry Andric   // line may be elided.
53bdd1243dSDimitry Andric   while (std::optional<MarkupNode> Node = Parser.nextNode()) {
54fcaf7f86SDimitry Andric     // If this was a contextual line, then summarily stop processing.
55fcaf7f86SDimitry Andric     if (tryContextualElement(*Node, DeferredNodes))
56fcaf7f86SDimitry Andric       return;
57fcaf7f86SDimitry Andric     // This node may yet be part of an elided contextual line.
58fcaf7f86SDimitry Andric     DeferredNodes.push_back(*Node);
5981ad6265SDimitry Andric   }
6081ad6265SDimitry Andric 
61fcaf7f86SDimitry Andric   // This was not a contextual line, so nothing in it should be elided.
62fcaf7f86SDimitry Andric   endAnyModuleInfoLine();
63fcaf7f86SDimitry Andric   for (const MarkupNode &Node : DeferredNodes)
64fcaf7f86SDimitry Andric     filterNode(Node);
65fcaf7f86SDimitry Andric }
66fcaf7f86SDimitry Andric 
finish()67fcaf7f86SDimitry Andric void MarkupFilter::finish() {
68fcaf7f86SDimitry Andric   Parser.flush();
69bdd1243dSDimitry Andric   while (std::optional<MarkupNode> Node = Parser.nextNode())
70fcaf7f86SDimitry Andric     filterNode(*Node);
71fcaf7f86SDimitry Andric   endAnyModuleInfoLine();
72fcaf7f86SDimitry Andric   resetColor();
73fcaf7f86SDimitry Andric   Modules.clear();
74fcaf7f86SDimitry Andric   MMaps.clear();
75fcaf7f86SDimitry Andric }
76fcaf7f86SDimitry Andric 
77fcaf7f86SDimitry Andric // See if the given node is a contextual element and handle it if so. This may
78fcaf7f86SDimitry Andric // either output or defer the element; in the former case, it will first emit
79fcaf7f86SDimitry Andric // any DeferredNodes.
80fcaf7f86SDimitry Andric //
81fcaf7f86SDimitry Andric // Returns true if the given element was a contextual element. In this case,
82fcaf7f86SDimitry Andric // DeferredNodes should be considered handled and should not be emitted. The
83fcaf7f86SDimitry Andric // rest of the containing line must also be ignored in case the element was
84fcaf7f86SDimitry Andric // deferred to a following line.
tryContextualElement(const MarkupNode & Node,const SmallVector<MarkupNode> & DeferredNodes)85fcaf7f86SDimitry Andric bool MarkupFilter::tryContextualElement(
86fcaf7f86SDimitry Andric     const MarkupNode &Node, const SmallVector<MarkupNode> &DeferredNodes) {
87fcaf7f86SDimitry Andric   if (tryMMap(Node, DeferredNodes))
88fcaf7f86SDimitry Andric     return true;
89fcaf7f86SDimitry Andric   if (tryReset(Node, DeferredNodes))
90fcaf7f86SDimitry Andric     return true;
91fcaf7f86SDimitry Andric   return tryModule(Node, DeferredNodes);
92fcaf7f86SDimitry Andric }
93fcaf7f86SDimitry Andric 
tryMMap(const MarkupNode & Node,const SmallVector<MarkupNode> & DeferredNodes)94fcaf7f86SDimitry Andric bool MarkupFilter::tryMMap(const MarkupNode &Node,
95fcaf7f86SDimitry Andric                            const SmallVector<MarkupNode> &DeferredNodes) {
96fcaf7f86SDimitry Andric   if (Node.Tag != "mmap")
97fcaf7f86SDimitry Andric     return false;
98bdd1243dSDimitry Andric   std::optional<MMap> ParsedMMap = parseMMap(Node);
99fcaf7f86SDimitry Andric   if (!ParsedMMap)
100fcaf7f86SDimitry Andric     return true;
101fcaf7f86SDimitry Andric 
102a4a491e2SDimitry Andric   if (const MMap *M = getOverlappingMMap(*ParsedMMap)) {
103fcaf7f86SDimitry Andric     WithColor::error(errs())
104a4a491e2SDimitry Andric         << formatv("overlapping mmap: #{0:x} [{1:x}-{2:x}]\n", M->Mod->ID,
105a4a491e2SDimitry Andric                    M->Addr, M->Addr + M->Size - 1);
106fcaf7f86SDimitry Andric     reportLocation(Node.Fields[0].begin());
107fcaf7f86SDimitry Andric     return true;
108fcaf7f86SDimitry Andric   }
109fcaf7f86SDimitry Andric 
110fcaf7f86SDimitry Andric   auto Res = MMaps.emplace(ParsedMMap->Addr, std::move(*ParsedMMap));
111fcaf7f86SDimitry Andric   assert(Res.second && "Overlap check should ensure emplace succeeds.");
112fcaf7f86SDimitry Andric   MMap &MMap = Res.first->second;
113fcaf7f86SDimitry Andric 
114fcaf7f86SDimitry Andric   if (!MIL || MIL->Mod != MMap.Mod) {
115fcaf7f86SDimitry Andric     endAnyModuleInfoLine();
116fcaf7f86SDimitry Andric     for (const MarkupNode &Node : DeferredNodes)
117fcaf7f86SDimitry Andric       filterNode(Node);
118fcaf7f86SDimitry Andric     beginModuleInfoLine(MMap.Mod);
119fcaf7f86SDimitry Andric     OS << "; adds";
120fcaf7f86SDimitry Andric   }
121fcaf7f86SDimitry Andric   MIL->MMaps.push_back(&MMap);
122fcaf7f86SDimitry Andric   return true;
123fcaf7f86SDimitry Andric }
124fcaf7f86SDimitry Andric 
tryReset(const MarkupNode & Node,const SmallVector<MarkupNode> & DeferredNodes)125fcaf7f86SDimitry Andric bool MarkupFilter::tryReset(const MarkupNode &Node,
126fcaf7f86SDimitry Andric                             const SmallVector<MarkupNode> &DeferredNodes) {
127fcaf7f86SDimitry Andric   if (Node.Tag != "reset")
128fcaf7f86SDimitry Andric     return false;
129fcaf7f86SDimitry Andric   if (!checkNumFields(Node, 0))
130fcaf7f86SDimitry Andric     return true;
131fcaf7f86SDimitry Andric 
132fcaf7f86SDimitry Andric   if (!Modules.empty() || !MMaps.empty()) {
133fcaf7f86SDimitry Andric     endAnyModuleInfoLine();
134fcaf7f86SDimitry Andric     for (const MarkupNode &Node : DeferredNodes)
135fcaf7f86SDimitry Andric       filterNode(Node);
13606c3fb27SDimitry Andric     printRawElement(Node);
13706c3fb27SDimitry Andric     OS << lineEnding();
138fcaf7f86SDimitry Andric 
139fcaf7f86SDimitry Andric     Modules.clear();
140fcaf7f86SDimitry Andric     MMaps.clear();
141fcaf7f86SDimitry Andric   }
142fcaf7f86SDimitry Andric   return true;
143fcaf7f86SDimitry Andric }
144fcaf7f86SDimitry Andric 
tryModule(const MarkupNode & Node,const SmallVector<MarkupNode> & DeferredNodes)145fcaf7f86SDimitry Andric bool MarkupFilter::tryModule(const MarkupNode &Node,
146fcaf7f86SDimitry Andric                              const SmallVector<MarkupNode> &DeferredNodes) {
147fcaf7f86SDimitry Andric   if (Node.Tag != "module")
148fcaf7f86SDimitry Andric     return false;
149bdd1243dSDimitry Andric   std::optional<Module> ParsedModule = parseModule(Node);
150fcaf7f86SDimitry Andric   if (!ParsedModule)
151fcaf7f86SDimitry Andric     return true;
152fcaf7f86SDimitry Andric 
153fcaf7f86SDimitry Andric   auto Res = Modules.try_emplace(
154fcaf7f86SDimitry Andric       ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule)));
155fcaf7f86SDimitry Andric   if (!Res.second) {
156fcaf7f86SDimitry Andric     WithColor::error(errs()) << "duplicate module ID\n";
157fcaf7f86SDimitry Andric     reportLocation(Node.Fields[0].begin());
158fcaf7f86SDimitry Andric     return true;
159fcaf7f86SDimitry Andric   }
160fcaf7f86SDimitry Andric   Module &Module = *Res.first->second;
161fcaf7f86SDimitry Andric 
162fcaf7f86SDimitry Andric   endAnyModuleInfoLine();
163fcaf7f86SDimitry Andric   for (const MarkupNode &Node : DeferredNodes)
164fcaf7f86SDimitry Andric     filterNode(Node);
165fcaf7f86SDimitry Andric   beginModuleInfoLine(&Module);
166fcaf7f86SDimitry Andric   OS << "; BuildID=";
167a4a491e2SDimitry Andric   printValue(toHex(Module.BuildID, /*LowerCase=*/true));
168fcaf7f86SDimitry Andric   return true;
169fcaf7f86SDimitry Andric }
170fcaf7f86SDimitry Andric 
beginModuleInfoLine(const Module * M)171fcaf7f86SDimitry Andric void MarkupFilter::beginModuleInfoLine(const Module *M) {
172fcaf7f86SDimitry Andric   highlight();
173fcaf7f86SDimitry Andric   OS << "[[[ELF module";
174a4a491e2SDimitry Andric   printValue(formatv(" #{0:x} ", M->ID));
175a4a491e2SDimitry Andric   OS << '"';
176a4a491e2SDimitry Andric   printValue(M->Name);
177a4a491e2SDimitry Andric   OS << '"';
178fcaf7f86SDimitry Andric   MIL = ModuleInfoLine{M};
179fcaf7f86SDimitry Andric }
180fcaf7f86SDimitry Andric 
endAnyModuleInfoLine()181fcaf7f86SDimitry Andric void MarkupFilter::endAnyModuleInfoLine() {
182fcaf7f86SDimitry Andric   if (!MIL)
183fcaf7f86SDimitry Andric     return;
184fcaf7f86SDimitry Andric   llvm::stable_sort(MIL->MMaps, [](const MMap *A, const MMap *B) {
185fcaf7f86SDimitry Andric     return A->Addr < B->Addr;
186fcaf7f86SDimitry Andric   });
187fcaf7f86SDimitry Andric   for (const MMap *M : MIL->MMaps) {
188a4a491e2SDimitry Andric     OS << (M == MIL->MMaps.front() ? ' ' : ',');
189a4a491e2SDimitry Andric     OS << '[';
190a4a491e2SDimitry Andric     printValue(formatv("{0:x}", M->Addr));
191a4a491e2SDimitry Andric     OS << '-';
192a4a491e2SDimitry Andric     printValue(formatv("{0:x}", M->Addr + M->Size - 1));
193a4a491e2SDimitry Andric     OS << "](";
194a4a491e2SDimitry Andric     printValue(M->Mode);
195fcaf7f86SDimitry Andric     OS << ')';
196fcaf7f86SDimitry Andric   }
197fcaf7f86SDimitry Andric   OS << "]]]" << lineEnding();
198fcaf7f86SDimitry Andric   restoreColor();
199fcaf7f86SDimitry Andric   MIL.reset();
200fcaf7f86SDimitry Andric }
201fcaf7f86SDimitry Andric 
202fcaf7f86SDimitry Andric // Handle a node that is known not to be a contextual element.
filterNode(const MarkupNode & Node)203fcaf7f86SDimitry Andric void MarkupFilter::filterNode(const MarkupNode &Node) {
20481ad6265SDimitry Andric   if (!checkTag(Node))
20581ad6265SDimitry Andric     return;
206fcaf7f86SDimitry Andric   if (tryPresentation(Node))
207fcaf7f86SDimitry Andric     return;
20881ad6265SDimitry Andric   if (trySGR(Node))
20981ad6265SDimitry Andric     return;
21081ad6265SDimitry Andric 
211fcaf7f86SDimitry Andric   OS << Node.Text;
212fcaf7f86SDimitry Andric }
213fcaf7f86SDimitry Andric 
tryPresentation(const MarkupNode & Node)214fcaf7f86SDimitry Andric bool MarkupFilter::tryPresentation(const MarkupNode &Node) {
215a4a491e2SDimitry Andric   if (trySymbol(Node))
216a4a491e2SDimitry Andric     return true;
217a4a491e2SDimitry Andric   if (tryPC(Node))
218a4a491e2SDimitry Andric     return true;
219a4a491e2SDimitry Andric   if (tryBackTrace(Node))
220a4a491e2SDimitry Andric     return true;
221a4a491e2SDimitry Andric   return tryData(Node);
222fcaf7f86SDimitry Andric }
223fcaf7f86SDimitry Andric 
trySymbol(const MarkupNode & Node)224fcaf7f86SDimitry Andric bool MarkupFilter::trySymbol(const MarkupNode &Node) {
225fcaf7f86SDimitry Andric   if (Node.Tag != "symbol")
226fcaf7f86SDimitry Andric     return false;
22781ad6265SDimitry Andric   if (!checkNumFields(Node, 1))
228fcaf7f86SDimitry Andric     return true;
229fcaf7f86SDimitry Andric 
23081ad6265SDimitry Andric   highlight();
23181ad6265SDimitry Andric   OS << llvm::demangle(Node.Fields.front().str());
23281ad6265SDimitry Andric   restoreColor();
233fcaf7f86SDimitry Andric   return true;
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric 
tryPC(const MarkupNode & Node)236a4a491e2SDimitry Andric bool MarkupFilter::tryPC(const MarkupNode &Node) {
237a4a491e2SDimitry Andric   if (Node.Tag != "pc")
238a4a491e2SDimitry Andric     return false;
239a4a491e2SDimitry Andric   if (!checkNumFieldsAtLeast(Node, 1))
240a4a491e2SDimitry Andric     return true;
24106c3fb27SDimitry Andric   warnNumFieldsAtMost(Node, 2);
242a4a491e2SDimitry Andric 
243bdd1243dSDimitry Andric   std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
244a4a491e2SDimitry Andric   if (!Addr)
245a4a491e2SDimitry Andric     return true;
246a4a491e2SDimitry Andric 
247a4a491e2SDimitry Andric   // PC addresses that aren't part of a backtrace are assumed to be precise code
248a4a491e2SDimitry Andric   // locations.
249a4a491e2SDimitry Andric   PCType Type = PCType::PreciseCode;
250a4a491e2SDimitry Andric   if (Node.Fields.size() == 2) {
251bdd1243dSDimitry Andric     std::optional<PCType> ParsedType = parsePCType(Node.Fields[1]);
252a4a491e2SDimitry Andric     if (!ParsedType)
253a4a491e2SDimitry Andric       return true;
254a4a491e2SDimitry Andric     Type = *ParsedType;
255a4a491e2SDimitry Andric   }
256a4a491e2SDimitry Andric   *Addr = adjustAddr(*Addr, Type);
257a4a491e2SDimitry Andric 
258a4a491e2SDimitry Andric   const MMap *MMap = getContainingMMap(*Addr);
259a4a491e2SDimitry Andric   if (!MMap) {
260a4a491e2SDimitry Andric     WithColor::error() << "no mmap covers address\n";
261a4a491e2SDimitry Andric     reportLocation(Node.Fields[0].begin());
262a4a491e2SDimitry Andric     printRawElement(Node);
263a4a491e2SDimitry Andric     return true;
264a4a491e2SDimitry Andric   }
265a4a491e2SDimitry Andric 
266a4a491e2SDimitry Andric   Expected<DILineInfo> LI = Symbolizer.symbolizeCode(
267a4a491e2SDimitry Andric       MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
268a4a491e2SDimitry Andric   if (!LI) {
269a4a491e2SDimitry Andric     WithColor::defaultErrorHandler(LI.takeError());
270a4a491e2SDimitry Andric     printRawElement(Node);
271a4a491e2SDimitry Andric     return true;
272a4a491e2SDimitry Andric   }
273a4a491e2SDimitry Andric   if (!*LI) {
274a4a491e2SDimitry Andric     printRawElement(Node);
275a4a491e2SDimitry Andric     return true;
276a4a491e2SDimitry Andric   }
277a4a491e2SDimitry Andric 
278a4a491e2SDimitry Andric   highlight();
279a4a491e2SDimitry Andric   printValue(LI->FunctionName);
280a4a491e2SDimitry Andric   OS << '[';
281a4a491e2SDimitry Andric   printValue(LI->FileName);
282a4a491e2SDimitry Andric   OS << ':';
283a4a491e2SDimitry Andric   printValue(Twine(LI->Line));
284a4a491e2SDimitry Andric   OS << ']';
285a4a491e2SDimitry Andric   restoreColor();
286a4a491e2SDimitry Andric   return true;
287a4a491e2SDimitry Andric }
288a4a491e2SDimitry Andric 
tryBackTrace(const MarkupNode & Node)289a4a491e2SDimitry Andric bool MarkupFilter::tryBackTrace(const MarkupNode &Node) {
290a4a491e2SDimitry Andric   if (Node.Tag != "bt")
291a4a491e2SDimitry Andric     return false;
292a4a491e2SDimitry Andric   if (!checkNumFieldsAtLeast(Node, 2))
293a4a491e2SDimitry Andric     return true;
29406c3fb27SDimitry Andric   warnNumFieldsAtMost(Node, 3);
295a4a491e2SDimitry Andric 
296bdd1243dSDimitry Andric   std::optional<uint64_t> FrameNumber = parseFrameNumber(Node.Fields[0]);
297a4a491e2SDimitry Andric   if (!FrameNumber)
298a4a491e2SDimitry Andric     return true;
299a4a491e2SDimitry Andric 
300bdd1243dSDimitry Andric   std::optional<uint64_t> Addr = parseAddr(Node.Fields[1]);
301a4a491e2SDimitry Andric   if (!Addr)
302a4a491e2SDimitry Andric     return true;
303a4a491e2SDimitry Andric 
304a4a491e2SDimitry Andric   // Backtrace addresses are assumed to be return addresses by default.
305a4a491e2SDimitry Andric   PCType Type = PCType::ReturnAddress;
306a4a491e2SDimitry Andric   if (Node.Fields.size() == 3) {
307bdd1243dSDimitry Andric     std::optional<PCType> ParsedType = parsePCType(Node.Fields[2]);
308a4a491e2SDimitry Andric     if (!ParsedType)
309a4a491e2SDimitry Andric       return true;
310a4a491e2SDimitry Andric     Type = *ParsedType;
311a4a491e2SDimitry Andric   }
312a4a491e2SDimitry Andric   *Addr = adjustAddr(*Addr, Type);
313a4a491e2SDimitry Andric 
314a4a491e2SDimitry Andric   const MMap *MMap = getContainingMMap(*Addr);
315a4a491e2SDimitry Andric   if (!MMap) {
316a4a491e2SDimitry Andric     WithColor::error() << "no mmap covers address\n";
317a4a491e2SDimitry Andric     reportLocation(Node.Fields[0].begin());
318a4a491e2SDimitry Andric     printRawElement(Node);
319a4a491e2SDimitry Andric     return true;
320a4a491e2SDimitry Andric   }
321a4a491e2SDimitry Andric   uint64_t MRA = MMap->getModuleRelativeAddr(*Addr);
322a4a491e2SDimitry Andric 
323a4a491e2SDimitry Andric   Expected<DIInliningInfo> II =
324a4a491e2SDimitry Andric       Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA});
325a4a491e2SDimitry Andric   if (!II) {
326a4a491e2SDimitry Andric     WithColor::defaultErrorHandler(II.takeError());
327a4a491e2SDimitry Andric     printRawElement(Node);
328a4a491e2SDimitry Andric     return true;
329a4a491e2SDimitry Andric   }
330a4a491e2SDimitry Andric 
331a4a491e2SDimitry Andric   highlight();
332a4a491e2SDimitry Andric   for (unsigned I = 0, E = II->getNumberOfFrames(); I != E; ++I) {
333a4a491e2SDimitry Andric     auto Header = formatv("{0, +6}", formatv("#{0}", FrameNumber)).sstr<16>();
334a4a491e2SDimitry Andric     // Don't highlight the # sign as a value.
335a4a491e2SDimitry Andric     size_t NumberIdx = Header.find("#") + 1;
336a4a491e2SDimitry Andric     OS << Header.substr(0, NumberIdx);
337a4a491e2SDimitry Andric     printValue(Header.substr(NumberIdx));
338a4a491e2SDimitry Andric     if (I == E - 1) {
339a4a491e2SDimitry Andric       OS << "   ";
340a4a491e2SDimitry Andric     } else {
341a4a491e2SDimitry Andric       OS << '.';
342a4a491e2SDimitry Andric       printValue(formatv("{0, -2}", I + 1));
343a4a491e2SDimitry Andric     }
344a4a491e2SDimitry Andric     printValue(formatv(" {0:x16} ", *Addr));
345a4a491e2SDimitry Andric 
346a4a491e2SDimitry Andric     DILineInfo LI = II->getFrame(I);
347a4a491e2SDimitry Andric     if (LI) {
348a4a491e2SDimitry Andric       printValue(LI.FunctionName);
349a4a491e2SDimitry Andric       OS << ' ';
350a4a491e2SDimitry Andric       printValue(LI.FileName);
351a4a491e2SDimitry Andric       OS << ':';
352a4a491e2SDimitry Andric       printValue(Twine(LI.Line));
353a4a491e2SDimitry Andric       OS << ':';
354a4a491e2SDimitry Andric       printValue(Twine(LI.Column));
355a4a491e2SDimitry Andric       OS << ' ';
356a4a491e2SDimitry Andric     }
357a4a491e2SDimitry Andric     OS << '(';
358a4a491e2SDimitry Andric     printValue(MMap->Mod->Name);
359a4a491e2SDimitry Andric     OS << "+";
360a4a491e2SDimitry Andric     printValue(formatv("{0:x}", MRA));
361a4a491e2SDimitry Andric     OS << ')';
362a4a491e2SDimitry Andric     if (I != E - 1)
363a4a491e2SDimitry Andric       OS << lineEnding();
364a4a491e2SDimitry Andric   }
365a4a491e2SDimitry Andric   restoreColor();
366a4a491e2SDimitry Andric   return true;
367a4a491e2SDimitry Andric }
368a4a491e2SDimitry Andric 
tryData(const MarkupNode & Node)369a4a491e2SDimitry Andric bool MarkupFilter::tryData(const MarkupNode &Node) {
370a4a491e2SDimitry Andric   if (Node.Tag != "data")
371a4a491e2SDimitry Andric     return false;
372a4a491e2SDimitry Andric   if (!checkNumFields(Node, 1))
373a4a491e2SDimitry Andric     return true;
374bdd1243dSDimitry Andric   std::optional<uint64_t> Addr = parseAddr(Node.Fields[0]);
375a4a491e2SDimitry Andric   if (!Addr)
376a4a491e2SDimitry Andric     return true;
377a4a491e2SDimitry Andric 
378a4a491e2SDimitry Andric   const MMap *MMap = getContainingMMap(*Addr);
379a4a491e2SDimitry Andric   if (!MMap) {
380a4a491e2SDimitry Andric     WithColor::error() << "no mmap covers address\n";
381a4a491e2SDimitry Andric     reportLocation(Node.Fields[0].begin());
382a4a491e2SDimitry Andric     printRawElement(Node);
383a4a491e2SDimitry Andric     return true;
384a4a491e2SDimitry Andric   }
385a4a491e2SDimitry Andric 
386a4a491e2SDimitry Andric   Expected<DIGlobal> Symbol = Symbolizer.symbolizeData(
387a4a491e2SDimitry Andric       MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
388a4a491e2SDimitry Andric   if (!Symbol) {
389a4a491e2SDimitry Andric     WithColor::defaultErrorHandler(Symbol.takeError());
390a4a491e2SDimitry Andric     printRawElement(Node);
391a4a491e2SDimitry Andric     return true;
392a4a491e2SDimitry Andric   }
393a4a491e2SDimitry Andric 
394a4a491e2SDimitry Andric   highlight();
395a4a491e2SDimitry Andric   OS << Symbol->Name;
396a4a491e2SDimitry Andric   restoreColor();
397a4a491e2SDimitry Andric   return true;
398a4a491e2SDimitry Andric }
399a4a491e2SDimitry Andric 
trySGR(const MarkupNode & Node)40081ad6265SDimitry Andric bool MarkupFilter::trySGR(const MarkupNode &Node) {
40181ad6265SDimitry Andric   if (Node.Text == "\033[0m") {
40281ad6265SDimitry Andric     resetColor();
40381ad6265SDimitry Andric     return true;
40481ad6265SDimitry Andric   }
40581ad6265SDimitry Andric   if (Node.Text == "\033[1m") {
40681ad6265SDimitry Andric     Bold = true;
40781ad6265SDimitry Andric     if (ColorsEnabled)
40881ad6265SDimitry Andric       OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
40981ad6265SDimitry Andric     return true;
41081ad6265SDimitry Andric   }
411bdd1243dSDimitry Andric   auto SGRColor = StringSwitch<std::optional<raw_ostream::Colors>>(Node.Text)
41281ad6265SDimitry Andric                       .Case("\033[30m", raw_ostream::Colors::BLACK)
41381ad6265SDimitry Andric                       .Case("\033[31m", raw_ostream::Colors::RED)
41481ad6265SDimitry Andric                       .Case("\033[32m", raw_ostream::Colors::GREEN)
41581ad6265SDimitry Andric                       .Case("\033[33m", raw_ostream::Colors::YELLOW)
41681ad6265SDimitry Andric                       .Case("\033[34m", raw_ostream::Colors::BLUE)
41781ad6265SDimitry Andric                       .Case("\033[35m", raw_ostream::Colors::MAGENTA)
41881ad6265SDimitry Andric                       .Case("\033[36m", raw_ostream::Colors::CYAN)
41981ad6265SDimitry Andric                       .Case("\033[37m", raw_ostream::Colors::WHITE)
420bdd1243dSDimitry Andric                       .Default(std::nullopt);
42181ad6265SDimitry Andric   if (SGRColor) {
42281ad6265SDimitry Andric     Color = *SGRColor;
42381ad6265SDimitry Andric     if (ColorsEnabled)
42481ad6265SDimitry Andric       OS.changeColor(*Color);
42581ad6265SDimitry Andric     return true;
42681ad6265SDimitry Andric   }
42781ad6265SDimitry Andric 
42881ad6265SDimitry Andric   return false;
42981ad6265SDimitry Andric }
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric // Begin highlighting text by picking a different color than the current color
43281ad6265SDimitry Andric // state.
highlight()43381ad6265SDimitry Andric void MarkupFilter::highlight() {
43481ad6265SDimitry Andric   if (!ColorsEnabled)
43581ad6265SDimitry Andric     return;
43681ad6265SDimitry Andric   OS.changeColor(Color == raw_ostream::Colors::BLUE ? raw_ostream::Colors::CYAN
43781ad6265SDimitry Andric                                                     : raw_ostream::Colors::BLUE,
43881ad6265SDimitry Andric                  Bold);
43981ad6265SDimitry Andric }
44081ad6265SDimitry Andric 
441fcaf7f86SDimitry Andric // Begin highlighting a field within a highlighted markup string.
highlightValue()442fcaf7f86SDimitry Andric void MarkupFilter::highlightValue() {
443fcaf7f86SDimitry Andric   if (!ColorsEnabled)
444fcaf7f86SDimitry Andric     return;
445fcaf7f86SDimitry Andric   OS.changeColor(raw_ostream::Colors::GREEN, Bold);
446fcaf7f86SDimitry Andric }
447fcaf7f86SDimitry Andric 
44881ad6265SDimitry Andric // Set the output stream's color to the current color and bold state of the SGR
44981ad6265SDimitry Andric // abstract machine.
restoreColor()45081ad6265SDimitry Andric void MarkupFilter::restoreColor() {
45181ad6265SDimitry Andric   if (!ColorsEnabled)
45281ad6265SDimitry Andric     return;
45381ad6265SDimitry Andric   if (Color) {
45481ad6265SDimitry Andric     OS.changeColor(*Color, Bold);
45581ad6265SDimitry Andric   } else {
45681ad6265SDimitry Andric     OS.resetColor();
45781ad6265SDimitry Andric     if (Bold)
45881ad6265SDimitry Andric       OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
45981ad6265SDimitry Andric   }
46081ad6265SDimitry Andric }
46181ad6265SDimitry Andric 
46281ad6265SDimitry Andric // Set the SGR and output stream's color and bold states back to the default.
resetColor()46381ad6265SDimitry Andric void MarkupFilter::resetColor() {
46481ad6265SDimitry Andric   if (!Color && !Bold)
46581ad6265SDimitry Andric     return;
46681ad6265SDimitry Andric   Color.reset();
46781ad6265SDimitry Andric   Bold = false;
46881ad6265SDimitry Andric   if (ColorsEnabled)
46981ad6265SDimitry Andric     OS.resetColor();
47081ad6265SDimitry Andric }
47181ad6265SDimitry Andric 
printRawElement(const MarkupNode & Element)472a4a491e2SDimitry Andric void MarkupFilter::printRawElement(const MarkupNode &Element) {
473a4a491e2SDimitry Andric   highlight();
474a4a491e2SDimitry Andric   OS << "[[[";
475a4a491e2SDimitry Andric   printValue(Element.Tag);
476a4a491e2SDimitry Andric   for (StringRef Field : Element.Fields) {
477a4a491e2SDimitry Andric     OS << ':';
478a4a491e2SDimitry Andric     printValue(Field);
479a4a491e2SDimitry Andric   }
480a4a491e2SDimitry Andric   OS << "]]]";
481a4a491e2SDimitry Andric   restoreColor();
482a4a491e2SDimitry Andric }
483a4a491e2SDimitry Andric 
printValue(Twine Value)484a4a491e2SDimitry Andric void MarkupFilter::printValue(Twine Value) {
485a4a491e2SDimitry Andric   highlightValue();
486a4a491e2SDimitry Andric   OS << Value;
487a4a491e2SDimitry Andric   highlight();
488a4a491e2SDimitry Andric }
489a4a491e2SDimitry Andric 
490fcaf7f86SDimitry Andric // This macro helps reduce the amount of indirection done through Optional
491bdd1243dSDimitry Andric // below, since the usual case upon returning a std::nullopt Optional is to
492bdd1243dSDimitry Andric // return std::nullopt.
493fcaf7f86SDimitry Andric #define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR)                                \
494fcaf7f86SDimitry Andric   auto NAME##Opt = (EXPR);                                                     \
495fcaf7f86SDimitry Andric   if (!NAME##Opt)                                                              \
496bdd1243dSDimitry Andric     return std::nullopt;                                                       \
497fcaf7f86SDimitry Andric   TYPE NAME = std::move(*NAME##Opt)
498fcaf7f86SDimitry Andric 
499bdd1243dSDimitry Andric std::optional<MarkupFilter::Module>
parseModule(const MarkupNode & Element) const500fcaf7f86SDimitry Andric MarkupFilter::parseModule(const MarkupNode &Element) const {
501fcaf7f86SDimitry Andric   if (!checkNumFieldsAtLeast(Element, 3))
502bdd1243dSDimitry Andric     return std::nullopt;
503fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[0]));
504fcaf7f86SDimitry Andric   StringRef Name = Element.Fields[1];
505fcaf7f86SDimitry Andric   StringRef Type = Element.Fields[2];
506fcaf7f86SDimitry Andric   if (Type != "elf") {
507fcaf7f86SDimitry Andric     WithColor::error() << "unknown module type\n";
508fcaf7f86SDimitry Andric     reportLocation(Type.begin());
509bdd1243dSDimitry Andric     return std::nullopt;
510fcaf7f86SDimitry Andric   }
511fcaf7f86SDimitry Andric   if (!checkNumFields(Element, 4))
512bdd1243dSDimitry Andric     return std::nullopt;
51306c3fb27SDimitry Andric   SmallVector<uint8_t> BuildID = parseBuildID(Element.Fields[3]);
51406c3fb27SDimitry Andric   if (BuildID.empty())
51506c3fb27SDimitry Andric     return std::nullopt;
516fcaf7f86SDimitry Andric   return Module{ID, Name.str(), std::move(BuildID)};
517fcaf7f86SDimitry Andric }
518fcaf7f86SDimitry Andric 
519bdd1243dSDimitry Andric std::optional<MarkupFilter::MMap>
parseMMap(const MarkupNode & Element) const520fcaf7f86SDimitry Andric MarkupFilter::parseMMap(const MarkupNode &Element) const {
521fcaf7f86SDimitry Andric   if (!checkNumFieldsAtLeast(Element, 3))
522bdd1243dSDimitry Andric     return std::nullopt;
523fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(uint64_t, Addr, parseAddr(Element.Fields[0]));
524fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(uint64_t, Size, parseSize(Element.Fields[1]));
525fcaf7f86SDimitry Andric   StringRef Type = Element.Fields[2];
526fcaf7f86SDimitry Andric   if (Type != "load") {
527fcaf7f86SDimitry Andric     WithColor::error() << "unknown mmap type\n";
528fcaf7f86SDimitry Andric     reportLocation(Type.begin());
529bdd1243dSDimitry Andric     return std::nullopt;
530fcaf7f86SDimitry Andric   }
531fcaf7f86SDimitry Andric   if (!checkNumFields(Element, 6))
532bdd1243dSDimitry Andric     return std::nullopt;
533fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(uint64_t, ID, parseModuleID(Element.Fields[3]));
534fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(std::string, Mode, parseMode(Element.Fields[4]));
535fcaf7f86SDimitry Andric   auto It = Modules.find(ID);
536fcaf7f86SDimitry Andric   if (It == Modules.end()) {
537fcaf7f86SDimitry Andric     WithColor::error() << "unknown module ID\n";
538fcaf7f86SDimitry Andric     reportLocation(Element.Fields[3].begin());
539bdd1243dSDimitry Andric     return std::nullopt;
540fcaf7f86SDimitry Andric   }
541fcaf7f86SDimitry Andric   ASSIGN_OR_RETURN_NONE(uint64_t, ModuleRelativeAddr,
542fcaf7f86SDimitry Andric                         parseAddr(Element.Fields[5]));
543fcaf7f86SDimitry Andric   return MMap{Addr, Size, It->second.get(), std::move(Mode),
544fcaf7f86SDimitry Andric               ModuleRelativeAddr};
545fcaf7f86SDimitry Andric }
546fcaf7f86SDimitry Andric 
547fcaf7f86SDimitry Andric // Parse an address (%p in the spec).
parseAddr(StringRef Str) const548bdd1243dSDimitry Andric std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str) const {
549fcaf7f86SDimitry Andric   if (Str.empty()) {
550fcaf7f86SDimitry Andric     reportTypeError(Str, "address");
551bdd1243dSDimitry Andric     return std::nullopt;
552fcaf7f86SDimitry Andric   }
553fcaf7f86SDimitry Andric   if (all_of(Str, [](char C) { return C == '0'; }))
554fcaf7f86SDimitry Andric     return 0;
5555f757f3fSDimitry Andric   if (!Str.starts_with("0x")) {
556fcaf7f86SDimitry Andric     reportTypeError(Str, "address");
557bdd1243dSDimitry Andric     return std::nullopt;
558fcaf7f86SDimitry Andric   }
559fcaf7f86SDimitry Andric   uint64_t Addr;
560fcaf7f86SDimitry Andric   if (Str.drop_front(2).getAsInteger(16, Addr)) {
561fcaf7f86SDimitry Andric     reportTypeError(Str, "address");
562bdd1243dSDimitry Andric     return std::nullopt;
563fcaf7f86SDimitry Andric   }
564fcaf7f86SDimitry Andric   return Addr;
565fcaf7f86SDimitry Andric }
566fcaf7f86SDimitry Andric 
567fcaf7f86SDimitry Andric // Parse a module ID (%i in the spec).
parseModuleID(StringRef Str) const568bdd1243dSDimitry Andric std::optional<uint64_t> MarkupFilter::parseModuleID(StringRef Str) const {
569fcaf7f86SDimitry Andric   uint64_t ID;
570fcaf7f86SDimitry Andric   if (Str.getAsInteger(0, ID)) {
571fcaf7f86SDimitry Andric     reportTypeError(Str, "module ID");
572bdd1243dSDimitry Andric     return std::nullopt;
573fcaf7f86SDimitry Andric   }
574fcaf7f86SDimitry Andric   return ID;
575fcaf7f86SDimitry Andric }
576fcaf7f86SDimitry Andric 
577fcaf7f86SDimitry Andric // Parse a size (%i in the spec).
parseSize(StringRef Str) const578bdd1243dSDimitry Andric std::optional<uint64_t> MarkupFilter::parseSize(StringRef Str) const {
579fcaf7f86SDimitry Andric   uint64_t ID;
580fcaf7f86SDimitry Andric   if (Str.getAsInteger(0, ID)) {
581fcaf7f86SDimitry Andric     reportTypeError(Str, "size");
582bdd1243dSDimitry Andric     return std::nullopt;
583fcaf7f86SDimitry Andric   }
584fcaf7f86SDimitry Andric   return ID;
585fcaf7f86SDimitry Andric }
586fcaf7f86SDimitry Andric 
587a4a491e2SDimitry Andric // Parse a frame number (%i in the spec).
parseFrameNumber(StringRef Str) const588bdd1243dSDimitry Andric std::optional<uint64_t> MarkupFilter::parseFrameNumber(StringRef Str) const {
589a4a491e2SDimitry Andric   uint64_t ID;
590a4a491e2SDimitry Andric   if (Str.getAsInteger(10, ID)) {
591a4a491e2SDimitry Andric     reportTypeError(Str, "frame number");
592bdd1243dSDimitry Andric     return std::nullopt;
593a4a491e2SDimitry Andric   }
594a4a491e2SDimitry Andric   return ID;
595a4a491e2SDimitry Andric }
596a4a491e2SDimitry Andric 
597fcaf7f86SDimitry Andric // Parse a build ID (%x in the spec).
parseBuildID(StringRef Str) const59806c3fb27SDimitry Andric object::BuildID MarkupFilter::parseBuildID(StringRef Str) const {
59906c3fb27SDimitry Andric   object::BuildID BID = llvm::object::parseBuildID(Str);
60006c3fb27SDimitry Andric   if (BID.empty())
601fcaf7f86SDimitry Andric     reportTypeError(Str, "build ID");
60206c3fb27SDimitry Andric   return BID;
603fcaf7f86SDimitry Andric }
604fcaf7f86SDimitry Andric 
605fcaf7f86SDimitry Andric // Parses the mode string for an mmap element.
parseMode(StringRef Str) const606bdd1243dSDimitry Andric std::optional<std::string> MarkupFilter::parseMode(StringRef Str) const {
607fcaf7f86SDimitry Andric   if (Str.empty()) {
608fcaf7f86SDimitry Andric     reportTypeError(Str, "mode");
609bdd1243dSDimitry Andric     return std::nullopt;
610fcaf7f86SDimitry Andric   }
611fcaf7f86SDimitry Andric 
612fcaf7f86SDimitry Andric   // Pop off each of r/R, w/W, and x/X from the front, in that order.
613fcaf7f86SDimitry Andric   StringRef Remainder = Str;
614*7a6dacacSDimitry Andric   Remainder.consume_front_insensitive("r");
615*7a6dacacSDimitry Andric   Remainder.consume_front_insensitive("w");
616*7a6dacacSDimitry Andric   Remainder.consume_front_insensitive("x");
617fcaf7f86SDimitry Andric 
618fcaf7f86SDimitry Andric   // If anything remains, then the string wasn't a mode.
619fcaf7f86SDimitry Andric   if (!Remainder.empty()) {
620fcaf7f86SDimitry Andric     reportTypeError(Str, "mode");
621bdd1243dSDimitry Andric     return std::nullopt;
622fcaf7f86SDimitry Andric   }
623fcaf7f86SDimitry Andric 
624fcaf7f86SDimitry Andric   // Normalize the mode.
625fcaf7f86SDimitry Andric   return Str.lower();
626fcaf7f86SDimitry Andric }
627fcaf7f86SDimitry Andric 
628bdd1243dSDimitry Andric std::optional<MarkupFilter::PCType>
parsePCType(StringRef Str) const629bdd1243dSDimitry Andric MarkupFilter::parsePCType(StringRef Str) const {
630bdd1243dSDimitry Andric   std::optional<MarkupFilter::PCType> Type =
631bdd1243dSDimitry Andric       StringSwitch<std::optional<MarkupFilter::PCType>>(Str)
632a4a491e2SDimitry Andric           .Case("ra", MarkupFilter::PCType::ReturnAddress)
633a4a491e2SDimitry Andric           .Case("pc", MarkupFilter::PCType::PreciseCode)
634bdd1243dSDimitry Andric           .Default(std::nullopt);
635a4a491e2SDimitry Andric   if (!Type)
636a4a491e2SDimitry Andric     reportTypeError(Str, "PC type");
637a4a491e2SDimitry Andric   return Type;
638a4a491e2SDimitry Andric }
639a4a491e2SDimitry Andric 
checkTag(const MarkupNode & Node) const64081ad6265SDimitry Andric bool MarkupFilter::checkTag(const MarkupNode &Node) const {
64181ad6265SDimitry Andric   if (any_of(Node.Tag, [](char C) { return C < 'a' || C > 'z'; })) {
64281ad6265SDimitry Andric     WithColor::error(errs()) << "tags must be all lowercase characters\n";
64381ad6265SDimitry Andric     reportLocation(Node.Tag.begin());
64481ad6265SDimitry Andric     return false;
64581ad6265SDimitry Andric   }
64681ad6265SDimitry Andric   return true;
64781ad6265SDimitry Andric }
64881ad6265SDimitry Andric 
checkNumFields(const MarkupNode & Element,size_t Size) const649fcaf7f86SDimitry Andric bool MarkupFilter::checkNumFields(const MarkupNode &Element,
650fcaf7f86SDimitry Andric                                   size_t Size) const {
651fcaf7f86SDimitry Andric   if (Element.Fields.size() != Size) {
65206c3fb27SDimitry Andric     bool Warn = Element.Fields.size() > Size;
65306c3fb27SDimitry Andric     WithColor(errs(), Warn ? HighlightColor::Warning : HighlightColor::Error)
65406c3fb27SDimitry Andric         << (Warn ? "warning: " : "error: ") << "expected " << Size
65506c3fb27SDimitry Andric         << " field(s); found " << Element.Fields.size() << "\n";
656fcaf7f86SDimitry Andric     reportLocation(Element.Tag.end());
65706c3fb27SDimitry Andric     return Warn;
65881ad6265SDimitry Andric   }
65981ad6265SDimitry Andric   return true;
66081ad6265SDimitry Andric }
66181ad6265SDimitry Andric 
checkNumFieldsAtLeast(const MarkupNode & Element,size_t Size) const662fcaf7f86SDimitry Andric bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element,
663fcaf7f86SDimitry Andric                                          size_t Size) const {
664fcaf7f86SDimitry Andric   if (Element.Fields.size() < Size) {
665fcaf7f86SDimitry Andric     WithColor::error(errs())
666a4a491e2SDimitry Andric         << "expected at least " << Size << " field(s); found "
667a4a491e2SDimitry Andric         << Element.Fields.size() << "\n";
668a4a491e2SDimitry Andric     reportLocation(Element.Tag.end());
669a4a491e2SDimitry Andric     return false;
670a4a491e2SDimitry Andric   }
671a4a491e2SDimitry Andric   return true;
672a4a491e2SDimitry Andric }
673a4a491e2SDimitry Andric 
warnNumFieldsAtMost(const MarkupNode & Element,size_t Size) const67406c3fb27SDimitry Andric void MarkupFilter::warnNumFieldsAtMost(const MarkupNode &Element,
675a4a491e2SDimitry Andric                                        size_t Size) const {
67606c3fb27SDimitry Andric   if (Element.Fields.size() <= Size)
67706c3fb27SDimitry Andric     return;
67806c3fb27SDimitry Andric   WithColor::warning(errs())
679a4a491e2SDimitry Andric       << "expected at most " << Size << " field(s); found "
680fcaf7f86SDimitry Andric       << Element.Fields.size() << "\n";
681fcaf7f86SDimitry Andric   reportLocation(Element.Tag.end());
682fcaf7f86SDimitry Andric }
683fcaf7f86SDimitry Andric 
reportTypeError(StringRef Str,StringRef TypeName) const684fcaf7f86SDimitry Andric void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const {
685fcaf7f86SDimitry Andric   WithColor::error(errs()) << "expected " << TypeName << "; found '" << Str
686fcaf7f86SDimitry Andric                            << "'\n";
687fcaf7f86SDimitry Andric   reportLocation(Str.begin());
688fcaf7f86SDimitry Andric }
689fcaf7f86SDimitry Andric 
690fcaf7f86SDimitry Andric // Prints two lines that point out the given location in the current Line using
691fcaf7f86SDimitry Andric // a caret. The iterator must be within the bounds of the most recent line
692fcaf7f86SDimitry Andric // passed to beginLine().
reportLocation(StringRef::iterator Loc) const69381ad6265SDimitry Andric void MarkupFilter::reportLocation(StringRef::iterator Loc) const {
69481ad6265SDimitry Andric   errs() << Line;
6955f757f3fSDimitry Andric   WithColor(errs().indent(Loc - StringRef(Line).begin()),
6965f757f3fSDimitry Andric             HighlightColor::String)
6975f757f3fSDimitry Andric       << '^';
69881ad6265SDimitry Andric   errs() << '\n';
69981ad6265SDimitry Andric }
700fcaf7f86SDimitry Andric 
701fcaf7f86SDimitry Andric // Checks for an existing mmap that overlaps the given one and returns a
702fcaf7f86SDimitry Andric // pointer to one of them.
703a4a491e2SDimitry Andric const MarkupFilter::MMap *
getOverlappingMMap(const MMap & Map) const704a4a491e2SDimitry Andric MarkupFilter::getOverlappingMMap(const MMap &Map) const {
705fcaf7f86SDimitry Andric   // If the given map contains the start of another mmap, they overlap.
706fcaf7f86SDimitry Andric   auto I = MMaps.upper_bound(Map.Addr);
707fcaf7f86SDimitry Andric   if (I != MMaps.end() && Map.contains(I->second.Addr))
708fcaf7f86SDimitry Andric     return &I->second;
709fcaf7f86SDimitry Andric 
710fcaf7f86SDimitry Andric   // If no element starts inside the given mmap, the only possible overlap would
711fcaf7f86SDimitry Andric   // be if the preceding mmap contains the start point of the given mmap.
712fcaf7f86SDimitry Andric   if (I != MMaps.begin()) {
713fcaf7f86SDimitry Andric     --I;
714fcaf7f86SDimitry Andric     if (I->second.contains(Map.Addr))
715fcaf7f86SDimitry Andric       return &I->second;
716fcaf7f86SDimitry Andric   }
717fcaf7f86SDimitry Andric   return nullptr;
718fcaf7f86SDimitry Andric }
719fcaf7f86SDimitry Andric 
720a4a491e2SDimitry Andric // Returns the MMap that contains the given address or nullptr if none.
getContainingMMap(uint64_t Addr) const721a4a491e2SDimitry Andric const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const {
722a4a491e2SDimitry Andric   // Find the first mmap starting >= Addr.
723a4a491e2SDimitry Andric   auto I = MMaps.lower_bound(Addr);
724a4a491e2SDimitry Andric   if (I != MMaps.end() && I->second.contains(Addr))
725a4a491e2SDimitry Andric     return &I->second;
726a4a491e2SDimitry Andric 
727a4a491e2SDimitry Andric   // The previous mmap is the last one starting < Addr.
728a4a491e2SDimitry Andric   if (I == MMaps.begin())
729a4a491e2SDimitry Andric     return nullptr;
730a4a491e2SDimitry Andric   --I;
731a4a491e2SDimitry Andric   return I->second.contains(Addr) ? &I->second : nullptr;
732a4a491e2SDimitry Andric }
733a4a491e2SDimitry Andric 
adjustAddr(uint64_t Addr,PCType Type) const734a4a491e2SDimitry Andric uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const {
735a4a491e2SDimitry Andric   // Decrementing return addresses by one moves them into the call instruction.
736a4a491e2SDimitry Andric   // The address doesn't have to be the start of the call instruction, just some
737a4a491e2SDimitry Andric   // byte on the inside. Subtracting one avoids needing detailed instruction
738a4a491e2SDimitry Andric   // length information here.
739a4a491e2SDimitry Andric   return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr;
740a4a491e2SDimitry Andric }
741a4a491e2SDimitry Andric 
lineEnding() const742fcaf7f86SDimitry Andric StringRef MarkupFilter::lineEnding() const {
7435f757f3fSDimitry Andric   return StringRef(Line).ends_with("\r\n") ? "\r\n" : "\n";
744fcaf7f86SDimitry Andric }
745fcaf7f86SDimitry Andric 
contains(uint64_t Addr) const746fcaf7f86SDimitry Andric bool MarkupFilter::MMap::contains(uint64_t Addr) const {
747fcaf7f86SDimitry Andric   return this->Addr <= Addr && Addr < this->Addr + Size;
748fcaf7f86SDimitry Andric }
749a4a491e2SDimitry Andric 
750a4a491e2SDimitry Andric // Returns the module-relative address for a given virtual address.
getModuleRelativeAddr(uint64_t Addr) const751a4a491e2SDimitry Andric uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr) const {
752a4a491e2SDimitry Andric   return Addr - this->Addr + ModuleRelativeAddr;
753a4a491e2SDimitry Andric }
754