LLVM 20.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
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
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)
406 return true;
407 }
409 .Case("\033[30m", raw_ostream::Colors::BLACK)
410 .Case("\033[31m", raw_ostream::Colors::RED)
411 .Case("\033[32m", raw_ostream::Colors::GREEN)
413 .Case("\033[34m", raw_ostream::Colors::BLUE)
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;
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)
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;
510 SmallVector<uint8_t> BuildID = parseBuildID(Element.Fields[3]);
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 }
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 =
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}
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
uint64_t Addr
std::string Name
uint64_t Size
#define I(x, y, z)
Definition: MD5.cpp:58
#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
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
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...
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:156
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition: DenseMap.h:226
bool empty() const
Definition: DenseMap.h:98
iterator end()
Definition: DenseMap.h:84
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
bool empty() const
Definition: SmallVector.h:81
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:147
iterator end() const
Definition: StringRef.h:118
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition: StringRef.h:277
bool consume_front_insensitive(StringRef Prefix)
Returns true if this StringRef has the given prefix, ignoring case, and removes that prefix.
Definition: StringRef.h:645
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
An RAII object that temporarily switches an output stream to a specific color.
Definition: WithColor.h:54
static raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Definition: WithColor.cpp:85
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition: WithColor.cpp:83
static void defaultErrorHandler(Error Err)
Implement default handling for Error.
Definition: WithColor.cpp:158
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
virtual raw_ostream & changeColor(enum Colors Color, bool Bold=false, bool BG=false)
Changes the foreground color of text that will be output from this point forward.
virtual raw_ostream & resetColor()
Resets the colors to terminal defaults.
Expected< DIInliningInfo > symbolizeInlinedCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:134
Expected< DILineInfo > symbolizeCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:83
Expected< DIGlobal > symbolizeData(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Definition: Symbolize.cpp:179
MarkupFilter(raw_ostream &OS, LLVMSymbolizer &Symbolizer, std::optional< bool > ColorsEnabled=std::nullopt)
void filter(std::string &&InputLine)
Filters a line containing symbolizer markup and writes the human-readable results to the output strea...
void finish()
Records that the input stream has ended and writes any deferred output.
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
BuildID parseBuildID(StringRef Str)
Parses a build ID from a hex string.
Definition: BuildID.cpp:47
static std::string toHex(uint64_t V)
Definition: DIPrinter.cpp:288
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
Definition: Path.cpp:226
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void stable_sort(R &&Range)
Definition: STLExtras.h:2037
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:1739
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:1746
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
std::string demangle(std::string_view MangledName)
Attempt to demangle a string using different demangling schemes.
Definition: Demangle.cpp:20
A format-neutral container for source line information.
Definition: DIContext.h:32
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:33
SmallVector< StringRef > Fields
If this represents an element with fields, a list of the field contents.
Definition: Markup.h:42
StringRef Tag
If this represents an element, the tag. Otherwise, empty.
Definition: Markup.h:38