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