[llvm] [DWARFYAML] Begin DWARFv5 debug_line support (PR #191167)

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 9 04:46:35 PDT 2026


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

>From b8ae2d1013dcce5a985694fc508632d4e7db80a7 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 9 Apr 2026 13:07:50 +0200
Subject: [PATCH] [DWARFYAML] Begin DWARFv5 debug_line support

This patch adds enough support to generate a correct basic v5 header
(llvm-dwarfdump complains it can't find DW_LNCT_path, but I wouldn't say
it's strictly required).  Directory and file name counts use relatively
complex encodings, so I'm leaving those for separate patch(es). For now,
I'm hardcoding the relevant fields to zero.
---
 llvm/include/llvm/ObjectYAML/DWARFYAML.h      |   2 +
 llvm/lib/ObjectYAML/DWARFEmitter.cpp          |  37 +++--
 llvm/lib/ObjectYAML/DWARFYAML.cpp             |  12 +-
 .../yaml2obj/ELF/DWARF/debug-line-v5.yaml     | 128 ++++++++++++++++++
 4 files changed, 166 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml

diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
index c8528686592ab..b4ddf9b752ecd 100644
--- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
@@ -166,6 +166,8 @@ struct LineTable {
   dwarf::DwarfFormat Format;
   std::optional<uint64_t> Length;
   uint16_t Version;
+  uint8_t AddressSize;
+  uint8_t SegmentSelectorSize;
   std::optional<uint64_t> PrologueLength;
   uint8_t MinInstLength;
   uint8_t MaxOpsPerInst;
diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
index fbe083a663e0d..0d73c94f270c7 100644
--- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
@@ -602,7 +602,6 @@ Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
     raw_string_ostream BufferOS(Buffer);
 
     writeInteger(LineTable.MinInstLength, BufferOS, DI.IsLittleEndian);
-    // TODO: Add support for emitting DWARFv5 line table.
     if (LineTable.Version >= 4)
       writeInteger(LineTable.MaxOpsPerInst, BufferOS, DI.IsLittleEndian);
     writeInteger(LineTable.DefaultIsStmt, BufferOS, DI.IsLittleEndian);
@@ -619,15 +618,25 @@ Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
     for (uint8_t OpcodeLength : StandardOpcodeLengths)
       writeInteger(OpcodeLength, BufferOS, DI.IsLittleEndian);
 
-    for (StringRef IncludeDir : LineTable.IncludeDirs) {
-      BufferOS.write(IncludeDir.data(), IncludeDir.size());
+    if (LineTable.Version >= 5) {
+      // 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);
+      encodeULEB128(/*file_names_count=*/0, BufferOS);
+    } else {
+      for (StringRef IncludeDir : LineTable.IncludeDirs) {
+        BufferOS.write(IncludeDir.data(), IncludeDir.size());
+        BufferOS.write('\0');
+      }
       BufferOS.write('\0');
-    }
-    BufferOS.write('\0');
 
-    for (const DWARFYAML::File &File : LineTable.Files)
-      emitFileEntry(BufferOS, File);
-    BufferOS.write('\0');
+      for (const DWARFYAML::File &File : LineTable.Files)
+        emitFileEntry(BufferOS, File);
+      BufferOS.write('\0');
+    }
 
     uint64_t HeaderLength =
         LineTable.PrologueLength ? *LineTable.PrologueLength : Buffer.size();
@@ -640,14 +649,20 @@ Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) {
     if (LineTable.Length) {
       Length = *LineTable.Length;
     } else {
-      Length = 2; // sizeof(version)
-      Length +=
-          (LineTable.Format == dwarf::DWARF64 ? 8 : 4); // sizeof(header_length)
+      Length =
+          (LineTable.Format == dwarf::DWARF64 ? 8 : 4); // sizeof(unit_length)
+      Length += 2;                                      // sizeof(version)
+      if (LineTable.Version >= 5)
+        Length += 2; // sizeof(address_size) + sizeof(segment_selector_size)
       Length += Buffer.size();
     }
 
     writeInitialLength(LineTable.Format, Length, OS, DI.IsLittleEndian);
     writeInteger(LineTable.Version, OS, DI.IsLittleEndian);
+    if (LineTable.Version >= 5) {
+      writeInteger(LineTable.AddressSize, OS, DI.IsLittleEndian);
+      writeInteger(LineTable.SegmentSelectorSize, OS, DI.IsLittleEndian);
+    }
     writeDWARFOffset(HeaderLength, LineTable.Format, OS, DI.IsLittleEndian);
     OS.write(Buffer.data(), Buffer.size());
   }
diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp
index c65a494bd4172..20d4dca04434c 100644
--- a/llvm/lib/ObjectYAML/DWARFYAML.cpp
+++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp
@@ -280,6 +280,10 @@ void MappingTraits<DWARFYAML::LineTable>::mapping(
   IO.mapOptional("Format", LineTable.Format, dwarf::DWARF32);
   IO.mapOptional("Length", LineTable.Length);
   IO.mapRequired("Version", LineTable.Version);
+  if (LineTable.Version >= 5) {
+    IO.mapRequired("AddressSize", LineTable.AddressSize);
+    IO.mapOptional("SegmentSelectorSize", LineTable.SegmentSelectorSize, 0);
+  }
   IO.mapOptional("PrologueLength", LineTable.PrologueLength);
   IO.mapRequired("MinInstLength", LineTable.MinInstLength);
   if(LineTable.Version >= 4)
@@ -289,8 +293,12 @@ void MappingTraits<DWARFYAML::LineTable>::mapping(
   IO.mapRequired("LineRange", LineTable.LineRange);
   IO.mapOptional("OpcodeBase", LineTable.OpcodeBase);
   IO.mapOptional("StandardOpcodeLengths", LineTable.StandardOpcodeLengths);
-  IO.mapOptional("IncludeDirs", LineTable.IncludeDirs);
-  IO.mapOptional("Files", LineTable.Files);
+  if (LineTable.Version >= 5) {
+    // TODO
+  } else {
+    IO.mapOptional("IncludeDirs", LineTable.IncludeDirs);
+    IO.mapOptional("Files", LineTable.Files);
+  }
   IO.mapOptional("Opcodes", LineTable.Opcodes);
 }
 
diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml
new file mode 100644
index 0000000000000..14b11472ce61a
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line-v5.yaml
@@ -0,0 +1,128 @@
+## Test yaml2obj for DWARFv5 .debug_line. This file only tests new features of
+## DWARFv5 and assumes that the common functionality is tested elsewhere.
+
+## An empty debug_line section - test DWARF32/64 and little-/big-endian cases.
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  [[ENDIAN]]
+  Type:  ET_EXEC
+DWARF:
+  debug_line:
+    - Format:              [[FORMAT]]
+      Version:             5
+      AddressSize:         8
+      SegmentSelectorSize: 4
+      MinInstLength:       1
+      MaxOpsPerInst:       1
+      DefaultIsStmt:       1
+      LineBase:            1
+      LineRange:           14
+      OpcodeBase:          13
+
+# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2LSB -DFORMAT=DWARF32 %s | \
+# RUN:   llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=HEADER32LE
+
+# HEADER32LE:      Hex dump of section '.debug_line':
+# HEADER32LE-NEXT: 0x00000000 1e000000 05000804 16000000 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)
+# HEADER32LE-NEXT: 0x00000010 0e0d0001 01010100 00000100 00010000
+##                            ^-                                  line_range (1-byte)
+##                              ^-                                opcode_base (1-byte)
+##                                ^--- -------- -------- ----     standard_opcode_lengths
+##                                                           ^-   directory_entry_format_count (1-byte)
+##                                                             ^- directories_count (ULEB128)
+# HEADER32LE-NEXT: 0x00000020 0000{{ }}
+##                            ^-                                  file_name_entry_format_count (1-byte)
+##                              ^-                                file_names_count (ULEB128)
+##                                ^----                           EOF
+
+# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2MSB -DFORMAT=DWARF32 %s | \
+# RUN:   llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=HEADER32BE
+
+# HEADER32BE:      Hex dump of section '.debug_line':
+# HEADER32BE-NEXT: 0x00000000 0000001e 00050804 00000016 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)
+# HEADER32BE-NEXT: 0x00000010 0e0d0001 01010100 00000100 00010000
+##                            ^-                                  line_range (1-byte)
+##                              ^-                                opcode_base (1-byte)
+##                                ^--- -------- -------- ----     standard_opcode_lengths
+##                                                           ^-   directory_entry_format_count (1-byte)
+##                                                             ^- directories_count (ULEB128)
+# HEADER32BE-NEXT: 0x00000020 0000{{ }}
+##                            ^-                                  file_name_entry_format_count (1-byte)
+##                              ^-                                file_names_count (ULEB128)
+##                                ^----                           EOF
+
+# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2LSB -DFORMAT=DWARF64 %s | \
+# RUN:   llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=HEADER64LE
+
+# HEADER64LE:      Hex dump of section '.debug_line':
+# HEADER64LE-NEXT: 0x00000000 ffffffff 22000000 00000000 05000804
+##                            ^------- -------- --------          unit_length (12-byte)
+##                                                       ^---     version (2-byte)
+##                                                           ^-   address_size (1-byte)
+##                                                             ^- segment_selector_size (4-byte)
+# HEADER64LE-NEXT: 0x00000010 16000000 00000000 01010101 0e0d0001
+##                            ^------- --------                   header_length (4-byte)
+##                                              ^-                minimum_instruction_length (1-byte)
+##                                                ^-              maximum_operations_per_instruction (1-byte)
+##                                                  ^-            default_is_stmt (1-byte)
+##                                                    ^-          line_base (1-byte)
+##                                                       ^-                                  line_range (1-byte)
+##                                                         ^-                                opcode_base (1-byte)
+##                                                           ^--- standard_opcode_lengths
+# HEADER64LE-NEXT: 0x00000020 01010100 00000100 00010000 0000{{ }}
+#                             -------- -------- ----              standard_opcode_lengths
+##                                                  ^-            directory_entry_format_count (1-byte)
+##                                                    ^-          directories_count (ULEB128)
+##                                                       ^-       file_name_entry_format_count (1-byte)
+##                                                         ^-     file_names_count (ULEB128)
+##                                                           ^----EOF
+
+# RUN: yaml2obj --docnum=1 -DENDIAN=ELFDATA2MSB -DFORMAT=DWARF64 %s | \
+# RUN:   llvm-readelf --hex-dump=.debug_line - | \
+# RUN:   FileCheck %s --check-prefix=HEADER64BE
+
+# HEADER64BE:      Hex dump of section '.debug_line':
+# HEADER64BE-NEXT: 0x00000000 ffffffff 00000000 00000022 00050804
+##                            ^------- -------- --------          unit_length (12-byte)
+##                                                       ^---     version (2-byte)
+##                                                           ^-   address_size (1-byte)
+##                                                             ^- segment_selector_size (4-byte)
+# HEADER64BE-NEXT: 0x00000010 00000000 00000016 01010101 0e0d0001
+##                            ^------- --------                   header_length (4-byte)
+##                                              ^-                minimum_instruction_length (1-byte)
+##                                                ^-              maximum_operations_per_instruction (1-byte)
+##                                                  ^-            default_is_stmt (1-byte)
+##                                                    ^-          line_base (1-byte)
+##                                                       ^-                                  line_range (1-byte)
+##                                                         ^-                                opcode_base (1-byte)
+##                                                           ^--- standard_opcode_lengths
+# HEADER64BE-NEXT: 0x00000020 01010100 00000100 00010000 0000{{ }}
+#                             -------- -------- ----              standard_opcode_lengths
+##                                                  ^-            directory_entry_format_count (1-byte)
+##                                                    ^-          directories_count (ULEB128)
+##                                                       ^-       file_name_entry_format_count (1-byte)
+##                                                         ^-     file_names_count (ULEB128)
+##                                                           ^----EOF



More information about the llvm-commits mailing list