encodeULEB128(File.Length, OS);
}
+static void writeExtendedOpcode(const DWARFYAML::LineTableOpcode &Op,
+ uint8_t AddrSize, bool IsLittleEndian,
+ raw_ostream &OS) {
+ // The first byte of extended opcodes is a zero byte. The next bytes are an
+ // ULEB128 integer giving the number of bytes in the instruction itself (does
+ // not include the first zero byte or the size). We serialize the instruction
+ // itself into the OpBuffer and then write the size of the buffer and the
+ // buffer to the real output stream.
+ std::string OpBuffer;
+ raw_string_ostream OpBufferOS(OpBuffer);
+ writeInteger((uint8_t)Op.SubOpcode, OpBufferOS, IsLittleEndian);
+ switch (Op.SubOpcode) {
+ case dwarf::DW_LNE_set_address:
+ cantFail(writeVariableSizedInteger(Op.Data, AddrSize, OpBufferOS,
+ IsLittleEndian));
+ break;
+ case dwarf::DW_LNE_define_file:
+ emitFileEntry(OpBufferOS, Op.FileEntry);
+ break;
+ case dwarf::DW_LNE_set_discriminator:
+ encodeULEB128(Op.Data, OpBufferOS);
+ break;
+ case dwarf::DW_LNE_end_sequence:
+ break;
+ default:
+ for (auto OpByte : Op.UnknownOpcodeData)
+ writeInteger((uint8_t)OpByte, OpBufferOS, IsLittleEndian);
+ }
+ uint64_t ExtLen = Op.ExtLen.getValueOr(OpBuffer.size());
+ encodeULEB128(ExtLen, OS);
+ OS.write(OpBuffer.data(), OpBuffer.size());
+}
+
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);
- }
+ writeExtendedOpcode(Op, AddrSize, IsLittleEndian, OS);
} else if (Op.Opcode < OpcodeBase) {
switch (Op.Opcode) {
case dwarf::DW_LNS_copy:
LineRange: 14
OpcodeBase: 4
StandardOpcodeLengths: [ 0, 1, 1 ]
+
+## l) Test that we can specify or omit the ExtLen field of extended opcodes.
+
+# RUN: yaml2obj --docnum=12 %s -o %t12.o
+# RUN: llvm-readelf --hex-dump=.debug_line %t12.o | \
+# RUN: FileCheck %s --check-prefix=EXTLEN --strict-whitespace
+
+# EXTLEN: Hex dump of section '.debug_line':
+# EXTLEN-NEXT: 0x00000000 20000000 04000800 00000101 01fb0e01
+## ^---------------------------------- line number program header
+# EXTLEN-NEXT: 0x00000010 0000000c 03616263 6400b424 b424b424
+## ----
+## ^- DW_LNS_extended_op
+## ^- extended opcode length (ULEB128) 12
+## ^- DW_LNE_define_file
+## ^---------- "abcd\0"
+## ^--- directory index (ULEB128) 0x1234
+## ^--- modification time (ULEB128) 0x1234
+## ^--- file length (ULEB128) 0x1234
+# EXTLEN-NEXT: 0x00000020 00b42401{{ }}
+## ^- DW_LNS_extended_op
+## ^--- extended opcode length (ULEB128) 0x1234
+## ^- DW_LNE_end_sequence
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+DWARF:
+ debug_line:
+ - Version: 4
+ MinInstLength: 1
+ MaxOpsPerInst: 1
+ DefaultIsStmt: 1
+ LineBase: 251
+ LineRange: 14
+ OpcodeBase: 1
+ StandardOpcodeLengths: []
+ Opcodes:
+ - Opcode: DW_LNS_extended_op
+ ## Omit the ExtLen field.
+ SubOpcode: DW_LNE_define_file
+ FileEntry:
+ Name: abcd
+ DirIdx: 0x1234
+ ModTime: 0x1234
+ Length: 0x1234
+ - Opcode: DW_LNS_extended_op
+ ## Specify the ExtLen field.
+ ExtLen: 0x1234
+ SubOpcode: DW_LNE_end_sequence