diff --git a/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll b/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll --- a/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll +++ b/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll @@ -5,6 +5,7 @@ ; Prologue. ; LINE: source_lines_test: +; LINE-NEXT: ; source_lines_test(): ; LINE-NEXT: ; {{.*}}source-lines.cl:1 ; Kernel. ; LINE: v_mov_b32_e32 v{{[0-9]+}}, 0x777 diff --git a/llvm/test/tools/llvm-objdump/Hexagon/source-interleave-hexagon.ll b/llvm/test/tools/llvm-objdump/Hexagon/source-interleave-hexagon.ll --- a/llvm/test/tools/llvm-objdump/Hexagon/source-interleave-hexagon.ll +++ b/llvm/test/tools/llvm-objdump/Hexagon/source-interleave-hexagon.ll @@ -66,6 +66,7 @@ !22 = !DILocation(line: 8, column: 13, scope: !14) !23 = !DILocation(line: 8, column: 3, scope: !14) ; LINES: main: +; LINES-NEXT: main(): ; LINES-NEXT: SRC_COMPDIR/source-interleave-hexagon.c:6 ; SOURCE: main: diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test @@ -0,0 +1,61 @@ +;; Verify that llvm-objdump -l also prints the function name in disassembly +;; output, getting it from the debug info. + +; RUN: llc < %s -o %t.o -filetype=obj -mtriple=x86_64-pc-linux +; RUN: llvm-objdump -d -l -C %t.o | FileCheck %s + +; RUN: llvm-strip %t.o -N foo -N _ZN3xyz3barEv -o %t-stripped.o +; RUN: llvm-objdump -d -l -C %t-stripped.o | FileCheck %s --check-prefix=STRIPPED + +; CHECK: 0000000000000000 foo: +; CHECK-NEXT: ; foo(): +; CHECK-NEXT: 0: b8 05 00 00 00 movl $5, %eax +; CHECK: 0000000000000010 xyz::bar(): +; CHECK-NEXT: ; _ZN3xyz3barEv(): +; CHECK-NEXT: ; /tmp/foo.c:2 +; CHECK-NEXT: 10: b8 0a 00 00 00 movl $10, %eax + +; STRIPPED: 0000000000000000 .text: +; STRIPPED-NEXT: ; Function1(): +; STRIPPED-NEXT: 0: b8 05 00 00 00 movl $5, %eax +; STRIPPED: ; _ZN3xyz3barEv(): +; STRIPPED-NEXT: ; /tmp/foo.c:2 +; STRIPPED-NEXT: 10: b8 0a 00 00 00 movl $10, %eax + +;; IR adapted from: +;; extern "C" int foo() { return 5; }; +;; namespace xyz { +;; int bar() { return 10; } +;; } // namespace xyz + +; ModuleID = '/tmp/foo.c' +source_filename = "/tmp/foo.c" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local i32 @foo() !dbg !7 { + ret i32 5, !dbg !12 +} + +define dso_local i32 @_ZN3xyz3barEv() !dbg !13 { + ret i32 10, !dbg !14 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang trunk", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +; Note: triggers a bad DILineInfo. We still print "Function1()". +!1 = !DIFile(filename: "", directory: "") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !{!"clang trunk"} +!7 = distinct !DISubprogram(name: "Function1", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DIFile(filename: "foo.c", directory: "/tmp") +!9 = !DISubroutineType(types: !10) +!10 = !{!11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DILocation(line: 1, column: 13, scope: !7) +!13 = distinct !DISubprogram(name: "_ZN3xyz3barEv", scope: !8, file: !8, line: 2, type: !9, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!14 = !DILocation(line: 2, column: 13, scope: !13) diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-x86_64.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-x86_64.test --- a/llvm/test/tools/llvm-objdump/X86/source-interleave-x86_64.test +++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-x86_64.test @@ -10,6 +10,7 @@ # RUN: FileCheck --check-prefix=SOURCE --strict-whitespace %s < %t2 # LINES: main: +# LINES-NEXT: ; main(): # LINES-NEXT: ; {{[ -\(\)_A-Za-z0-9.\\/:]+}}source-interleave-x86_64.c:6 # SOURCE: main: diff --git a/llvm/test/tools/llvm-objdump/embedded-source.test b/llvm/test/tools/llvm-objdump/embedded-source.test --- a/llvm/test/tools/llvm-objdump/embedded-source.test +++ b/llvm/test/tools/llvm-objdump/embedded-source.test @@ -13,6 +13,7 @@ ; } ; LINE: main: +; LINE-NEXT: ; main(): ; LINE-NEXT: ; {{.*}}embedded-source.c:1 ; LINE-NEXT: pushq %rbp ; LINE: ; {{.*}}embedded-source.c:2 diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -553,12 +553,19 @@ private: bool cacheSource(const DILineInfo& LineInfoFile); + void printLines(raw_ostream &OS, const DILineInfo &LineInfo, + StringRef Delimiter); + + void printSources(raw_ostream &OS, const DILineInfo &LineInfo, + StringRef ObjectFilename, StringRef Delimiter); + public: SourcePrinter() = default; SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj), WarnedNoDebugInfo(false) { symbolize::LLVMSymbolizer::Options SymbolizerOpts; - SymbolizerOpts.PrintFunctions = DILineInfoSpecifier::FunctionNameKind::None; + SymbolizerOpts.PrintFunctions = + DILineInfoSpecifier::FunctionNameKind::LinkageName; SymbolizerOpts.Demangle = false; SymbolizerOpts.DefaultArch = std::string(DefaultArch); Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts)); @@ -624,34 +631,51 @@ reportWarning(Warning, ObjectFilename); WarnedNoDebugInfo = true; } - return; } - if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) && - (OldLineInfo.FileName == LineInfo.FileName))) + if (OldLineInfo.Line == LineInfo.Line && + OldLineInfo.FileName == LineInfo.FileName && + OldLineInfo.FunctionName == LineInfo.FunctionName) return; if (PrintLines) + printLines(OS, LineInfo, Delimiter); + if (PrintSource) + printSources(OS, LineInfo, ObjectFilename, Delimiter); + OldLineInfo = LineInfo; +} + +void SourcePrinter::printLines(raw_ostream &OS, const DILineInfo &LineInfo, + StringRef Delimiter) { + if (LineInfo.FunctionName != DILineInfo::BadString && + LineInfo.FunctionName != OldLineInfo.FunctionName) + OS << Delimiter << LineInfo.FunctionName << "():\n"; + if (LineInfo.FileName != DILineInfo::BadString && LineInfo.Line != 0) OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n"; - if (PrintSource) { - if (SourceCache.find(LineInfo.FileName) == SourceCache.end()) - if (!cacheSource(LineInfo)) - return; - auto LineBuffer = LineCache.find(LineInfo.FileName); - if (LineBuffer != LineCache.end()) { - if (LineInfo.Line > LineBuffer->second.size()) { - reportWarning( - formatv( - "debug info line number {0} exceeds the number of lines in {1}", - LineInfo.Line, LineInfo.FileName), - ObjectFilename); - return; - } - // Vector begins at 0, line numbers are non-zero - OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n'; +} + +void SourcePrinter::printSources(raw_ostream &OS, const DILineInfo &LineInfo, + StringRef ObjectFilename, + StringRef Delimiter) { + if (LineInfo.FileName == DILineInfo::BadString || LineInfo.Line == 0) + return; + + if (SourceCache.find(LineInfo.FileName) == SourceCache.end()) + if (!cacheSource(LineInfo)) + return; + auto LineBuffer = LineCache.find(LineInfo.FileName); + if (LineBuffer != LineCache.end()) { + if (LineInfo.Line > LineBuffer->second.size()) { + reportWarning( + formatv( + "debug info line number {0} exceeds the number of lines in {1}", + LineInfo.Line, LineInfo.FileName), + ObjectFilename); + return; } + // Vector begins at 0, line numbers are non-zero + OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n'; } - OldLineInfo = LineInfo; } static bool isAArch64Elf(const ObjectFile *Obj) {