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