36 std::optional<bool> ColorsEnabled)
37 : OS(OS), Symbolizer(Symbolizer),
39 ColorsEnabled.value_or(
WithColor::defaultAutoDetectFunction()(OS))) {}
42 Line = std::move(InputLine);
45 Parser.parseLine(Line);
50 while (std::optional<MarkupNode>
Node = Parser.nextNode()) {
52 if (tryContextualElement(*
Node, DeferredNodes))
59 endAnyModuleInfoLine();
66 while (std::optional<MarkupNode>
Node = Parser.nextNode())
68 endAnyModuleInfoLine();
82bool MarkupFilter::tryContextualElement(
84 if (tryMMap(
Node, DeferredNodes))
86 if (tryReset(
Node, DeferredNodes))
88 return tryModule(
Node, DeferredNodes);
93 if (
Node.Tag !=
"mmap")
95 std::optional<MMap> ParsedMMap = parseMMap(
Node);
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());
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;
111 if (!MIL || MIL->Mod != MMap.Mod) {
112 endAnyModuleInfoLine();
115 beginModuleInfoLine(MMap.Mod);
118 MIL->MMaps.push_back(&MMap);
122bool MarkupFilter::tryReset(
const MarkupNode &Node,
124 if (
Node.Tag !=
"reset")
126 if (!checkNumFields(Node, 0))
129 if (!Modules.empty() || !MMaps.empty()) {
130 endAnyModuleInfoLine();
131 for (
const MarkupNode &Node : DeferredNodes)
133 printRawElement(Node);
142bool MarkupFilter::tryModule(
const MarkupNode &Node,
144 if (
Node.Tag !=
"module")
146 std::optional<Module> ParsedModule = parseModule(Node);
150 auto Res = Modules.try_emplace(
151 ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule)));
154 reportLocation(
Node.Fields[0].begin());
157 Module &Module = *Res.first->second;
159 endAnyModuleInfoLine();
160 for (
const MarkupNode &Node : DeferredNodes)
162 beginModuleInfoLine(&Module);
164 printValue(
toHex(Module.BuildID,
true));
168void MarkupFilter::beginModuleInfoLine(
const Module *M) {
170 OS <<
"[[[ELF module";
171 printValue(
formatv(
" #{0:x} ",
M->ID));
175 MIL = ModuleInfoLine{
M};
178void MarkupFilter::endAnyModuleInfoLine() {
182 return A->Addr < B->Addr;
184 for (
const MMap *M : MIL->MMaps) {
185 OS << (
M == MIL->MMaps.front() ?
' ' :
',');
187 printValue(
formatv(
"{0:x}",
M->Addr));
189 printValue(
formatv(
"{0:x}",
M->Addr +
M->Size - 1));
194 OS <<
"]]]" << lineEnding();
200void MarkupFilter::filterNode(
const MarkupNode &Node) {
203 if (tryPresentation(Node))
211bool MarkupFilter::tryPresentation(
const MarkupNode &Node) {
216 if (tryBackTrace(Node))
218 return tryData(Node);
221bool MarkupFilter::trySymbol(
const MarkupNode &Node) {
222 if (
Node.Tag !=
"symbol")
224 if (!checkNumFields(Node, 1))
233bool MarkupFilter::tryPC(
const MarkupNode &Node) {
234 if (
Node.Tag !=
"pc")
236 if (!checkNumFieldsAtLeast(Node, 1))
238 warnNumFieldsAtMost(Node, 2);
240 std::optional<uint64_t> Addr = parseAddr(
Node.Fields[0]);
246 PCType
Type = PCType::PreciseCode;
247 if (
Node.Fields.size() == 2) {
248 std::optional<PCType> ParsedType = parsePCType(
Node.Fields[1]);
253 *Addr = adjustAddr(*Addr,
Type);
255 const MMap *MMap = getContainingMMap(*Addr);
258 reportLocation(
Node.Fields[0].begin());
259 printRawElement(Node);
263 Expected<DILineInfo> LI = Symbolizer.symbolizeCode(
264 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
267 printRawElement(Node);
271 printRawElement(Node);
276 printValue(LI->FunctionName);
278 printValue(LI->FileName);
280 printValue(Twine(LI->Line));
286bool MarkupFilter::tryBackTrace(
const MarkupNode &Node) {
287 if (
Node.Tag !=
"bt")
289 if (!checkNumFieldsAtLeast(Node, 2))
291 warnNumFieldsAtMost(Node, 3);
293 std::optional<uint64_t> FrameNumber = parseFrameNumber(
Node.Fields[0]);
297 std::optional<uint64_t> Addr = parseAddr(
Node.Fields[1]);
302 PCType
Type = PCType::ReturnAddress;
303 if (
Node.Fields.size() == 3) {
304 std::optional<PCType> ParsedType = parsePCType(
Node.Fields[2]);
309 *Addr = adjustAddr(*Addr,
Type);
311 const MMap *MMap = getContainingMMap(*Addr);
314 reportLocation(
Node.Fields[0].begin());
315 printRawElement(Node);
318 uint64_t MRA = MMap->getModuleRelativeAddr(*Addr);
320 Expected<DIInliningInfo>
II =
321 Symbolizer.symbolizeInlinedCode(MMap->Mod->BuildID, {MRA});
324 printRawElement(Node);
329 for (
unsigned I = 0,
E =
II->getNumberOfFrames();
I !=
E; ++
I) {
330 auto Header =
formatv(
"{0, +6}",
formatv(
"#{0}", FrameNumber)).sstr<16>();
332 size_t NumberIdx = Header.find(
"#") + 1;
333 OS << Header.substr(0, NumberIdx);
334 printValue(Header.substr(NumberIdx));
339 printValue(
formatv(
"{0, -2}",
I + 1));
341 printValue(
formatv(
" {0:x16} ", *Addr));
343 DILineInfo LI =
II->getFrame(
I);
349 printValue(Twine(LI.
Line));
351 printValue(Twine(LI.
Column));
355 printValue(MMap->Mod->Name);
357 printValue(
formatv(
"{0:x}", MRA));
366bool MarkupFilter::tryData(
const MarkupNode &Node) {
367 if (
Node.Tag !=
"data")
369 if (!checkNumFields(Node, 1))
371 std::optional<uint64_t> Addr = parseAddr(
Node.Fields[0]);
375 const MMap *MMap = getContainingMMap(*Addr);
378 reportLocation(
Node.Fields[0].begin());
379 printRawElement(Node);
383 Expected<DIGlobal>
Symbol = Symbolizer.symbolizeData(
384 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
387 printRawElement(Node);
397bool MarkupFilter::trySGR(
const MarkupNode &Node) {
398 if (
Node.Text ==
"\033[0m") {
402 if (
Node.Text ==
"\033[1m") {
408 auto SGRColor = StringSwitch<std::optional<raw_ostream::Colors>>(
Node.Text)
417 .Default(std::nullopt);
421 OS.changeColor(*Color);
430void MarkupFilter::highlight() {
439void MarkupFilter::highlightValue() {
447void MarkupFilter::restoreColor() {
451 OS.changeColor(*Color, Bold);
460void MarkupFilter::resetColor() {
469void MarkupFilter::printRawElement(
const MarkupNode &Element) {
472 printValue(Element.
Tag);
481void MarkupFilter::printValue(Twine
Value) {
490#define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR) \
491 auto NAME##Opt = (EXPR); \
493 return std::nullopt; \
494 TYPE NAME = std::move(*NAME##Opt)
496std::optional<MarkupFilter::Module>
497MarkupFilter::parseModule(
const MarkupNode &Element)
const {
498 if (!checkNumFieldsAtLeast(Element, 3))
505 reportLocation(
Type.begin());
508 if (!checkNumFields(Element, 4))
516std::optional<MarkupFilter::MMap>
517MarkupFilter::parseMMap(
const MarkupNode &Element)
const {
518 if (!checkNumFieldsAtLeast(Element, 3))
523 if (
Type !=
"load") {
525 reportLocation(
Type.begin());
528 if (!checkNumFields(Element, 6))
532 auto It = Modules.find(
ID);
533 if (It == Modules.end()) {
535 reportLocation(Element.
Fields[3].begin());
539 parseAddr(Element.
Fields[5]));
540 return MMap{Addr,
Size, It->second.get(), std::move(
Mode),
545std::optional<uint64_t> MarkupFilter::parseAddr(StringRef Str)
const {
547 reportTypeError(Str,
"address");
550 if (
all_of(Str, [](
char C) {
return C ==
'0'; }))
552 if (!Str.starts_with(
"0x")) {
553 reportTypeError(Str,
"address");
557 if (Str.drop_front(2).getAsInteger(16, Addr)) {
558 reportTypeError(Str,
"address");
565std::optional<uint64_t> MarkupFilter::parseModuleID(StringRef Str)
const {
567 if (Str.getAsInteger(0,
ID)) {
568 reportTypeError(Str,
"module ID");
575std::optional<uint64_t> MarkupFilter::parseSize(StringRef Str)
const {
577 if (Str.getAsInteger(0,
ID)) {
578 reportTypeError(Str,
"size");
585std::optional<uint64_t> MarkupFilter::parseFrameNumber(StringRef Str)
const {
587 if (Str.getAsInteger(10,
ID)) {
588 reportTypeError(Str,
"frame number");
598 reportTypeError(Str,
"build ID");
603std::optional<std::string> MarkupFilter::parseMode(StringRef Str)
const {
605 reportTypeError(Str,
"mode");
610 StringRef Remainder = Str;
616 if (!Remainder.
empty()) {
617 reportTypeError(Str,
"mode");
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);
633 reportTypeError(Str,
"PC type");
637bool MarkupFilter::checkTag(
const MarkupNode &Node)
const {
638 if (
any_of(
Node.Tag, [](
char C) { return C <
'a' || C >
'z'; })) {
640 reportLocation(
Node.Tag.begin());
646bool MarkupFilter::checkNumFields(
const MarkupNode &Element,
651 << (Warn ?
"warning: " :
"error: ") <<
"expected " <<
Size
652 <<
" field(s); found " << Element.
Fields.size() <<
"\n";
653 reportLocation(Element.
Tag.
end());
659bool MarkupFilter::checkNumFieldsAtLeast(
const MarkupNode &Element,
663 <<
"expected at least " <<
Size <<
" field(s); found "
664 << Element.
Fields.size() <<
"\n";
665 reportLocation(Element.
Tag.
end());
671void MarkupFilter::warnNumFieldsAtMost(
const MarkupNode &Element,
676 <<
"expected at most " <<
Size <<
" field(s); found "
677 << Element.
Fields.size() <<
"\n";
678 reportLocation(Element.
Tag.
end());
681void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName)
const {
684 reportLocation(Str.begin());
692 WithColor(
errs().indent(Loc - StringRef(Line).
begin()),
700const MarkupFilter::MMap *
701MarkupFilter::getOverlappingMMap(
const MMap &Map)
const {
703 auto I = MMaps.upper_bound(
Map.Addr);
704 if (
I != MMaps.end() &&
Map.contains(
I->second.Addr))
709 if (
I != MMaps.begin()) {
711 if (
I->second.contains(
Map.Addr))
718const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr)
const {
720 auto I = MMaps.lower_bound(Addr);
721 if (
I != MMaps.end() &&
I->second.contains(Addr))
725 if (
I == MMaps.begin())
728 return I->second.contains(Addr) ? &
I->second :
nullptr;
731uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType
Type)
const {
736 return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr;
739StringRef MarkupFilter::lineEnding()
const {
740 return StringRef(Line).ends_with(
"\r\n") ?
"\r\n" :
"\n";
743bool MarkupFilter::MMap::contains(uint64_t Addr)
const {
744 return this->Addr <= Addr && Addr < this->Addr + Size;
748uint64_t MarkupFilter::MMap::getModuleRelativeAddr(uint64_t Addr)
const {
749 return Addr - this->Addr + ModuleRelativeAddr;
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")
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 implements the StringSwitch template, which mimics a switch() statement whose cases are str...
Error takeError()
Take ownership of the stored error.
A Module instance is used to store all the information related to an LLVM module.
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.
constexpr bool empty() const
empty - Check if the string is empty.
bool consume_front_insensitive(StringRef Prefix)
Returns true if this StringRef has the given prefix, ignoring case, and removes that prefix.
The instances of the Type class are immutable: once they are created, they are never changed.
An RAII object that temporarily switches an output stream to a specific color.
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
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.
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.
@ C
The default llvm calling convention, compatible with C.
SmallVector< uint8_t, 10 > BuildID
A build ID in binary form.
LLVM_ABI BuildID parseBuildID(StringRef Str)
Parses a build ID from a hex string.
NodeAddr< NodeBase * > Node
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
void stable_sort(R &&Range)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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.
A node of symbolizer markup.
SmallVector< StringRef > Fields
If this represents an element with fields, a list of the field contents.
StringRef Tag
If this represents an element, the tag. Otherwise, empty.