authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-02 19:57:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-02 19:57:42-07:00
log1ce6e201aa818b05f6637438d1c0b460ea817e3f
tree6e4dee6d2077b442703ca3a0ba8bfb14daa5745d
parent1a3f250f195d4ed5455795d4fa6e4b0cf97cb6ce

.debug_line: don't rely on header_length field

Empirically, debug info consumers do not respect this field, or otherwise consider it to be an error when it does not point exactly to the end of the header. Therefore we rely on the NOP jump at the beginning of the Line Number Program for padding rather than this field. llvm-dwarfdump says the line number data is fine; gdb and binutils-readelf crap out.

1 files changed, 20 insertions(+), 3 deletions(-)

src-self-hosted/link.zig+20-3
...@@ -647,6 +647,8 @@ pub const File = struct {...@@ -647,6 +647,8 @@ pub const File = struct {
647 }647 }
648648
649 fn allocatedSize(self: *Elf, start: u64) u64 {649 fn allocatedSize(self: *Elf, start: u64) u64 {
650 if (start == 0)
651 return 0;
650 var min_pos: u64 = std.math.maxInt(u64);652 var min_pos: u64 = std.math.maxInt(u64);
651 if (self.shdr_table_offset) |off| {653 if (self.shdr_table_offset) |off| {
652 if (off > start and off < min_pos) min_pos = off;654 if (off > start and off < min_pos) min_pos = off;
...@@ -1229,8 +1231,13 @@ pub const File = struct {...@@ -1229,8 +1231,13 @@ pub const File = struct {
1229 0, // segment_selector_size1231 0, // segment_selector_size
1230 });1232 });
12311233
1232 const header_length = dbg_line_prg_off - (di_buf.items.len + ptr_width_bytes);1234 // Empirically, debug info consumers do not respect this field, or otherwise
1233 self.writeDwarfAddrAssumeCapacity(&di_buf, header_length);1235 // consider it to be an error when it does not point exactly to the end of the header.
1236 // Therefore we rely on the NOP jump at the beginning of the Line Number Program for
1237 // padding rather than this field.
1238 const before_header_len = di_buf.items.len;
1239 di_buf.items.len += ptr_width_bytes; // We will come back and write this.
1240 const after_header_len = di_buf.items.len;
12341241
1235 const opcode_base = DW.LNS_set_isa + 1;1242 const opcode_base = DW.LNS_set_isa + 1;
1236 di_buf.appendSliceAssumeCapacity(&[_]u8{1243 di_buf.appendSliceAssumeCapacity(&[_]u8{
...@@ -1280,7 +1287,17 @@ pub const File = struct {...@@ -1280,7 +1287,17 @@ pub const File = struct {
1280 self.writeDwarfAddrAssumeCapacity(&di_buf, root_src_file_strp); // DW.LNCT_path, DW.FORM_strp1287 self.writeDwarfAddrAssumeCapacity(&di_buf, root_src_file_strp); // DW.LNCT_path, DW.FORM_strp
1281 di_buf.appendAssumeCapacity(0); // LNCT_directory_index, FORM_data11288 di_buf.appendAssumeCapacity(0); // LNCT_directory_index, FORM_data1
12821289
1283 // Add a redundant NOP in case the consumer ignores header_length.1290 const header_len = di_buf.items.len - after_header_len;
1291 switch (self.ptr_width) {
1292 .p32 => {
1293 mem.writeInt(u32, di_buf.items[before_header_len..][0..4], @intCast(u32, header_len), target_endian);
1294 },
1295 .p64 => {
1296 mem.writeInt(u64, di_buf.items[before_header_len..][0..8], header_len, target_endian);
1297 },
1298 }
1299
1300 // We use a NOP jmp because consumers empirically do not respect the header length field.
1284 const after_jmp = di_buf.items.len + 6;1301 const after_jmp = di_buf.items.len + 6;
1285 if (after_jmp > dbg_line_prg_off) {1302 if (after_jmp > dbg_line_prg_off) {
1286 // Move the first N files to the end to make more padding for the header.1303 // Move the first N files to the end to make more padding for the header.