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)
411 OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, Bold);
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;
448 OS.changeColor(raw_ostream::Colors::GREEN, Bold);
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)
461 OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, 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.
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:150
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&... Args)
Definition: DenseMap.h:222
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:597
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
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:278
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void stable_sort(R &&Range)
Definition: STLExtras.h:1948
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:1735
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:1742
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