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