Index: docs/CommandGuide/index.rst =================================================================== --- docs/CommandGuide/index.rst +++ docs/CommandGuide/index.rst @@ -31,6 +31,7 @@ llvm-profdata llvm-stress llvm-symbolizer + llvm-addr2line llvm-dwarfdump dsymutil llvm-mca Index: docs/CommandGuide/llvm-addr2line.md =================================================================== --- /dev/null +++ docs/CommandGuide/llvm-addr2line.md @@ -0,0 +1,53 @@ +# llvm-addr2line - a drop-in replacement for addr2line + +## SYNOPSIS + +**llvm-addr2line** [*options*] + +## DESCRIPTION + +**llvm-addr2line** is an alias for the [llvm-symbolizer](llvm-symbolizer) tool +with different defaults. The goal is to make it a drop-in replacement for +GNU's **addr2line**. + +Here are some of those differences: + +* Defaults not to print function names. Use [-f](llvm-symbolizer-opt-f) + to enable that. + +* Defaults not to demangle function names. Use [-C](llvm-symbolizer-opt-C) + to switch the demangling on. + +* Defaults not to print inlined frames. Use [-i](llvm-symbolizer-opt-i) + to show inlined frames for a source code location in an inlined function. + +* Never overrides the name of an inlined function even if + [-use-symbol-table](llvm-symbolizer-opt-use-symbol-table) is on. For example: + + ```console + $ llvm-symbolizer -p -e=a.out 0x40054d + inc at /tmp/x.c:3:3 + (inlined by) main at /tmp/x.c:9:0 + + $ llvm-symbolizer -p -i=0 -e=a.out 0x40054d + main at /tmp/x.c:3:3 + + $ llvm-symbolizer -p -i=0 -use-symbol-table=0 -e=a.out 0x40054d + inc at /tmp/x.c:3:3 + + $ llvm-addr2line -pfi -e=a.out 0x40054d + inc at /tmp/x.c:3 + (inlined by) main at /tmp/x.c:9 + + $ llvm-addr2line -pf -use-symbol-table=0 -e=a.out 0x40054d + inc at /tmp/x.c:3 + + $ llvm-addr2line -pf -use-symbol-table=1 -e=a.out 0x40054d + inc at /tmp/x.c:3 + ``` + +* Does not print column of a source code location. + +## SEE ALSO + +Refer to [llvm-symbolizer](llvm-symbolizer) for additional information. Index: docs/CommandGuide/llvm-symbolizer.rst =================================================================== --- docs/CommandGuide/llvm-symbolizer.rst +++ docs/CommandGuide/llvm-symbolizer.rst @@ -72,17 +72,23 @@ Path to object file to be symbolized. +.. _llvm-symbolizer-opt-f: + .. option:: -functions[=], -f Specify the way function names are printed (omit function name, print short function name, or print full linkage name, respectively). Defaults to ``linkage``. +.. _llvm-symbolizer-opt-use-symbol-table: + .. option:: -use-symbol-table Prefer function names stored in symbol table to function names in debug info sections. Defaults to true. +.. _llvm-symbolizer-opt-C: + .. option:: -demangle, -C Print demangled function names. Defaults to true. @@ -91,6 +97,8 @@ Don't print demangled function names. +.. _llvm-symbolizer-opt-i: + .. option:: -inlining, -inlines, -i If a source code location is in an inlined function, prints all the Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -45,6 +45,7 @@ llc lli lli-child-target + llvm-addr2line llvm-ar llvm-as llvm-bcanalyzer Index: test/tools/llvm-symbolizer/demangle.s =================================================================== --- test/tools/llvm-symbolizer/demangle.s +++ test/tools/llvm-symbolizer/demangle.s @@ -25,5 +25,11 @@ # RUN: llvm-symbolizer --no-demangle -C --obj %t.o 0 \ # RUN: | FileCheck %s --check-prefix=DEMANGLED_FUNCTION_NAME +# Check that for llvm-addr2line the default is not to demangle. +# RUN: llvm-addr2line -fe %t.o 0 \ +# RUN: | FileCheck %s --check-prefix=MANGLED_FUNCTION_NAME +# RUN: llvm-addr2line -fCe %t.o 0 \ +# RUN: | FileCheck %s --check-prefix=DEMANGLED_FUNCTION_NAME + # MANGLED_FUNCTION_NAME: _Z1cv # DEMANGLED_FUNCTION_NAME: c() Index: test/tools/llvm-symbolizer/help.test =================================================================== --- /dev/null +++ test/tools/llvm-symbolizer/help.test @@ -0,0 +1,8 @@ +RUN: llvm-symbolizer -help | FileCheck %s --check-prefix=SYMBOLIZER +RUN: llvm-addr2line -help | FileCheck %s --check-prefix=ADDR2LINE + +SYMBOLIZER: OVERVIEW: llvm-symbolizer +SYMBOLIZER: USAGE: llvm-symbolizer{{(.exe)?}} [options] ... + +ADDR2LINE: OVERVIEW: llvm-addr2line +ADDR2LINE: USAGE: llvm-addr2line{{(.exe)?}} [options] ... Index: test/tools/llvm-symbolizer/output-style.test =================================================================== --- test/tools/llvm-symbolizer/output-style.test +++ test/tools/llvm-symbolizer/output-style.test @@ -7,5 +7,14 @@ RUN: llvm-symbolizer --output-style=LLVM -e %p/Inputs/addr.exe 0x40054d \ RUN: | FileCheck %s --check-prefix=LLVM +RUN: llvm-addr2line -e %p/Inputs/addr.exe 0x40054d \ +RUN: | FileCheck %s --check-prefix=GNU + +RUN: llvm-addr2line --output-style=GNU -e %p/Inputs/addr.exe 0x40054d \ +RUN: | FileCheck %s --check-prefix=GNU + +RUN: llvm-addr2line --output-style=LLVM -e %p/Inputs/addr.exe 0x40054d \ +RUN: | FileCheck %s --check-prefix=LLVM + LLVM: {{^}}/tmp{{\\|/}}x.c:3:3{{$}} GNU: {{^}}/tmp{{\\|/}}x.c:3{{$}} Index: test/tools/llvm-symbolizer/sym.test =================================================================== --- test/tools/llvm-symbolizer/sym.test +++ test/tools/llvm-symbolizer/sym.test @@ -29,6 +29,19 @@ RUN: echo "0x1" > %t.input RUN: llvm-symbolizer -obj=%p/Inputs/zero < %t.input | FileCheck -check-prefix="ZERO" %s +RUN: llvm-addr2line -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefix=A2L %s +RUN: llvm-addr2line -a -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_A %s +RUN: llvm-addr2line -f -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_F %s +RUN: llvm-addr2line -i -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_I %s +RUN: llvm-addr2line -fi -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_F,A2L_I,A2L_FI %s + +RUN: llvm-addr2line -pa -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_A %s +RUN: llvm-addr2line -pf -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_F %s +RUN: llvm-addr2line -paf -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_AF %s +RUN: llvm-addr2line -pai -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_A,A2LP_I %s +RUN: llvm-addr2line -pfi -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_F,A2LP_FI %s +RUN: llvm-addr2line -pafi -obj=%p/Inputs/addr.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_AF,A2LP_FI %s + #CHECK: some text #CHECK: 0x40054d #CHECK: main @@ -43,3 +56,23 @@ # #ZERO: ?? #ZERO: ??:0:0 +# +#A2L: some text +#A2L_A-NEXT: 0x40054d +#A2L_F-NEXT: inctwo +#A2L-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}} +#A2L_FI-NEXT: inc{{$}} +#A2L_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}} +#A2L_FI-NEXT: main +#A2L_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}} +#A2L-NEXT: some text2 + +#A2LP: some text +#A2LP_A-NEXT: 0x40054d: {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}} +#A2LP_F-NEXT: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}} +#A2LP_AF-NEXT: 0x40054d: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}} +#A2LP_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}} +#A2LP_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}} +#A2LP_FI-NEXT: (inlined by) inc at {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}} +#A2LP_FI-NEXT: (inlined by) main at {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}} +#A2LP-NEXT: some text2 Index: tools/llvm-symbolizer/CMakeLists.txt =================================================================== --- tools/llvm-symbolizer/CMakeLists.txt +++ tools/llvm-symbolizer/CMakeLists.txt @@ -16,6 +16,8 @@ llvm-symbolizer.cpp ) +add_llvm_tool_symlink(llvm-addr2line llvm-symbolizer) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) add_llvm_tool_symlink(addr2line llvm-symbolizer) endif() Index: tools/llvm-symbolizer/llvm-symbolizer.cpp =================================================================== --- tools/llvm-symbolizer/llvm-symbolizer.cpp +++ tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -43,7 +43,7 @@ clEnumValN(FunctionNameKind::ShortName, "short", "print short function name"), clEnumValN(FunctionNameKind::LinkageName, "linkage", - "print function linkage name (default)"), + "print function linkage name"), // Sentinel value for unspecified value. clEnumValN(FunctionNameKind::LinkageName, "", ""))); static cl::alias ClPrintFunctionsShort("f", cl::desc("Alias for -functions"), @@ -202,7 +202,7 @@ } static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer, - DIPrinter &Printer) { + DIPrinter &Printer, bool IsAddr2Line) { bool IsData = false; std::string ModuleName; uint64_t Offset = 0; @@ -227,21 +227,43 @@ ModuleName, {Offset, object::SectionedAddress::UndefSection}, ClDwpName); Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get()); + } else if (IsAddr2Line) { + // 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}, + ClDwpName); + Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get().getFrame(0)); } else { auto ResOrErr = Symbolizer.symbolizeCode( ModuleName, {Offset, object::SectionedAddress::UndefSection}, ClDwpName); Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get()); } - outs() << "\n"; + if (ClOutputStyle == DIPrinter::OutputStyle::LLVM) + outs() << "\n"; outs().flush(); } 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, "llvm-symbolizer\n"); + cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n" + : "llvm-symbolizer\n"); // If both --demangle and --no-demangle are specified then pick the last one. if (ClNoDemangle.getPosition() > ClDemangle.getPosition()) @@ -270,10 +292,10 @@ char InputString[kMaxInputStringLength]; while (fgets(InputString, sizeof(InputString), stdin)) - symbolizeInput(InputString, Symbolizer, Printer); + symbolizeInput(InputString, Symbolizer, Printer, IsAddr2Line); } else { for (StringRef Address : ClInputAddresses) - symbolizeInput(Address, Symbolizer, Printer); + symbolizeInput(Address, Symbolizer, Printer, IsAddr2Line); } return 0;