[llvm] 266877a - [llvm-objdump] Print method name from debug info in disassembly output.

Jordan Rupprecht via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 21 15:32:22 PST 2020


Author: Jordan Rupprecht
Date: 2020-02-21T15:30:51-08:00
New Revision: 266877a2a8b2d1939f3b08fcfb711890fefc96e3

URL: https://github.com/llvm/llvm-project/commit/266877a2a8b2d1939f3b08fcfb711890fefc96e3
DIFF: https://github.com/llvm/llvm-project/commit/266877a2a8b2d1939f3b08fcfb711890fefc96e3.diff

LOG: [llvm-objdump] Print method name from debug info in disassembly output.

Summary:
GNU objdump prints the method name in disassembly output, and upon further investigation this seems to come from debug info, not the symbol table.

Some additional refactoring is necessary to make this work even when the line number is 0/the filename is unknown. The added test case includes a note for this scenario.

See http://llvm.org/PR41341 for more info.

Reviewers: dblaikie, MaskRay, jhenderson

Reviewed By: MaskRay

Subscribers: ormris, jvesely, aprantl, kerbowa, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74507

Added: 
    llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test

Modified: 
    llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll
    llvm/test/tools/llvm-objdump/Hexagon/source-interleave-hexagon.ll
    llvm/test/tools/llvm-objdump/X86/source-interleave-x86_64.test
    llvm/test/tools/llvm-objdump/embedded-source.test
    llvm/tools/llvm-objdump/llvm-objdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll b/llvm/test/tools/llvm-objdump/AMDGPU/source-lines.ll
index 2e31f6612346..2c5900858a42 100644
--- 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
index 35ca7065e6a5..69058f4baa3d 100644
--- 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 @@ attributes #1 = { nounwind readnone }
 !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
index 000000000000..bbf38f8956f6
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-function-from-debug.test
@@ -0,0 +1,108 @@
+;; 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-unknown-linux-gnu
+; RUN: llvm-objdump -dl %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DEMANGLE
+
+; RUN: llc < %s -o %t.o -filetype=obj -mtriple=x86_64-unknown-linux-gnu
+; RUN: llvm-objdump -dlC %t.o | FileCheck %s --check-prefixes=CHECK,CHECK-DEMANGLE
+
+; CHECK:      0000000000000000 foo:
+; CHECK-NEXT: ; foo():
+; CHECK-NEXT: ; /tmp/src.cc:1
+; CHECK-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
+; CHECK-NEXT:        5: c3                            retq
+
+; CHECK-NO-DEMANGLE:      0000000000000010 _ZN3xyz3barEv:
+; CHECK-NO-DEMANGLE-NEXT: ; _ZN3xyz3barEv():
+; CHECK-DEMANGLE:         0000000000000010 xyz::bar():
+; CHECK-DEMANGLE-NEXT:    ; xyz::bar():
+
+; CHECK-NEXT: ; /tmp/src.cc:3
+; CHECK-NEXT:       10: b8 0a 00 00 00                movl    $10, %eax
+; CHECK-NEXT:       15: c3                            retq
+
+; CHECK-NO-DEMANGLE:      0000000000000020 _ZN3xyz3bazEv:
+; CHECK-NO-DEMANGLE-NEXT: ; _ZN3xyz3bazEv():
+; CHECK-DEMANGLE:         0000000000000020 xyz::baz():
+; CHECK-DEMANGLE-NEXT:    ; xyz::baz():
+
+; CHECK-NEXT: ; /tmp/src.cc:3
+; CHECK-NEXT:       20: b8 14 00 00 00                movl    $20, %eax
+; CHECK-NEXT:       25: c3                            retq
+
+;; When symbol information is missing, we can get function names from debug
+;; info. The IR is intentionally doctored to have 
diff erent names in debug info
+;; for the test case here.
+; RUN: llvm-strip %t.o -N foo -N _ZN3xyz3barEv -N _ZN3xyz3bazEv -o %t-stripped.o
+; RUN: llvm-objdump -dlC %t-stripped.o | FileCheck %s --check-prefix=STRIPPED
+
+; STRIPPED:      0000000000000000 .text:
+; STRIPPED-NEXT: ; Function1():
+; STRIPPED-NEXT: ; /tmp/src.cc:1
+; STRIPPED-NEXT:        0: b8 05 00 00 00                movl    $5, %eax
+; STRIPPED-NEXT:        5: c3                            retq
+
+; STRIPPED:      ; xyz::bar():
+; STRIPPED-NEXT: ; /tmp/src.cc:3
+; STRIPPED-NEXT:       10: b8 0a 00 00 00                movl    $10, %eax
+; STRIPPED-NEXT:       15: c3                            retq
+
+; STRIPPED:      ; xyz::baz():
+; STRIPPED-NEXT: ; /tmp/src.cc:3
+; STRIPPED-NEXT:       20: b8 14 00 00 00                movl    $20, %eax
+; STRIPPED-NEXT:       25: c3                            retq
+
+;; IR adapted from:
+;; $ cat /tmp/src.cc
+;; extern "C" int foo() { return 5; };
+;; namespace xyz {
+;; int bar() { return 10; } int baz() { return 20; }
+;; } // namespace xyz
+;; $ clang++ -O -g -c /tmp/src.cc -S -emit-llvm
+;; Note: bar() and baz() intentionally written on the same line.
+
+; ModuleID = '/tmp/src.cc'
+source_filename = "/tmp/src.cc"
+target triple = "x86_64-unknown-linux-gnu"
+
+define dso_local i32 @foo() #0 !dbg !7 {
+entry:
+  ret i32 5, !dbg !12
+}
+
+define dso_local i32 @_ZN3xyz3barEv() #0 !dbg !13 {
+entry:
+  ret i32 10, !dbg !15
+}
+
+define dso_local i32 @_ZN3xyz3bazEv() #0 !dbg !16 {
+entry:
+  ret i32 20, !dbg !17
+}
+
+attributes #0 = { "frame-pointer"="none" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang trunk", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+; Note: <invalid> triggers a bad DILineInfo. We still print "Function1()".
+!1 = !DIFile(filename: "<invalid>", directory: "")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang trunk)"}
+!7 = distinct !DISubprogram(name: "Function1", scope: !8, file: !8, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!8 = !DIFile(filename: "/tmp/src.cc", directory: "")
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocation(line: 1, column: 24, scope: !7)
+!13 = distinct !DISubprogram(name: "bar", linkageName: "_ZN3xyz3barEv", scope: !14, file: !8, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!14 = !DINamespace(name: "xyz", scope: null)
+!15 = !DILocation(line: 3, column: 13, scope: !13)
+!16 = distinct !DISubprogram(name: "baz", linkageName: "_ZN3xyz3bazEv", scope: !14, file: !8, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!17 = !DILocation(line: 3, column: 38, scope: !16)

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
index 63a6c0571802..198d4ed67df5 100644
--- 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
index dd3047173c91..0d8786b7c45d 100644
--- 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
index 1b98d7844d68..c07a4ecfe439 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -553,13 +553,20 @@ class SourcePrinter {
 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.Demangle = false;
+    SymbolizerOpts.PrintFunctions =
+        DILineInfoSpecifier::FunctionNameKind::LinkageName;
+    SymbolizerOpts.Demangle = Demangle;
     SymbolizerOpts.DefaultArch = std::string(DefaultArch);
     Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
   }
@@ -624,34 +631,57 @@ void SourcePrinter::printSourceLine(raw_ostream &OS,
       reportWarning(Warning, ObjectFilename);
       WarnedNoDebugInfo = true;
     }
-    return;
   }
 
-  if (LineInfo.Line == 0 || ((OldLineInfo.Line == LineInfo.Line) &&
-                             (OldLineInfo.FileName == LineInfo.FileName)))
-    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) {
+  bool PrintFunctionName = LineInfo.FunctionName != DILineInfo::BadString &&
+                           LineInfo.FunctionName != OldLineInfo.FunctionName;
+  if (PrintFunctionName) {
+    OS << Delimiter << LineInfo.FunctionName;
+    // If demangling is successful, FunctionName will end with "()". Print it
+    // only if demangling did not run or was unsuccessful.
+    if (!StringRef(LineInfo.FunctionName).endswith("()"))
+      OS << "()";
+    OS << ":\n";
+  }
+  if (LineInfo.FileName != DILineInfo::BadString && LineInfo.Line != 0 &&
+      (OldLineInfo.Line != LineInfo.Line ||
+       OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName))
     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 ||
+      (OldLineInfo.Line == LineInfo.Line &&
+       OldLineInfo.FileName == LineInfo.FileName))
+    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) {


        


More information about the llvm-commits mailing list