[llvm] [DWARFYAML] Add support for v5 debug_line entry formats (PR #191358)

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 13 07:01:17 PDT 2026


https://github.com/labath updated https://github.com/llvm/llvm-project/pull/191358

>From 2a064b30e3d26c0683ecd10fb078673dab960de8 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Fri, 10 Apr 2026 09:55:51 +0200
Subject: [PATCH 1/2] [DWARFYAML] Add support for v5 debug_line entry formats

This lets us specify the *format* of the directory and file name
entries, but not the entries themselves.
---
 llvm/include/llvm/ObjectYAML/DWARFYAML.h      |  29 +++++
 llvm/lib/ObjectYAML/DWARFEmitter.cpp          |  19 ++-
 llvm/lib/ObjectYAML/DWARFYAML.cpp             |  18 ++-
 .../yaml2obj/ELF/DWARF/debug-line-v5.yaml     | 115 ++++++++++++++++++
 4 files changed, 176 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
index b4ddf9b752ecd..4924d4284d02a 100644
--- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
@@ -151,6 +151,11 @@ struct File {
   uint64_t Length;
 };
 
+struct LnctForm {
+  dwarf::LineNumberEntryFormat ContentType;
+  dwarf::Form Form;
+};
+
 struct LineTableOpcode {
   dwarf::LineNumberOps Opcode;
   std::optional<uint64_t> ExtLen;
@@ -176,8 +181,17 @@ struct LineTable {
   uint8_t LineRange;
   std::optional<uint8_t> OpcodeBase;
   std::optional<std::vector<uint8_t>> StandardOpcodeLengths;
+
+  // For DWARF<=v4
   std::vector<StringRef> IncludeDirs;
   std::vector<File> Files;
+
+  // For DWARF>=v5
+  uint8_t DirectoryEntryFormatCount;
+  std::vector<LnctForm> DirectoryEntryFormat;
+  uint8_t FileNameEntryFormatCount;
+  std::vector<LnctForm> FileNameEntryFormat;
+
   std::vector<LineTableOpcode> Opcodes;
 };
 
@@ -289,6 +303,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Unit)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::FormValue)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Entry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::File)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LnctForm)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTable)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTableOpcode)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::SegAddrPair)
@@ -381,6 +396,10 @@ template <> struct MappingTraits<DWARFYAML::File> {
   LLVM_ABI static void mapping(IO &IO, DWARFYAML::File &File);
 };
 
+template <> struct MappingTraits<DWARFYAML::LnctForm> {
+  LLVM_ABI static void mapping(IO &IO, DWARFYAML::LnctForm &);
+};
+
 template <> struct MappingTraits<DWARFYAML::LineTableOpcode> {
   LLVM_ABI static void mapping(IO &IO,
                                DWARFYAML::LineTableOpcode &LineTableOpcode);
@@ -465,6 +484,16 @@ template <> struct ScalarEnumerationTraits<dwarf::LineNumberExtendedOps> {
   }
 };
 
+#define HANDLE_DW_LNCT(unused, name)                                           \
+  io.enumCase(value, "DW_LNCT_" #name, dwarf::DW_LNCT_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::LineNumberEntryFormat> {
+  static void enumeration(IO &io, dwarf::LineNumberEntryFormat &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+    io.enumFallback<Hex16>(value);
+  }
+};
+
 #define HANDLE_DW_AT(unused, name, unused2, unused3)                           \
   io.enumCase(value, "DW_AT_" #name, dwarf::DW_AT_##name);
 
diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
index 0d73c94f270c7..6f2c54b5949a5 100644
--- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
@@ -594,6 +594,15 @@ getStandardOpcodeLengths(uint16_t Version, std::optional<uint8_t> OpcodeBase) {
   return StandardOpcodeLengths;
 }
 
+static void writeV5EntryFormat(raw_ostream &OS, uint8_t Count,
+                               ArrayRef<DWARFYAML::LnctForm> Format) {
+  OS << static_cast<char>(Count);
+  for (const auto [ContentType, Form] : Format) {
+    encodeULEB128(ContentType, OS);
+    encodeULEB128(Form, OS);
+  }
+}
+
 Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
   for (const DWARFYAML::LineTable &LineTable : DI.DebugLines) {
     // Buffer holds the bytes following the header_length (or prologue_length in
@@ -619,12 +628,14 @@ Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
       writeInteger(OpcodeLength, BufferOS, DI.IsLittleEndian);
 
     if (LineTable.Version >= 5) {
+      writeV5EntryFormat(BufferOS, LineTable.DirectoryEntryFormatCount,
+                         LineTable.DirectoryEntryFormat);
       // TODO: Support directories and file names in DWARFv5
-      writeInteger(/*directory_entry_format_count=*/uint8_t(0), BufferOS,
-                   DI.IsLittleEndian);
       encodeULEB128(/*directories_count=*/0, BufferOS);
-      writeInteger(/*file_name_entry_format_count=*/uint8_t(0), BufferOS,
-                   DI.IsLittleEndian);
+
+      writeV5EntryFormat(BufferOS, LineTable.FileNameEntryFormatCount,
+                         LineTable.FileNameEntryFormat);
+      // TODO: Support directories and file names in DWARFv5
       encodeULEB128(/*file_names_count=*/0, BufferOS);
     } else {
       for (StringRef IncludeDir : LineTable.IncludeDirs) {
diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp
index 20d4dca04434c..1e90387255909 100644
--- a/llvm/lib/ObjectYAML/DWARFYAML.cpp
+++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp
@@ -256,6 +256,12 @@ void MappingTraits<DWARFYAML::File>::mapping(IO &IO, DWARFYAML::File &File) {
   IO.mapRequired("Length", File.Length);
 }
 
+void MappingTraits<DWARFYAML::LnctForm>::mapping(
+    IO &IO, DWARFYAML::LnctForm &LnctForm) {
+  IO.mapRequired("ContentType", LnctForm.ContentType);
+  IO.mapRequired("Form", LnctForm.Form);
+}
+
 void MappingTraits<DWARFYAML::LineTableOpcode>::mapping(
     IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) {
   IO.mapRequired("Opcode", LineTableOpcode.Opcode);
@@ -294,7 +300,17 @@ void MappingTraits<DWARFYAML::LineTable>::mapping(
   IO.mapOptional("OpcodeBase", LineTable.OpcodeBase);
   IO.mapOptional("StandardOpcodeLengths", LineTable.StandardOpcodeLengths);
   if (LineTable.Version >= 5) {
-    // TODO
+    IO.mapRequired("DirectoryEntryFormat", LineTable.DirectoryEntryFormat);
+    IO.mapOptional("DirectoryEntryFormatCount",
+                   LineTable.DirectoryEntryFormatCount,
+                   LineTable.DirectoryEntryFormat.size());
+
+    IO.mapRequired("FileNameEntryFormat", LineTable.FileNameEntryFormat);
+    IO.mapOptional("FileNameEntryFormatCount",
+                   LineTable.FileNameEntryFormatCount,
+                   LineTable.FileNameEntryFormat.size());
+
+    // TODO: Add support for directory and file entries.
   } else {
     IO.mapOptional("IncludeDirs", LineTable.IncludeDirs);
     IO.mapOptional("Files", LineTable.Files);
diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml
index 14b11472ce61a..e722256b6d5b2 100644
--- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml
@@ -20,6 +20,8 @@ DWARF:
       LineBase:            1
       LineRange:           14
       OpcodeBase:          13
+      DirectoryEntryFormat:
+      FileNameEntryFormat:
 
 # RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2LSB -DFORMAT=DWARF32 %s | \
 # RUN:   llvm-readelf --hex-dump=.debug_line - | \
@@ -126,3 +128,116 @@ DWARF:
 ##                                                       ^-       file_name_entry_format_count (1-byte)
 ##                                                         ^-     file_names_count (ULEB128)
 ##                                                           ^----EOF
+
+## Check file/directory entry format handling, particularly the interaction
+## between the count and array fields.
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+DWARF:
+  debug_line:
+    - Format:              DWARF32
+      Version:             5
+      AddressSize:         8
+      SegmentSelectorSize: 4
+      MinInstLength:       1
+      MaxOpsPerInst:       1
+      DefaultIsStmt:       1
+      LineBase:            1
+      LineRange:           14
+      OpcodeBase:          13
+      # DirectoryEntryFormatCount: 1  # Implicit
+      DirectoryEntryFormat:
+        - ContentType:     DW_LNCT_path
+          Form:            DW_FORM_string
+      FileNameEntryFormatCount: 1  # Explicit
+      FileNameEntryFormat:
+        - ContentType:     DW_LNCT_path
+          Form:            DW_FORM_string
+
+# RUN: yaml2obj --docnum=2 %s | llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=FORMATCNT1
+
+# FORMATCNT1:      Hex dump of section '.debug_line':
+# FORMATCNT1-NEXT: 0x00000000 22000000 05000804 1a000000 01010101
+##                            ^-------                            unit_length (4-byte)
+##                                     ^---                       version (2-byte)
+##                                         ^-                     address_size (1-byte)
+##                                           ^-                   segment_selector_size (4-byte)
+##                                              ^-------          header_length (4-byte)
+##                                                       ^-       minimum_instruction_length (1-byte)
+##                                                         ^-     maximum_operations_per_instruction (1-byte)
+##                                                           ^-   default_is_stmt (1-byte)
+##                                                             ^- line_base (1-byte)
+# FORMATCNT1-NEXT: 0x00000010 0e0d0001 01010100 00000100 00010101
+##                            ^-                                  line_range (1-byte)
+##                              ^-                                opcode_base (1-byte)
+##                                ^--- -------- -------- ----     standard_opcode_lengths
+##                                                           ^-   directory_entry_format_count (1-byte)
+##                                                             ^- directories_entry_format[0].content_type (ULEB128)
+# FORMATCNT1-NEXT: 0x00000020 08000101 0800{{ }}
+##                            ^-                                  directories_entry_format[0].form (ULEB128)
+##                              ^-                                directories_count (ULEB128)
+##                                ^-                              file_name_entry_format_count (1-byte)
+##                                  ^-                            file_name_entry_format[0].content_type (ULEB128)
+##                                     ^-                         file_name_entry_format[0].form (ULEB128)
+##                                       ^-                       file_names_count (ULEB128)
+##                                         ^----                  EOF
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+DWARF:
+  debug_line:
+    - Format:              DWARF32
+      Version:             5
+      AddressSize:         8
+      SegmentSelectorSize: 4
+      MinInstLength:       1
+      MaxOpsPerInst:       1
+      DefaultIsStmt:       1
+      LineBase:            1
+      LineRange:           14
+      OpcodeBase:          13
+      DirectoryEntryFormatCount: 0  # Smaller than the array length
+      DirectoryEntryFormat:
+        - ContentType:     DW_LNCT_path
+          Form:            DW_FORM_string
+      FileNameEntryFormatCount: 2  # Larger than the array length
+      FileNameEntryFormat:
+        - ContentType:     DW_LNCT_path
+          Form:            DW_FORM_string
+
+# RUN: yaml2obj --docnum=3 %s | llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=FORMATCNT2
+
+# FORMATCNT2:      Hex dump of section '.debug_line':
+# FORMATCNT2-NEXT: 0x00000000 22000000 05000804 1a000000 01010101
+##                            ^-------                            unit_length (4-byte)
+##                                     ^---                       version (2-byte)
+##                                         ^-                     address_size (1-byte)
+##                                           ^-                   segment_selector_size (4-byte)
+##                                              ^-------          header_length (4-byte)
+##                                                       ^-       minimum_instruction_length (1-byte)
+##                                                         ^-     maximum_operations_per_instruction (1-byte)
+##                                                           ^-   default_is_stmt (1-byte)
+##                                                             ^- line_base (1-byte)
+# FORMATCNT2-NEXT: 0x00000010 0e0d0001 01010100 00000100 00010001
+##                            ^-                                  line_range (1-byte)
+##                              ^-                                opcode_base (1-byte)
+##                                ^--- -------- -------- ----     standard_opcode_lengths
+##                                                           ^-   directory_entry_format_count (1-byte)
+##                                                             ^- directories_entry_format[0].content_type (ULEB128)
+# FORMATCNT2-NEXT: 0x00000020 08000201 0800{{ }}
+##                            ^-                                  directories_entry_format[0].form (ULEB128)
+##                              ^-                                directories_count (ULEB128)
+##                                ^-                              file_name_entry_format_count (1-byte)
+##                                  ^-                            file_name_entry_format[0].content_type (ULEB128)
+##                                     ^-                         file_name_entry_format[0].form (ULEB128)
+##                                       ^-                       file_names_count (ULEB128)
+##                                         ^----                  EOF

>From 2785691709b5733e63be481e93e85a1dc5e333a6 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 13 Apr 2026 16:01:06 +0200
Subject: [PATCH 2/2] fix comment

---
 llvm/lib/ObjectYAML/DWARFEmitter.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
index 6f2c54b5949a5..d24dced8189fc 100644
--- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
@@ -630,12 +630,12 @@ Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
     if (LineTable.Version >= 5) {
       writeV5EntryFormat(BufferOS, LineTable.DirectoryEntryFormatCount,
                          LineTable.DirectoryEntryFormat);
-      // TODO: Support directories and file names in DWARFv5
+      // TODO: Support directories in DWARFv5
       encodeULEB128(/*directories_count=*/0, BufferOS);
 
       writeV5EntryFormat(BufferOS, LineTable.FileNameEntryFormatCount,
                          LineTable.FileNameEntryFormat);
-      // TODO: Support directories and file names in DWARFv5
+      // TODO: Support file names in DWARFv5
       encodeULEB128(/*file_names_count=*/0, BufferOS);
     } else {
       for (StringRef IncludeDir : LineTable.IncludeDirs) {



More information about the llvm-commits mailing list