39 std::optional<bool> ColorsEnabled)
40 :
OS(
OS), Symbolizer(Symbolizer),
42 ColorsEnabled.value_or(
WithColor::defaultAutoDetectFunction()(
OS))) {}
53 while (std::optional<MarkupNode> Node =
Parser.nextNode()) {
55 if (tryContextualElement(*Node, DeferredNodes))
62 endAnyModuleInfoLine();
69 while (std::optional<MarkupNode> Node =
Parser.nextNode())
71 endAnyModuleInfoLine();
85bool MarkupFilter::tryContextualElement(
87 if (tryMMap(Node, DeferredNodes))
89 if (tryReset(Node, DeferredNodes))
91 return tryModule(Node, DeferredNodes);
94bool MarkupFilter::tryMMap(
const MarkupNode &Node,
96 if (Node.Tag !=
"mmap")
98 std::optional<MMap> ParsedMMap = parseMMap(Node);
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());
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;
114 if (!MIL || MIL->Mod != MMap.Mod) {
115 endAnyModuleInfoLine();
118 beginModuleInfoLine(MMap.Mod);
121 MIL->MMaps.push_back(&MMap);
127 if (
Node.Tag !=
"reset")
129 if (!checkNumFields(
Node, 0))
132 if (!Modules.
empty() || !MMaps.empty()) {
133 endAnyModuleInfoLine();
137 OS <<
"[[[reset]]]" << lineEnding();
148 if (
Node.Tag !=
"module")
150 std::optional<Module> ParsedModule = parseModule(
Node);
155 ParsedModule->ID, std::make_unique<Module>(std::move(*ParsedModule)));
158 reportLocation(
Node.Fields[0].begin());
163 endAnyModuleInfoLine();
166 beginModuleInfoLine(&
Module);
172void MarkupFilter::beginModuleInfoLine(
const Module *M) {
174 OS <<
"[[[ELF module";
175 printValue(
formatv(
" #{0:x} ",
M->ID));
179 MIL = ModuleInfoLine{
M};
182void MarkupFilter::endAnyModuleInfoLine() {
186 return A->Addr < B->Addr;
188 for (
const MMap *M : MIL->MMaps) {
189 OS << (
M == MIL->MMaps.front() ?
' ' :
',');
191 printValue(
formatv(
"{0:x}",
M->Addr));
193 printValue(
formatv(
"{0:x}",
M->Addr +
M->Size - 1));
198 OS <<
"]]]" << lineEnding();
207 if (tryPresentation(
Node))
220 if (tryBackTrace(
Node))
222 return tryData(
Node);
226 if (
Node.Tag !=
"symbol")
228 if (!checkNumFields(
Node, 1))
238 if (
Node.Tag !=
"pc")
240 if (!checkNumFieldsAtLeast(
Node, 1))
242 if (!checkNumFieldsAtMost(
Node, 2))
245 std::optional<uint64_t>
Addr = parseAddr(
Node.Fields[0]);
251 PCType
Type = PCType::PreciseCode;
252 if (
Node.Fields.size() == 2) {
253 std::optional<PCType> ParsedType = parsePCType(
Node.Fields[1]);
260 const MMap *MMap = getContainingMMap(*
Addr);
263 reportLocation(
Node.Fields[0].begin());
264 printRawElement(
Node);
269 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
272 printRawElement(
Node);
276 printRawElement(
Node);
281 printValue(LI->FunctionName);
283 printValue(LI->FileName);
285 printValue(
Twine(LI->Line));
292 if (
Node.Tag !=
"bt")
294 if (!checkNumFieldsAtLeast(
Node, 2))
296 if (!checkNumFieldsAtMost(
Node, 3))
299 std::optional<uint64_t> FrameNumber = parseFrameNumber(
Node.Fields[0]);
303 std::optional<uint64_t>
Addr = parseAddr(
Node.Fields[1]);
308 PCType
Type = PCType::ReturnAddress;
309 if (
Node.Fields.size() == 3) {
310 std::optional<PCType> ParsedType = parsePCType(
Node.Fields[2]);
317 const MMap *MMap = getContainingMMap(*
Addr);
320 reportLocation(
Node.Fields[0].begin());
321 printRawElement(
Node);
330 printRawElement(
Node);
335 for (
unsigned I = 0,
E = II->getNumberOfFrames();
I !=
E; ++
I) {
336 auto Header =
formatv(
"{0, +6}",
formatv(
"#{0}", FrameNumber)).sstr<16>();
338 size_t NumberIdx = Header.find(
"#") + 1;
339 OS << Header.substr(0, NumberIdx);
340 printValue(Header.substr(NumberIdx));
345 printValue(
formatv(
"{0, -2}",
I + 1));
361 printValue(MMap->Mod->Name);
363 printValue(
formatv(
"{0:x}", MRA));
373 if (
Node.Tag !=
"data")
375 if (!checkNumFields(
Node, 1))
377 std::optional<uint64_t>
Addr = parseAddr(
Node.Fields[0]);
381 const MMap *MMap = getContainingMMap(*
Addr);
384 reportLocation(
Node.Fields[0].begin());
385 printRawElement(
Node);
390 MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)});
393 printRawElement(
Node);
404 if (
Node.Text ==
"\033[0m") {
408 if (
Node.Text ==
"\033[1m") {
436void MarkupFilter::highlight() {
445void MarkupFilter::highlightValue() {
453void MarkupFilter::restoreColor() {
466void MarkupFilter::resetColor() {
475void MarkupFilter::printRawElement(
const MarkupNode &Element) {
478 printValue(Element.
Tag);
496#define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR) \
497 auto NAME##Opt = (EXPR); \
499 return std::nullopt; \
500 TYPE NAME = std::move(*NAME##Opt)
502std::optional<MarkupFilter::Module>
503MarkupFilter::parseModule(
const MarkupNode &Element)
const {
504 if (!checkNumFieldsAtLeast(Element, 3))
511 reportLocation(
Type.begin());
514 if (!checkNumFields(Element, 4))
522std::optional<MarkupFilter::MMap>
523MarkupFilter::parseMMap(
const MarkupNode &Element)
const {
524 if (!checkNumFieldsAtLeast(Element, 3))
529 if (
Type !=
"load") {
531 reportLocation(
Type.begin());
534 if (!checkNumFields(Element, 6))
538 auto It = Modules.
find(
ID);
539 if (It == Modules.
end()) {
541 reportLocation(Element.
Fields[3].begin());
545 parseAddr(Element.
Fields[5]));
546 return MMap{
Addr,
Size, It->second.get(), std::move(Mode),
551std::optional<uint64_t> MarkupFilter::parseAddr(
StringRef Str)
const {
553 reportTypeError(Str,
"address");
556 if (
all_of(Str, [](
char C) {
return C ==
'0'; }))
558 if (!Str.startswith(
"0x")) {
559 reportTypeError(Str,
"address");
563 if (Str.drop_front(2).getAsInteger(16,
Addr)) {
564 reportTypeError(Str,
"address");
571std::optional<uint64_t> MarkupFilter::parseModuleID(
StringRef Str)
const {
573 if (Str.getAsInteger(0,
ID)) {
574 reportTypeError(Str,
"module ID");
581std::optional<uint64_t> MarkupFilter::parseSize(
StringRef Str)
const {
583 if (Str.getAsInteger(0,
ID)) {
584 reportTypeError(Str,
"size");
591std::optional<uint64_t> MarkupFilter::parseFrameNumber(
StringRef Str)
const {
593 if (Str.getAsInteger(10,
ID)) {
594 reportTypeError(Str,
"frame number");
604 reportTypeError(Str,
"build ID");
609std::optional<std::string> MarkupFilter::parseMode(
StringRef Str)
const {
611 reportTypeError(Str,
"mode");
617 if (!Remainder.
empty() && tolower(Remainder.
front()) ==
'r')
619 if (!Remainder.
empty() && tolower(Remainder.
front()) ==
'w')
621 if (!Remainder.
empty() && tolower(Remainder.
front()) ==
'x')
625 if (!Remainder.
empty()) {
626 reportTypeError(Str,
"mode");
634std::optional<MarkupFilter::PCType>
635MarkupFilter::parsePCType(
StringRef Str)
const {
636 std::optional<MarkupFilter::PCType>
Type =
638 .Case(
"ra", MarkupFilter::PCType::ReturnAddress)
639 .
Case(
"pc", MarkupFilter::PCType::PreciseCode)
642 reportTypeError(Str,
"PC type");
647 if (
any_of(
Node.Tag, [](
char C) { return C <
'a' || C >
'z'; })) {
649 reportLocation(
Node.Tag.begin());
655bool MarkupFilter::checkNumFields(
const MarkupNode &Element,
659 << Element.
Fields.size() <<
"\n";
660 reportLocation(Element.
Tag.
end());
666bool MarkupFilter::checkNumFieldsAtLeast(
const MarkupNode &Element,
670 <<
"expected at least " <<
Size <<
" field(s); found "
671 << Element.
Fields.size() <<
"\n";
672 reportLocation(Element.
Tag.
end());
678bool MarkupFilter::checkNumFieldsAtMost(
const MarkupNode &Element,
682 <<
"expected at most " <<
Size <<
" field(s); found "
683 << Element.
Fields.size() <<
"\n";
684 reportLocation(Element.
Tag.
end());
693 reportLocation(Str.begin());
707const MarkupFilter::MMap *
708MarkupFilter::getOverlappingMMap(
const MMap &Map)
const {
710 auto I = MMaps.upper_bound(
Map.Addr);
711 if (
I != MMaps.end() &&
Map.contains(
I->second.Addr))
716 if (
I != MMaps.begin()) {
718 if (
I->second.contains(
Map.Addr))
725const MarkupFilter::MMap *MarkupFilter::getContainingMMap(
uint64_t Addr)
const {
727 auto I = MMaps.lower_bound(
Addr);
728 if (
I != MMaps.end() &&
I->second.contains(
Addr))
732 if (
I == MMaps.begin())
735 return I->second.contains(
Addr) ? &
I->second :
nullptr;
743 return Type == MarkupFilter::PCType::ReturnAddress ?
Addr - 1 :
Addr;
746StringRef MarkupFilter::lineEnding()
const {
747 return Line.
endswith(
"\r\n") ?
"\r\n" :
"\n";
756 return Addr - this->Addr + ModuleRelativeAddr;
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.
#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 implements the StringSwitch template, which mimics a switch() statement whose cases are str...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&... Args)
Tagged union holding either a T or a Error.
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.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
char front() const
front - Get the first character in the string.
bool endswith(StringRef Suffix) const
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
An RAII object that temporarily switches an output stream to a specific color.
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
static 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.
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)
Expected< DILineInfo > symbolizeCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
Expected< DIGlobal > symbolizeData(const ObjectFile &Obj, object::SectionedAddress ModuleOffset)
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.
@ C
The default llvm calling convention, compatible with C.
BuildID parseBuildID(StringRef Str)
Parses a build ID from a hex string.
static std::string toHex(uint64_t V)
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
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.
std::string demangle(const std::string &MangledName)
Attempt to demangle a string using different demangling schemes.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
A format-neutral container for source line information.
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.