diff options
Diffstat (limited to 'tools/llvm-symbolizer/llvm-symbolizer.cpp')
-rw-r--r-- | tools/llvm-symbolizer/llvm-symbolizer.cpp | 161 |
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); |