[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