diff options
author | Daniel Thornburgh <dthorn@google.com> | 2022-08-01 14:35:25 -0700 |
---|---|---|
committer | Daniel Thornburgh <dthorn@google.com> | 2022-08-08 11:08:48 -0700 |
commit | bf48b128b02813e53e0c8f6585db837d14c9358f (patch) | |
tree | 2673e2306bea1d3a8f1ec05617671dc854170656 /llvm/lib | |
parent | 257251247a267c3fa30fdeef17ffa4987d8a52e5 (diff) | |
download | llvm-bf48b128b02813e53e0c8f6585db837d14c9358f.zip llvm-bf48b128b02813e53e0c8f6585db837d14c9358f.tar.gz llvm-bf48b128b02813e53e0c8f6585db837d14c9358f.tar.bz2 |
[Symbolizer] Implement pc element in symbolizing filter.
Implements the pc element for the symbolizing filter, including it's
"ra" and "pc" modes. Return addresses ("ra") are adjusted by
decrementing one. By default, {{{pc}}} elements are assumed to point to
precise code ("pc") locations. Backtrace elements will adopt the
opposite convention.
Along the way, some minor refactors of value printing and colorization.
Reviewed By: peter.smith
Differential Revision: https://reviews.llvm.org/D131115
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp | 145 |
1 files changed, 120 insertions, 25 deletions
diff --git a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp index 2bf2e17..70fb49d 100644 --- a/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp +++ b/llvm/lib/DebugInfo/Symbolize/MarkupFilter.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/Symbolize/Markup.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Debuginfod/Debuginfod.h" @@ -163,18 +164,17 @@ bool MarkupFilter::tryModule(const MarkupNode &Node, filterNode(Node); beginModuleInfoLine(&Module); OS << "; BuildID="; - highlightValue(); - OS << toHex(Module.BuildID, /*LowerCase=*/true); - highlight(); + printValue(toHex(Module.BuildID, /*LowerCase=*/true)); return true; } void MarkupFilter::beginModuleInfoLine(const Module *M) { highlight(); OS << "[[[ELF module"; - highlightValue(); - OS << formatv(" #{0:x} \"{1}\"", M->ID, M->Name); - highlight(); + printValue(formatv(" #{0:x} ", M->ID)); + OS << '"'; + printValue(M->Name); + OS << '"'; MIL = ModuleInfoLine{M}; } @@ -186,13 +186,12 @@ void MarkupFilter::endAnyModuleInfoLine() { }); for (const MMap *M : MIL->MMaps) { OS << (M == MIL->MMaps.front() ? ' ' : ','); - highlightValue(); - OS << formatv("[{0:x}-{1:x}]", M->Addr, M->Addr + M->Size - 1); - highlight(); - OS << '('; - highlightValue(); - OS << M->Mode; - highlight(); + OS << '['; + printValue(formatv("{0:x}", M->Addr)); + OS << '-'; + printValue(formatv("{0:x}", M->Addr + M->Size - 1)); + OS << "]("; + printValue(M->Mode); OS << ')'; } OS << "]]]" << lineEnding(); @@ -215,6 +214,8 @@ void MarkupFilter::filterNode(const MarkupNode &Node) { bool MarkupFilter::tryPresentation(const MarkupNode &Node) { if (trySymbol(Node)) return true; + if (tryPC(Node)) + return true; return tryData(Node); } @@ -230,6 +231,61 @@ bool MarkupFilter::trySymbol(const MarkupNode &Node) { return true; } +bool MarkupFilter::tryPC(const MarkupNode &Node) { + if (Node.Tag != "pc") + return false; + if (!checkNumFieldsAtLeast(Node, 1)) + return true; + if (!checkNumFieldsAtMost(Node, 2)) + return true; + + Optional<uint64_t> Addr = parseAddr(Node.Fields[0]); + if (!Addr) + return true; + + // PC addresses that aren't part of a backtrace are assumed to be precise code + // locations. + PCType Type = PCType::PreciseCode; + if (Node.Fields.size() == 2) { + Optional<PCType> ParsedType = parsePCType(Node.Fields[1]); + if (!ParsedType) + return true; + Type = *ParsedType; + } + *Addr = adjustAddr(*Addr, Type); + + const MMap *MMap = getContainingMMap(*Addr); + if (!MMap) { + WithColor::error() << "no mmap covers address\n"; + reportLocation(Node.Fields[0].begin()); + printRawElement(Node); + return true; + } + + Expected<DILineInfo> LI = Symbolizer.symbolizeCode( + MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)}); + if (!LI) { + WithColor::defaultErrorHandler(LI.takeError()); + printRawElement(Node); + return true; + } + if (LI->FileName == DILineInfo::BadString && + LI->FunctionName == DILineInfo::BadString && LI->Line == 0) { + printRawElement(Node); + return true; + } + + highlight(); + printValue(LI->FunctionName); + OS << '['; + printValue(LI->FileName); + OS << ':'; + printValue(Twine(LI->Line)); + OS << ']'; + restoreColor(); + return true; +} + bool MarkupFilter::tryData(const MarkupNode &Node) { if (Node.Tag != "data") return false; @@ -239,21 +295,11 @@ bool MarkupFilter::tryData(const MarkupNode &Node) { if (!Addr) return true; - const auto PrintRaw = [&]() { - highlight(); - OS << "[[[data:"; - highlightValue(); - OS << "0x" << toHex(*Addr, /*LowerCase=*/true); - highlight(); - OS << "]]]\n"; - restoreColor(); - }; - const MMap *MMap = getContainingMMap(*Addr); if (!MMap) { WithColor::error() << "no mmap covers address\n"; reportLocation(Node.Fields[0].begin()); - PrintRaw(); + printRawElement(Node); return true; } @@ -261,7 +307,7 @@ bool MarkupFilter::tryData(const MarkupNode &Node) { MMap->Mod->BuildID, {MMap->getModuleRelativeAddr(*Addr)}); if (!Symbol) { WithColor::defaultErrorHandler(Symbol.takeError()); - PrintRaw(); + printRawElement(Node); return true; } @@ -343,6 +389,24 @@ void MarkupFilter::resetColor() { OS.resetColor(); } +void MarkupFilter::printRawElement(const MarkupNode &Element) { + highlight(); + OS << "[[["; + printValue(Element.Tag); + for (StringRef Field : Element.Fields) { + OS << ':'; + printValue(Field); + } + OS << "]]]"; + restoreColor(); +} + +void MarkupFilter::printValue(Twine Value) { + highlightValue(); + OS << Value; + highlight(); +} + // This macro helps reduce the amount of indirection done through Optional // below, since the usual case upon returning a None Optional is to return None. #define ASSIGN_OR_RETURN_NONE(TYPE, NAME, EXPR) \ @@ -476,6 +540,17 @@ Optional<std::string> MarkupFilter::parseMode(StringRef Str) const { return Str.lower(); } +Optional<MarkupFilter::PCType> MarkupFilter::parsePCType(StringRef Str) const { + Optional<MarkupFilter::PCType> Type = + StringSwitch<Optional<MarkupFilter::PCType>>(Str) + .Case("ra", MarkupFilter::PCType::ReturnAddress) + .Case("pc", MarkupFilter::PCType::PreciseCode) + .Default(None); + if (!Type) + reportTypeError(Str, "PC type"); + return Type; +} + bool MarkupFilter::checkTag(const MarkupNode &Node) const { if (any_of(Node.Tag, [](char C) { return C < 'a' || C > 'z'; })) { WithColor::error(errs()) << "tags must be all lowercase characters\n"; @@ -508,6 +583,18 @@ bool MarkupFilter::checkNumFieldsAtLeast(const MarkupNode &Element, return true; } +bool MarkupFilter::checkNumFieldsAtMost(const MarkupNode &Element, + size_t Size) const { + if (Element.Fields.size() > Size) { + WithColor::error(errs()) + << "expected at most " << Size << " field(s); found " + << Element.Fields.size() << "\n"; + reportLocation(Element.Tag.end()); + return false; + } + return true; +} + void MarkupFilter::reportTypeError(StringRef Str, StringRef TypeName) const { WithColor::error(errs()) << "expected " << TypeName << "; found '" << Str << "'\n"; @@ -556,6 +643,14 @@ const MarkupFilter::MMap *MarkupFilter::getContainingMMap(uint64_t Addr) const { return I->second.contains(Addr) ? &I->second : nullptr; } +uint64_t MarkupFilter::adjustAddr(uint64_t Addr, PCType Type) const { + // Decrementing return addresses by one moves them into the call instruction. + // The address doesn't have to be the start of the call instruction, just some + // byte on the inside. Subtracting one avoids needing detailed instruction + // length information here. + return Type == MarkupFilter::PCType::ReturnAddress ? Addr - 1 : Addr; +} + StringRef MarkupFilter::lineEnding() const { return Line.endswith("\r\n") ? "\r\n" : "\n"; } |