[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