aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib
diff options
context:
space:
mode:
authorDaniel Thornburgh <dthorn@google.com>2022-08-01 14:35:25 -0700
committerDaniel Thornburgh <dthorn@google.com>2022-08-08 11:08:48 -0700
commitbf48b128b02813e53e0c8f6585db837d14c9358f (patch)
tree2673e2306bea1d3a8f1ec05617671dc854170656 /llvm/lib
parent257251247a267c3fa30fdeef17ffa4987d8a52e5 (diff)
downloadllvm-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.cpp145
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";
}