diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -137,9 +137,9 @@ struct LineTable { dwarf::DwarfFormat Format; - uint64_t Length; + Optional Length; uint16_t Version; - uint64_t PrologueLength; + Optional PrologueLength; uint8_t MinInstLength; uint8_t MaxOpsPerInst; uint8_t DefaultIsStmt; diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -448,89 +448,113 @@ encodeULEB128(File.Length, OS); } +static void writeLineTableOpcode(const DWARFYAML::LineTableOpcode &Op, + uint8_t OpcodeBase, uint8_t AddrSize, + raw_ostream &OS, bool IsLittleEndian) { + writeInteger((uint8_t)Op.Opcode, OS, IsLittleEndian); + if (Op.Opcode == 0) { + encodeULEB128(Op.ExtLen, OS); + writeInteger((uint8_t)Op.SubOpcode, OS, IsLittleEndian); + switch (Op.SubOpcode) { + case dwarf::DW_LNE_set_address: + cantFail( + writeVariableSizedInteger(Op.Data, AddrSize, OS, IsLittleEndian)); + break; + case dwarf::DW_LNE_define_file: + emitFileEntry(OS, Op.FileEntry); + break; + case dwarf::DW_LNE_set_discriminator: + encodeULEB128(Op.Data, OS); + break; + case dwarf::DW_LNE_end_sequence: + break; + default: + for (auto OpByte : Op.UnknownOpcodeData) + writeInteger((uint8_t)OpByte, OS, IsLittleEndian); + } + } else if (Op.Opcode < OpcodeBase) { + switch (Op.Opcode) { + case dwarf::DW_LNS_copy: + case dwarf::DW_LNS_negate_stmt: + case dwarf::DW_LNS_set_basic_block: + case dwarf::DW_LNS_const_add_pc: + case dwarf::DW_LNS_set_prologue_end: + case dwarf::DW_LNS_set_epilogue_begin: + break; + + case dwarf::DW_LNS_advance_pc: + case dwarf::DW_LNS_set_file: + case dwarf::DW_LNS_set_column: + case dwarf::DW_LNS_set_isa: + encodeULEB128(Op.Data, OS); + break; + + case dwarf::DW_LNS_advance_line: + encodeSLEB128(Op.SData, OS); + break; + + case dwarf::DW_LNS_fixed_advance_pc: + writeInteger((uint16_t)Op.Data, OS, IsLittleEndian); + break; + + default: + for (auto OpData : Op.StandardOpcodeData) { + encodeULEB128(OpData, OS); + } + } + } +} + Error DWARFYAML::emitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { for (const auto &LineTable : DI.DebugLines) { - writeInitialLength(LineTable.Format, LineTable.Length, OS, - DI.IsLittleEndian); - writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); - writeDWARFOffset(LineTable.PrologueLength, LineTable.Format, OS, DI.IsLittleEndian); - writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); + // Buffer holds the bytes following the header_length (or prologue_length in + // DWARFv2) field to the end of line number program itself. + std::string Buffer; + raw_string_ostream BufferOS(Buffer); + + writeInteger((uint8_t)LineTable.MinInstLength, BufferOS, DI.IsLittleEndian); if (LineTable.Version >= 4) - writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); - writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); - writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); - writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); - writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.MaxOpsPerInst, BufferOS, + DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.DefaultIsStmt, BufferOS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.LineBase, BufferOS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.LineRange, BufferOS, DI.IsLittleEndian); + writeInteger((uint8_t)LineTable.OpcodeBase, BufferOS, DI.IsLittleEndian); for (auto OpcodeLength : LineTable.StandardOpcodeLengths) - writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); + writeInteger((uint8_t)OpcodeLength, BufferOS, DI.IsLittleEndian); for (auto IncludeDir : LineTable.IncludeDirs) { - OS.write(IncludeDir.data(), IncludeDir.size()); - OS.write('\0'); + BufferOS.write(IncludeDir.data(), IncludeDir.size()); + BufferOS.write('\0'); } - OS.write('\0'); + BufferOS.write('\0'); for (auto File : LineTable.Files) - emitFileEntry(OS, File); - OS.write('\0'); + emitFileEntry(BufferOS, File); + BufferOS.write('\0'); - uint8_t AddrSize = DI.Is64BitAddrSize ? 8 : 4; - - for (auto Op : LineTable.Opcodes) { - writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); - if (Op.Opcode == 0) { - encodeULEB128(Op.ExtLen, OS); - writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); - switch (Op.SubOpcode) { - case dwarf::DW_LNE_set_address: - cantFail(writeVariableSizedInteger(Op.Data, AddrSize, OS, - DI.IsLittleEndian)); - break; - case dwarf::DW_LNE_define_file: - emitFileEntry(OS, Op.FileEntry); - break; - case dwarf::DW_LNE_set_discriminator: - encodeULEB128(Op.Data, OS); - break; - case dwarf::DW_LNE_end_sequence: - break; - default: - for (auto OpByte : Op.UnknownOpcodeData) - writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); - } - } else if (Op.Opcode < LineTable.OpcodeBase) { - switch (Op.Opcode) { - case dwarf::DW_LNS_copy: - case dwarf::DW_LNS_negate_stmt: - case dwarf::DW_LNS_set_basic_block: - case dwarf::DW_LNS_const_add_pc: - case dwarf::DW_LNS_set_prologue_end: - case dwarf::DW_LNS_set_epilogue_begin: - break; - - case dwarf::DW_LNS_advance_pc: - case dwarf::DW_LNS_set_file: - case dwarf::DW_LNS_set_column: - case dwarf::DW_LNS_set_isa: - encodeULEB128(Op.Data, OS); - break; - - case dwarf::DW_LNS_advance_line: - encodeSLEB128(Op.SData, OS); - break; - - case dwarf::DW_LNS_fixed_advance_pc: - writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); - break; - - default: - for (auto OpData : Op.StandardOpcodeData) { - encodeULEB128(OpData, OS); - } - } - } + uint64_t HeaderLength = + LineTable.PrologueLength ? *LineTable.PrologueLength : Buffer.size(); + + for (const DWARFYAML::LineTableOpcode &Op : LineTable.Opcodes) + writeLineTableOpcode(Op, LineTable.OpcodeBase, DI.Is64BitAddrSize ? 8 : 4, + BufferOS, DI.IsLittleEndian); + + uint64_t Length; + if (LineTable.Length) { + Length = *LineTable.Length; + } else { + Length = 2; // sizeof(version) + Length += + (LineTable.Format == dwarf::DWARF64 ? 8 : 4); // sizeof(header_length) + Length += Buffer.size(); } + + writeInitialLength(LineTable.Format, Length, OS, DI.IsLittleEndian); + writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); + writeDWARFOffset(HeaderLength, LineTable.Format, OS, DI.IsLittleEndian); + OS.write(Buffer.data(), Buffer.size()); } return Error::success(); diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -230,9 +230,9 @@ void MappingTraits::mapping( IO &IO, DWARFYAML::LineTable &LineTable) { IO.mapOptional("Format", LineTable.Format, dwarf::DWARF32); - IO.mapRequired("Length", LineTable.Length); + IO.mapOptional("Length", LineTable.Length); IO.mapRequired("Version", LineTable.Version); - IO.mapRequired("PrologueLength", LineTable.PrologueLength); + IO.mapOptional("PrologueLength", LineTable.PrologueLength); IO.mapRequired("MinInstLength", LineTable.MinInstLength); if(LineTable.Version >= 4) IO.mapRequired("MaxOpsPerInst", LineTable.MaxOpsPerInst); diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line.yaml --- a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line.yaml +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-line.yaml @@ -479,3 +479,61 @@ ExtLen: 0x09 SubOpcode: DW_LNE_set_discriminator Data: 0x1234 + +## j) Test that yaml2obj is able to infer the length and header_length fields. + +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: llvm-readelf --hex-dump=.debug_line %t10.o | FileCheck %s --check-prefix=INFER-LENGTH + +# INFER-LENGTH: Hex dump of section '.debug_line': +# INFER-LENGTH-NEXT: 0x00000000 39000000 04001b00 00000101 01fb0e0d 9............... +## ^------- unit_length (4-byte) 0x39 +## ^--- version (2-byte) +## ^-------- header_length (4-byte) 0x1b +## ^- minimum_instruction_length (1-byte) +## ^- maximum_operations_per_instruction (1-byte) +## ^- default_is_stmt (1-byte) +## ^- line_base (1-byte) -5 +## ^- line_range (1-byte) +## ^- opcode_base (1-byte) +# INFER-LENGTH-NEXT: 0x00000010 00010101 01000000 01000001 00612e63 .............a.c +## ^------------------------- standard_opcode_lengths (12-byte) +## ^- include_directories null byte +## ^----- file_names[0] file_name "a.c\0" +# INFER-LENGTH-NEXT: 0x00000020 00000000 00000101 ........ +## -- +## ^- file_names[0] directory index 0x00 +## ^- file_names[0] modification time 0x00 +## ^- file_names[0] file length 0x00 +## ^- file_names null byte +## ^- DW_LNS_extended_op +## ^- extended op length (ULEB128) 0x01 +## ^- DW_LNE_end_sequence + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +DWARF: +DWARF: + debug_line: + - Version: 4 + MinInstLength: 1 + MaxOpsPerInst: 1 + DefaultIsStmt: 1 + LineBase: 251 + LineRange: 14 + OpcodeBase: 13 + StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] + IncludeDirs: [] + Files: + - Name: a.c + DirIdx: 0 + ModTime: 0 + Length: 0 + Opcodes: + - Opcode: DW_LNS_extended_op + ExtLen: 1 + SubOpcode: DW_LNE_end_sequence + Data: 0 diff --git a/llvm/tools/obj2yaml/dwarf2yaml.cpp b/llvm/tools/obj2yaml/dwarf2yaml.cpp --- a/llvm/tools/obj2yaml/dwarf2yaml.cpp +++ b/llvm/tools/obj2yaml/dwarf2yaml.cpp @@ -318,13 +318,15 @@ DebugLines.Format = dwarf::DWARF32; DebugLines.Length = LengthOrDWARF64Prefix; } - uint64_t LineTableLength = DebugLines.Length; + assert(DebugLines.Length); + uint64_t LineTableLength = *DebugLines.Length; uint64_t SizeOfPrologueLength = DebugLines.Format == dwarf::DWARF64 ? 8 : 4; DebugLines.Version = LineData.getU16(&Offset); DebugLines.PrologueLength = LineData.getUnsigned(&Offset, SizeOfPrologueLength); - const uint64_t EndPrologue = DebugLines.PrologueLength + Offset; + assert(DebugLines.PrologueLength); + const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset; DebugLines.MinInstLength = LineData.getU8(&Offset); if (DebugLines.Version >= 4) diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -2196,9 +2196,7 @@ - Value: 0x0000000000000001 - Value: 0x0000000000000000 debug_line: - - Length: 68 - Version: 2 - PrologueLength: 34 + - Version: 2 MinInstLength: 1 DefaultIsStmt: 1 LineBase: 251 @@ -2265,9 +2263,7 @@ - Value: 0x0000000000000001 - Value: 0x0000000000000000 debug_line: - - Length: 61 - Version: 2 - PrologueLength: 34 + - Version: 2 MinInstLength: 1 DefaultIsStmt: 1 LineBase: 251 @@ -2336,9 +2332,7 @@ - Value: 0x0000000000000001 - Value: 0x0000000000000000 debug_line: - - Length: 61 - Version: 2 - PrologueLength: 34 + - Version: 2 MinInstLength: 1 DefaultIsStmt: 1 LineBase: 251 @@ -2408,9 +2402,7 @@ - Value: 0x0000000000000001 - Value: 0x0000000000000000 debug_line: - - Length: 71 - Version: 2 - PrologueLength: 44 + - Version: 2 MinInstLength: 1 DefaultIsStmt: 1 LineBase: 251 @@ -2495,9 +2487,7 @@ - Value: 0x000000000000000D - Value: 0x0000000000000000 debug_line: - - Length: 60 - Version: 2 - PrologueLength: 34 + - Version: 2 MinInstLength: 1 DefaultIsStmt: 1 LineBase: 251