aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-symbolizer/llvm-symbolizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-symbolizer/llvm-symbolizer.cpp')
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp161
1 files changed, 126 insertions, 35 deletions
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 9d19f994b739..ea94cf9b69a1 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,9 +1,8 @@
//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -39,12 +38,17 @@ ClUseSymbolTable("use-symbol-table", cl::init(true),
static cl::opt<FunctionNameKind> ClPrintFunctions(
"functions", cl::init(FunctionNameKind::LinkageName),
- cl::desc("Print function name for a given address:"),
+ cl::desc("Print function name for a given address"), cl::ValueOptional,
cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"),
clEnumValN(FunctionNameKind::ShortName, "short",
"print short function name"),
clEnumValN(FunctionNameKind::LinkageName, "linkage",
- "print function linkage name")));
+ "print function linkage name"),
+ // Sentinel value for unspecified value.
+ clEnumValN(FunctionNameKind::LinkageName, "", "")));
+static cl::alias ClPrintFunctionsShort("f", cl::desc("Alias for -functions"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(ClPrintFunctions));
static cl::opt<bool>
ClUseRelativeAddress("relative-address", cl::init(false),
@@ -54,13 +58,29 @@ static cl::opt<bool>
static cl::opt<bool>
ClPrintInlining("inlining", cl::init(true),
cl::desc("Print all inlined frames for a given address"));
+static cl::alias
+ ClPrintInliningAliasI("i", cl::desc("Alias for -inlining"),
+ cl::NotHidden, cl::aliasopt(ClPrintInlining),
+ cl::Grouping);
+static cl::alias
+ ClPrintInliningAliasInlines("inlines", cl::desc("Alias for -inlining"),
+ cl::NotHidden, cl::aliasopt(ClPrintInlining));
-// -demangle, -C
+// -basenames, -s
+static cl::opt<bool> ClBasenames("basenames", cl::init(false),
+ cl::desc("Strip directory names from paths"));
+static cl::alias ClBasenamesShort("s", cl::desc("Alias for -basenames"),
+ cl::NotHidden, cl::aliasopt(ClBasenames));
+
+// -demangle, -C, -no-demangle
static cl::opt<bool>
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
static cl::alias
ClDemangleShort("C", cl::desc("Alias for -demangle"),
- cl::NotHidden, cl::aliasopt(ClDemangle));
+ cl::NotHidden, cl::aliasopt(ClDemangle), cl::Grouping);
+static cl::opt<bool>
+ClNoDemangle("no-demangle", cl::init(false),
+ cl::desc("Don't demangle function names"));
static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
cl::desc("Default architecture "
@@ -74,10 +94,9 @@ ClBinaryName("obj", cl::init(""),
static cl::alias
ClBinaryNameAliasExe("exe", cl::desc("Alias for -obj"),
cl::NotHidden, cl::aliasopt(ClBinaryName));
-static cl::alias
-ClBinaryNameAliasE("e", cl::desc("Alias for -obj"),
- cl::NotHidden, cl::aliasopt(ClBinaryName));
-
+static cl::alias ClBinaryNameAliasE("e", cl::desc("Alias for -obj"),
+ cl::NotHidden, cl::Grouping, cl::Prefix,
+ cl::aliasopt(ClBinaryName));
static cl::opt<std::string>
ClDwpName("dwp", cl::init(""),
@@ -97,7 +116,7 @@ ClPrintAddressAliasAddresses("addresses", cl::desc("Alias for -print-address"),
cl::NotHidden, cl::aliasopt(ClPrintAddress));
static cl::alias
ClPrintAddressAliasA("a", cl::desc("Alias for -print-address"),
- cl::NotHidden, cl::aliasopt(ClPrintAddress));
+ cl::NotHidden, cl::aliasopt(ClPrintAddress), cl::Grouping);
// -pretty-print, -p
static cl::opt<bool>
@@ -105,7 +124,7 @@ static cl::opt<bool>
cl::desc("Make the output more human friendly"));
static cl::alias ClPrettyPrintShort("p", cl::desc("Alias for -pretty-print"),
cl::NotHidden,
- cl::aliasopt(ClPrettyPrint));
+ cl::aliasopt(ClPrettyPrint), cl::Grouping);
static cl::opt<int> ClPrintSourceContextLines(
"print-source-context-lines", cl::init(0),
@@ -114,10 +133,30 @@ static cl::opt<int> ClPrintSourceContextLines(
static cl::opt<bool> ClVerbose("verbose", cl::init(false),
cl::desc("Print verbose line info"));
+// -adjust-vma
+static cl::opt<uint64_t>
+ ClAdjustVMA("adjust-vma", cl::init(0), cl::value_desc("offset"),
+ cl::desc("Add specified offset to object file addresses"));
+
static cl::list<std::string> ClInputAddresses(cl::Positional,
cl::desc("<input addresses>..."),
cl::ZeroOrMore);
+static cl::opt<std::string>
+ ClFallbackDebugPath("fallback-debug-path", cl::init(""),
+ cl::desc("Fallback path for debug binaries."));
+
+static cl::opt<DIPrinter::OutputStyle>
+ ClOutputStyle("output-style", cl::init(DIPrinter::OutputStyle::LLVM),
+ cl::desc("Specify print style"),
+ cl::values(clEnumValN(DIPrinter::OutputStyle::LLVM, "LLVM",
+ "LLVM default style"),
+ clEnumValN(DIPrinter::OutputStyle::GNU, "GNU",
+ "GNU addr2line style")));
+
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
+
template<typename T>
static bool error(Expected<T> &ResOrErr) {
if (ResOrErr)
@@ -127,17 +166,25 @@ static bool error(Expected<T> &ResOrErr) {
return true;
}
-static bool parseCommand(StringRef InputString, bool &IsData,
+enum class Command {
+ Code,
+ Data,
+ Frame,
+};
+
+static bool parseCommand(StringRef InputString, Command &Cmd,
std::string &ModuleName, uint64_t &ModuleOffset) {
const char kDelimiters[] = " \n\r";
ModuleName = "";
if (InputString.consume_front("CODE ")) {
- IsData = false;
+ Cmd = Command::Code;
} else if (InputString.consume_front("DATA ")) {
- IsData = true;
+ Cmd = Command::Data;
+ } else if (InputString.consume_front("FRAME ")) {
+ Cmd = Command::Frame;
} else {
// If no cmd, assume it's CODE.
- IsData = false;
+ Cmd = Command::Code;
}
const char *pos = InputString.data();
// Skip delimiters and parse input filename (if needed).
@@ -167,44 +214,85 @@ static bool parseCommand(StringRef InputString, bool &IsData,
static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer,
DIPrinter &Printer) {
- bool IsData = false;
+ Command Cmd;
std::string ModuleName;
- uint64_t ModuleOffset = 0;
- if (!parseCommand(StringRef(InputString), IsData, ModuleName, ModuleOffset)) {
+ uint64_t Offset = 0;
+ if (!parseCommand(StringRef(InputString), Cmd, ModuleName, Offset)) {
outs() << InputString;
return;
}
if (ClPrintAddress) {
outs() << "0x";
- outs().write_hex(ModuleOffset);
+ outs().write_hex(Offset);
StringRef Delimiter = ClPrettyPrint ? ": " : "\n";
outs() << Delimiter;
}
- if (IsData) {
- auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
+ Offset -= ClAdjustVMA;
+ if (Cmd == Command::Data) {
+ auto ResOrErr = Symbolizer.symbolizeData(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
+ } else if (Cmd == Command::Frame) {
+ auto ResOrErr = Symbolizer.symbolizeFrame(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ if (!error(ResOrErr)) {
+ for (DILocal Local : *ResOrErr)
+ Printer << Local;
+ if (ResOrErr->empty())
+ outs() << "??\n";
+ }
} else if (ClPrintInlining) {
- auto ResOrErr =
- Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset, ClDwpName);
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
+ } else if (ClOutputStyle == DIPrinter::OutputStyle::GNU) {
+ // With ClPrintFunctions == FunctionNameKind::LinkageName (default)
+ // and ClUseSymbolTable == true (also default), Symbolizer.symbolizeCode()
+ // may override the name of an inlined function with the name of the topmost
+ // caller function in the inlining chain. This contradicts the existing
+ // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
+ // the topmost function, which suits our needs better.
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get().getFrame(0));
} else {
- auto ResOrErr =
- Symbolizer.symbolizeCode(ModuleName, ModuleOffset, ClDwpName);
+ auto ResOrErr = Symbolizer.symbolizeCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
}
- outs() << "\n";
- outs().flush();
+ if (ClOutputStyle == DIPrinter::OutputStyle::LLVM)
+ outs() << "\n";
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
+ bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line");
+
+ if (IsAddr2Line) {
+ ClDemangle.setInitialValue(false);
+ ClPrintFunctions.setInitialValue(FunctionNameKind::None);
+ ClPrintInlining.setInitialValue(false);
+ ClOutputStyle.setInitialValue(DIPrinter::OutputStyle::GNU);
+ }
+
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+ cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n"
+ : "llvm-symbolizer\n");
- cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n");
- LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, ClDemangle,
- ClUseRelativeAddress, ClDefaultArch);
+ // If both --demangle and --no-demangle are specified then pick the last one.
+ if (ClNoDemangle.getPosition() > ClDemangle.getPosition())
+ ClDemangle = !ClNoDemangle;
+
+ LLVMSymbolizer::Options Opts;
+ Opts.PrintFunctions = ClPrintFunctions;
+ Opts.UseSymbolTable = ClUseSymbolTable;
+ Opts.Demangle = ClDemangle;
+ Opts.RelativeAddresses = ClUseRelativeAddress;
+ Opts.DefaultArch = ClDefaultArch;
+ Opts.FallbackDebugPath = ClFallbackDebugPath;
+ Opts.DWPName = ClDwpName;
for (const auto &hint : ClDsymHint) {
if (sys::path::extension(hint) == ".dSYM") {
@@ -217,14 +305,17 @@ int main(int argc, char **argv) {
LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None,
- ClPrettyPrint, ClPrintSourceContextLines, ClVerbose);
+ ClPrettyPrint, ClPrintSourceContextLines, ClVerbose,
+ ClBasenames, ClOutputStyle);
if (ClInputAddresses.empty()) {
const int kMaxInputStringLength = 1024;
char InputString[kMaxInputStringLength];
- while (fgets(InputString, sizeof(InputString), stdin))
+ while (fgets(InputString, sizeof(InputString), stdin)) {
symbolizeInput(InputString, Symbolizer, Printer);
+ outs().flush();
+ }
} else {
for (StringRef Address : ClInputAddresses)
symbolizeInput(Address, Symbolizer, Printer);