[llvm] 05a4b64 - [llvm-dwarfdump] --show-sources option to show all sources

Daniel Thornburgh via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 30 09:53:12 PDT 2022


Author: Daniel Thornburgh
Date: 2022-06-30T09:53:08-07:00
New Revision: 05a4b640358be018800deb39de3bd5c1b9f8138f

URL: https://github.com/llvm/llvm-project/commit/05a4b640358be018800deb39de3bd5c1b9f8138f
DIFF: https://github.com/llvm/llvm-project/commit/05a4b640358be018800deb39de3bd5c1b9f8138f.diff

LOG: [llvm-dwarfdump] --show-sources option to show all sources

This option allows printing all sources used by an object file.

Reviewed By: dblaikie, jhenderson

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

Added: 
    llvm/test/tools/llvm-dwarfdump/X86/sources.test

Modified: 
    llvm/docs/CommandGuide/llvm-dwarfdump.rst
    llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/llvm-dwarfdump.rst b/llvm/docs/CommandGuide/llvm-dwarfdump.rst
index d0c436f08e2ba..8adccf1c0c0a3 100644
--- a/llvm/docs/CommandGuide/llvm-dwarfdump.rst
+++ b/llvm/docs/CommandGuide/llvm-dwarfdump.rst
@@ -109,6 +109,11 @@ OPTIONS
 
             Show the sizes of all debug sections, expressed in bytes.
 
+.. option:: --show-sources
+
+            Print all source files mentioned in the debug information. Absolute
+            paths are given whenever possible.
+
 .. option:: --statistics
 
             Collect debug info quality metrics and print the results

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/sources.test b/llvm/test/tools/llvm-dwarfdump/X86/sources.test
new file mode 100644
index 0000000000000..26eb2117a55fc
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/sources.test
@@ -0,0 +1,362 @@
+# RUN: yaml2obj --docnum=1 %s -o %t.name.o
+# RUN: llvm-dwarfdump --show-sources %t.name.o | \
+# RUN:   FileCheck --check-prefix=CU-NAME --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# CU-NAME:      first.c
+# CU-NAME-NEXT: second.c
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: first.c
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: second.c
+
+# RUN: yaml2obj --docnum=2 %s -o %t.comp-dir.o
+# RUN: llvm-dwarfdump --show-sources %t.comp-dir.o 2>&1 | \
+# RUN:   FileCheck -DFILE=%t.comp-dir.o --check-prefix=CU-COMP-DIR \
+# RUN:     --match-full-lines --implicit-check-not={{.}} %s
+
+# CU-COMP-DIR:      warning: [[FILE]]: missing name for compilation unit
+# CU-COMP-DIR-NEXT: warning: [[FILE]]: missing name for compilation unit
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: /comp/first
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: /comp/second
+
+# RUN: yaml2obj --docnum=3 \
+# RUN:   -DFIRST_NAME=first.c -DFIRST_COMP_DIR=/comp/first \
+# RUN:   -DSECOND_NAME=second.c -DSECOND_COMP_DIR=/comp/second \
+# RUN:   -o %t.comp-dir-rel-name.o %s
+# RUN: llvm-dwarfdump --show-sources %t.comp-dir-rel-name.o | \
+# RUN:   FileCheck --check-prefix=CU-COMP-DIR-REL-NAME --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# CU-COMP-DIR-REL-NAME:      /comp/first[[SEP:[/\\]]]first.c
+# CU-COMP-DIR-REL-NAME-NEXT: /comp/second[[SEP]]second.c
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: [[FIRST_NAME]]
+           - CStr: [[FIRST_COMP_DIR]]
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr: [[SECOND_NAME]]
+           - CStr: [[SECOND_COMP_DIR]]
+
+# RUN: yaml2obj --docnum=3 -o %t.comp-dir-abs-name-posix.o \
+# RUN:   -DFIRST_NAME=/abs/first.c -DFIRST_COMP_DIR=/comp/dir \
+# RUN:   -DSECOND_NAME=/abs/second.c -DSECOND_COMP_DIR=/comp/dir \
+# RUN:   %s
+# RUN: llvm-dwarfdump --show-sources %t.comp-dir-abs-name-posix.o | \
+# RUN:   FileCheck --check-prefix=CU-COMP-DIR-ABS-NAME-POSIX \
+# RUN:     --match-full-lines --implicit-check-not={{.}} %s
+
+# CU-COMP-DIR-ABS-NAME-POSIX:      /abs/first.c
+# CU-COMP-DIR-ABS-NAME-POSIX-NEXT: /abs/second.c
+
+# RUN: yaml2obj --docnum=3 -o %t.comp-dir-abs-name-windows.o \
+# RUN:   -DFIRST_NAME='C:\abs\first.c' -DFIRST_COMP_DIR='C:\comp\dir' \
+# RUN:   -DSECOND_NAME='C:\abs\second.c' -DSECOND_COMP_DIR='C:\comp\dir' \
+# RUN:   %s
+# RUN: llvm-dwarfdump --show-sources %t.comp-dir-abs-name-windows.o | \
+# RUN:   FileCheck --check-prefix=CU-COMP-DIR-ABS-NAME-WINDOWS \
+# RUN:     --match-full-lines --implicit-check-not={{.}} %s
+
+# CU-COMP-DIR-ABS-NAME-WINDOWS:      C:\abs\first.c
+# CU-COMP-DIR-ABS-NAME-WINDOWS-NEXT: C:\abs\second.c
+
+# RUN: yaml2obj --docnum=4 %s -o %t.line-table-abs.o
+# RUN: llvm-dwarfdump --show-sources %t.line-table-abs.o | \
+# RUN:   FileCheck --check-prefix=LINE-TABLE-ABS --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# LINE-TABLE-ABS:      /comp/first[[SEP:[/\\]]]first.c
+# LINE-TABLE-ABS-NEXT: /comp/second[[SEP]]second.c
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_line:
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      IncludeDirs:   [/comp/first]
+      Files:
+        - Name:    first.c
+          DirIdx:  1
+          ModTime: 0
+          Length:  0
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      IncludeDirs:   [/comp/second]
+      Files:
+        - Name:    second.c
+          DirIdx:  1
+          ModTime: 0
+          Length:  0
+
+# RUN: yaml2obj --docnum=5 %s -o %t.line-table-rel.o
+# RUN: llvm-dwarfdump --show-sources %t.line-table-rel.o | \
+# RUN:   FileCheck --check-prefix=LINE-TABLE-REL --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# LINE-TABLE-REL:      first.c
+# LINE-TABLE-REL-NEXT: second.c
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_line:
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      Files:
+        - Name:    first.c
+          DirIdx:  0
+          ModTime: 0
+          Length:  0
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      Files:
+        - Name:    second.c
+          DirIdx:  0
+          ModTime: 0
+          Length:  0
+
+# RUN: yaml2obj --docnum=6 %s -o %t.cu-line-table.o
+# RUN: llvm-dwarfdump --show-sources %t.cu-line-table.o | \
+# RUN:   FileCheck --check-prefix=CU-LINE-TABLE --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# CU-LINE-TABLE:      /first[[SEP:[/\\]]]first[[SEP]]first.c
+# CU-LINE-TABLE-NEXT: /second[[SEP]]second[[SEP]]second.c
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_stmt_list
+            Form:      DW_FORM_sec_offset
+    - Table:
+      - Code:     1
+        Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_comp_dir
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_stmt_list
+            Form:      DW_FORM_sec_offset
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr:  /first
+           - Value: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+           - CStr:  /second
+           - Value: 0x23
+  debug_line:
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      IncludeDirs:   [first]
+      Files:
+        - Name:    first.c
+          DirIdx:  1
+          ModTime: 0
+          Length:  0
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      IncludeDirs:   [second]
+      Files:
+        - Name:    second.c
+          DirIdx:  1
+          ModTime: 0
+          Length:  0
+
+# RUN: llvm-dwarfdump --show-sources %t.line-table-rel.o %t.cu-line-table.o | \
+# RUN:   FileCheck --check-prefix=MULTIPLE-FILES --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# MULTIPLE-FILES:      first.c
+# MULTIPLE-FILES-NEXT: second.c
+# MULTIPLE-FILES-NEXT: /first[[SEP:[/\\]]]first[[SEP]]first.c
+# MULTIPLE-FILES-NEXT: /second[[SEP]]second[[SEP]]second.c
+
+# RUN: yaml2obj --docnum=7 %s -o %t.no-filenames.o
+# RUN: llvm-dwarfdump --show-sources %t.no-filenames.o | count 0
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_REL
+  Machine: EM_X86_64
+DWARF:
+  debug_line:
+    - Version:       4
+      MinInstLength: 1
+      MaxOpsPerInst: 1
+      DefaultIsStmt: 1
+      LineBase:      0
+      LineRange:     0
+      OpcodeBase:    1
+      IncludeDirs:   []
+
+# TODO: Use yaml2obj for this test once it supports DWARFv5 line tables.
+# RUN: echo '.file 0 "/dir" "dwarfv5.c"' | \
+# RUN:   llvm-mc -g -dwarf-version=5 -triple x86_64-pc-linux -filetype=obj \
+# RUN:     -o %t.dwarfv5.o
+# RUN: llvm-dwarfdump --show-sources %t.dwarfv5.o | \
+# RUN:   FileCheck --check-prefix=DWARFV5 --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# DWARFV5: /dir{{[/\\]}}dwarfv5.c
+
+# RUN: llvm-mc -triple x86_64-pc-linux %S/Inputs/debug_line_malformed.s \
+# RUN:   -filetype=obj -o %t.malformed.o
+# RUN: not llvm-dwarfdump --show-sources %t.malformed.o 2>&1 | \
+# RUN:   FileCheck --check-prefix=MALFORMED --match-full-lines \
+# RUN:     --implicit-check-not={{.}} %s
+
+# MALFORMED: error: parsing line table prologue at offset 0x00000048: unsupported version 0

diff  --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 3cc211b8a9864..f7d3052c8c4dd 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -26,6 +26,7 @@
 #include "llvm/Support/Format.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/ToolOutputFile.h"
@@ -247,6 +248,10 @@ static cl::opt<bool>
                      cl::desc("Show the sizes of all debug sections, "
                               "expressed in bytes."),
                      cat(DwarfDumpCategory));
+static cl::opt<bool>
+    ShowSources("show-sources",
+                cl::desc("Show the sources across all compilation units."),
+                cat(DwarfDumpCategory));
 static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
                         cat(DwarfDumpCategory));
 static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
@@ -466,6 +471,87 @@ static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
   return true;
 }
 
+// Collect all sources referenced from the given line table, scoped to the given
+// CU compilation directory.
+static bool collectLineTableSources(const DWARFDebugLine::LineTable &LT,
+                                    StringRef CompDir,
+                                    std::vector<std::string> &Sources) {
+  bool Result = true;
+  llvm::Optional<uint64_t> LastIndex = LT.getLastValidFileIndex();
+  for (uint64_t I = LT.hasFileAtIndex(0) ? 0 : 1,
+                E = LastIndex ? *LastIndex + 1 : 0;
+       I < E; ++I) {
+    std::string Path;
+    Result &= LT.getFileNameByIndex(
+        I, CompDir, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+        Path);
+    Sources.push_back(std::move(Path));
+  }
+  return Result;
+}
+
+static bool collectObjectSources(ObjectFile &Obj, DWARFContext &DICtx,
+                                 const Twine &Filename, raw_ostream &OS) {
+  bool Result = true;
+  std::vector<std::string> Sources;
+
+  bool HasCompileUnits = false;
+  for (const auto &CU : DICtx.compile_units()) {
+    HasCompileUnits = true;
+    // Extract paths from the line table for this CU. This allows combining the
+    // compilation directory with the line information, in case both the include
+    // directory and file names in the line table are relative.
+    const DWARFDebugLine::LineTable *LT = DICtx.getLineTableForUnit(CU.get());
+    StringRef CompDir = CU->getCompilationDir();
+    if (LT) {
+      Result &= collectLineTableSources(*LT, CompDir, Sources);
+    } else {
+      // Since there's no line table for this CU, collect the name from the CU
+      // itself.
+      const char *Name = CU->getUnitDIE().getShortName();
+      if (!Name) {
+        WithColor::warning()
+            << Filename << ": missing name for compilation unit\n";
+        continue;
+      }
+      SmallString<64> AbsName;
+      if (sys::path::is_relative(Name, sys::path::Style::posix) &&
+          sys::path::is_relative(Name, sys::path::Style::windows))
+        AbsName = CompDir;
+      sys::path::append(AbsName, Name);
+      Sources.push_back(std::string(AbsName));
+    }
+  }
+
+  if (!HasCompileUnits) {
+    // Since there's no compile units available, walk the line tables and
+    // extract out any referenced paths.
+    DWARFDataExtractor LineData(DICtx.getDWARFObj(),
+                                DICtx.getDWARFObj().getLineSection(),
+                                DICtx.isLittleEndian(), 0);
+    DWARFDebugLine::SectionParser Parser(LineData, DICtx, DICtx.normal_units());
+    while (!Parser.done()) {
+      const auto RecoverableErrorHandler = [&](Error Err) {
+        Result = false;
+        WithColor::defaultErrorHandler(std::move(Err));
+      };
+      void (*UnrecoverableErrorHandler)(Error Err) = error;
+
+      DWARFDebugLine::LineTable LT =
+          Parser.parseNext(RecoverableErrorHandler, UnrecoverableErrorHandler);
+      Result &= collectLineTableSources(LT, /*CompDir=*/"", Sources);
+    }
+  }
+
+  // Dedup and order the sources.
+  llvm::sort(Sources.begin(), Sources.end());
+  Sources.erase(std::unique(Sources.begin(), Sources.end()), Sources.end());
+
+  for (StringRef Name : Sources)
+    OS << Name << "\n";
+  return Result;
+}
+
 static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
                            const Twine &Filename, raw_ostream &OS) {
   logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
@@ -679,6 +765,9 @@ int main(int argc, char **argv) {
   } else if (ShowSectionSizes) {
     for (auto Object : Objects)
       Success &= handleFile(Object, collectObjectSectionSizes, OutputFile.os());
+  } else if (ShowSources) {
+    for (auto Object : Objects)
+      Success &= handleFile(Object, collectObjectSources, OutputFile.os());
   } else {
     for (auto Object : Objects)
       Success &= handleFile(Object, dumpObjectFile, OutputFile.os());


        


More information about the llvm-commits mailing list