authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-11 14:07:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-11 14:07:06-07:00
log7612931c8020592a8c78b15339c696590579e03c
treeee3bfa7593956d54ff769a004349f25175b0a087
parent60ce5edaf9f9bd9c500eb74d6e775baa7867ed84

stage2: set up per-Decl .debug_info


2 files changed, 284 insertions(+), 102 deletions(-)

src-self-hosted/codegen.zig+61-52
......@@ -50,6 +50,7 @@ pub fn generateSymbol(
5050 typed_value: TypedValue,
5151 code: *std.ArrayList(u8),
5252 dbg_line: *std.ArrayList(u8),
53 dbg_info: *std.ArrayList(u8),
5354) GenerateSymbolError!Result {
5455 const tracy = trace(@src());
5556 defer tracy.end();
......@@ -57,61 +58,62 @@ pub fn generateSymbol(
5758 switch (typed_value.ty.zigTypeTag()) {
5859 .Fn => {
5960 switch (bin_file.base.options.target.cpu.arch) {
60 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line),
61 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
62 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
63 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line),
64 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
65 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
66 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line),
67 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
68 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
69 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line),
70 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line),
71 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
72 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
73 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line),
74 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line),
75 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
76 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
77 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line),
78 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line),
79 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line),
80 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
81 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
82 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line),
83 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line),
84 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line),
85 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line),
86 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line),
87 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line),
88 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
89 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),
90 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line),
91 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
92 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line),
93 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line),
94 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
95 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
96 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
97 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line),
98 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
99 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line),
100 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
101 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line),
102 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
103 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line),
104 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line),
105 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line),
106 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
107 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
108 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line),
109 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line),
110 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line),
61 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
62 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
63 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
64 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
65 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
66 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
67 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
68 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
69 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
70 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
71 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
72 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
73 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
74 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
75 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
76 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
77 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
78 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
79 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
80 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
81 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
82 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
83 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
84 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
85 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
86 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
87 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
88 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
89 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
90 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
91 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
92 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
93 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
94 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
95 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
96 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
97 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
98 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
99 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
100 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
101 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
102 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
103 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
104 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
105 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
106 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
107 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
108 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
109 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
110 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
111 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
111112 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
112113 }
113114 },
114115 .Array => {
116 // TODO populate .debug_info for the array
115117 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
116118 if (typed_value.ty.arraySentinel()) |sentinel| {
117119 try code.ensureCapacity(code.items.len + payload.data.len + 1);
......@@ -120,7 +122,7 @@ pub fn generateSymbol(
120122 switch (try generateSymbol(bin_file, src, .{
121123 .ty = typed_value.ty.elemType(),
122124 .val = sentinel,
123 }, code, dbg_line)) {
125 }, code, dbg_line, dbg_info)) {
124126 .appended => return Result{ .appended = {} },
125127 .externally_managed => |slice| {
126128 code.appendSliceAssumeCapacity(slice);
......@@ -142,6 +144,8 @@ pub fn generateSymbol(
142144 };
143145 },
144146 .Pointer => {
147 // TODO populate .debug_info for the pointer
148
145149 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
146150 const decl = payload.decl;
147151 if (decl.analysis != .complete) return error.AnalysisFail;
......@@ -177,6 +181,8 @@ pub fn generateSymbol(
177181 };
178182 },
179183 .Int => {
184 // TODO populate .debug_info for the integer
185
180186 const info = typed_value.ty.intInfo(bin_file.base.options.target);
181187 if (info.bits == 8 and !info.signed) {
182188 const x = typed_value.val.toUnsignedInt();
......@@ -218,6 +224,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
218224 mod_fn: *const Module.Fn,
219225 code: *std.ArrayList(u8),
220226 dbg_line: *std.ArrayList(u8),
227 dbg_info: *std.ArrayList(u8),
221228 err_msg: ?*ErrorMsg,
222229 args: []MCValue,
223230 ret_mcv: MCValue,
......@@ -387,6 +394,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
387394 typed_value: TypedValue,
388395 code: *std.ArrayList(u8),
389396 dbg_line: *std.ArrayList(u8),
397 dbg_info: *std.ArrayList(u8),
390398 ) GenerateSymbolError!Result {
391399 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
392400
......@@ -424,6 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
424432 .mod_fn = module_fn,
425433 .code = code,
426434 .dbg_line = dbg_line,
435 .dbg_info = dbg_info,
427436 .err_msg = null,
428437 .args = undefined, // populated after `resolveCallingConventionValues`
429438 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
src-self-hosted/link.zig+223-50
......@@ -342,9 +342,10 @@ pub const File = struct {
342342 shstrtab_dirty: bool = false,
343343 debug_strtab_dirty: bool = false,
344344 offset_table_count_dirty: bool = false,
345 debug_info_section_dirty: bool = false,
346345 debug_abbrev_section_dirty: bool = false,
347346 debug_aranges_section_dirty: bool = false,
347
348 debug_info_header_dirty: bool = false,
348349 debug_line_header_dirty: bool = false,
349350
350351 error_flags: ErrorFlags = ErrorFlags{},
......@@ -364,7 +365,7 @@ pub const File = struct {
364365 /// overcapacity can be negative. A simple way to have negative overcapacity is to
365366 /// allocate a fresh text block, which will have ideal capacity, and then grow it
366367 /// by 1 byte. It will then have -1 overcapacity.
367 text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = std.ArrayListUnmanaged(*TextBlock){},
368 text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
368369 last_text_block: ?*TextBlock = null,
369370
370371 /// A list of `SrcFn` whose Line Number Programs have surplus capacity.
......@@ -373,6 +374,12 @@ pub const File = struct {
373374 dbg_line_fn_first: ?*SrcFn = null,
374375 dbg_line_fn_last: ?*SrcFn = null,
375376
377 /// A list of `TextBlock` whose corresponding .debug_info tags have surplus capacity.
378 /// This is the same concept as `text_block_free_list`; see those doc comments.
379 dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
380 dbg_info_decl_first: ?*TextBlock = null,
381 dbg_info_decl_last: ?*TextBlock = null,
382
376383 /// `alloc_num / alloc_den` is the factor of padding when allocating.
377384 const alloc_num = 4;
378385 const alloc_den = 3;
......@@ -398,11 +405,24 @@ pub const File = struct {
398405 prev: ?*TextBlock,
399406 next: ?*TextBlock,
400407
408 /// Previous/next linked list pointers. This value is `next ^ prev`.
409 /// This is the linked list node for this Decl's corresponding .debug_info tag.
410 dbg_info_prev: ?*TextBlock,
411 dbg_info_next: ?*TextBlock,
412 /// Offset into .debug_info pointing to the tag for this Decl.
413 dbg_info_off: u32,
414 /// Size of the .debug_info tag for this Decl, not including padding.
415 dbg_info_len: u32,
416
401417 pub const empty = TextBlock{
402418 .local_sym_index = 0,
403419 .offset_table_index = undefined,
404420 .prev = null,
405421 .next = null,
422 .dbg_info_prev = null,
423 .dbg_info_next = null,
424 .dbg_info_off = undefined,
425 .dbg_info_len = undefined,
406426 };
407427
408428 /// Returns how much room there is to grow in virtual address space.
......@@ -566,6 +586,7 @@ pub const File = struct {
566586 self.offset_table_free_list.deinit(self.base.allocator);
567587 self.text_block_free_list.deinit(self.base.allocator);
568588 self.dbg_line_fn_free_list.deinit(self.base.allocator);
589 self.dbg_info_decl_free_list.deinit(self.base.allocator);
569590 self.offset_table.deinit(self.base.allocator);
570591 }
571592
......@@ -854,7 +875,7 @@ pub const File = struct {
854875 .sh_entsize = 0,
855876 });
856877 self.shdr_table_dirty = true;
857 self.debug_info_section_dirty = true;
878 self.debug_info_header_dirty = true;
858879 }
859880 if (self.debug_abbrev_section_index == null) {
860881 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
......@@ -1019,21 +1040,36 @@ pub const File = struct {
10191040
10201041 self.debug_abbrev_section_dirty = false;
10211042 }
1022 if (self.debug_info_section_dirty) {
1043
1044 if (self.debug_info_header_dirty) debug_info: {
1045 // If this value is null it means there is an error in the module;
1046 // leave debug_info_header_dirty=true.
1047 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
1048 const last_dbg_info_decl = self.dbg_info_decl_last.?;
10231049 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
10241050
10251051 var di_buf = std.ArrayList(u8).init(self.base.allocator);
10261052 defer di_buf.deinit();
10271053
1028 // Enough for a 64-bit header and main compilation unit without resizing.
1029 try di_buf.ensureCapacity(100);
1054 // We have a function to compute the upper bound size, because it's needed
1055 // for determining where to put the offset of the first `LinkBlock`.
1056 try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes());
10301057
10311058 // initial length - length of the .debug_info contribution for this compilation unit,
10321059 // not including the initial length itself.
10331060 // We have to come back and write it later after we know the size.
1034 const init_len_index = di_buf.items.len;
1035 di_buf.items.len += init_len_size;
1036 const after_init_len = di_buf.items.len;
1061 const after_init_len = di_buf.items.len + init_len_size;
1062 const dbg_info_end = last_dbg_info_decl.dbg_info_off + last_dbg_info_decl.dbg_info_len;
1063 const init_len = dbg_info_end - after_init_len;
1064 switch (self.ptr_width) {
1065 .p32 => {
1066 mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, init_len), target_endian);
1067 },
1068 .p64 => {
1069 di_buf.appendNTimesAssumeCapacity(0xff, 4);
1070 mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), init_len, target_endian);
1071 },
1072 }
10371073 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
10381074 const abbrev_offset = self.debug_abbrev_table_offset.?;
10391075 switch (self.ptr_width) {
......@@ -1068,39 +1104,15 @@ pub const File = struct {
10681104 // Until then we say it is C99.
10691105 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);
10701106
1071 const init_len = di_buf.items.len - after_init_len;
1072 switch (self.ptr_width) {
1073 .p32 => {
1074 mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian);
1075 },
1076 .p64 => {
1077 // initial length - length of the .debug_info contribution for this compilation unit,
1078 // not including the initial length itself.
1079 di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff };
1080 mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian);
1081 },
1082 }
1083
1084 const needed_size = di_buf.items.len;
1085 const allocated_size = self.allocatedSize(debug_info_sect.sh_offset);
1086 if (needed_size > allocated_size) {
1087 debug_info_sect.sh_size = 0; // free the space
1088 debug_info_sect.sh_offset = self.findFreeSpace(needed_size, 1);
1089 }
1090 debug_info_sect.sh_size = needed_size;
1091 log.debug(.link, ".debug_info start=0x{x} end=0x{x}\n", .{
1092 debug_info_sect.sh_offset,
1093 debug_info_sect.sh_offset + needed_size,
1094 });
1095
1096 try self.base.file.?.pwriteAll(di_buf.items, debug_info_sect.sh_offset);
1097 if (!self.shdr_table_dirty) {
1098 // Then it won't get written with the others and we need to do it.
1099 try self.writeSectHeader(self.debug_info_section_index.?);
1107 if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) {
1108 // Move the first N decls to the end to make more padding for the header.
1109 @panic("TODO: handle .debug_info header exceeding its padding");
11001110 }
1101
1102 self.debug_info_section_dirty = false;
1111 const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
1112 try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, debug_info_sect.sh_offset);
1113 self.debug_info_header_dirty = false;
11031114 }
1115
11041116 if (self.debug_aranges_section_dirty) {
11051117 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
11061118
......@@ -1266,7 +1278,7 @@ pub const File = struct {
12661278 @panic("TODO: handle .debug_line header exceeding its padding");
12671279 }
12681280 const jmp_amt = dbg_line_prg_off - di_buf.items.len;
1269 try self.pwriteWithNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
1281 try self.pwriteDbgLineNops(0, di_buf.items, jmp_amt, debug_line_sect.sh_offset);
12701282 self.debug_line_header_dirty = false;
12711283 }
12721284
......@@ -1417,8 +1429,7 @@ pub const File = struct {
14171429 // The point of flush() is to commit changes, so in theory, nothing should
14181430 // be dirty after this. However, it is possible for some things to remain
14191431 // dirty because they fail to be written in the event of compile errors,
1420 // such as debug_line_header_dirty.
1421 assert(!self.debug_info_section_dirty);
1432 // such as debug_line_header_dirty and debug_info_header_dirty.
14221433 assert(!self.debug_abbrev_section_dirty);
14231434 assert(!self.debug_aranges_section_dirty);
14241435 assert(!self.phdr_table_dirty);
......@@ -1700,8 +1711,8 @@ pub const File = struct {
17001711
17011712 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
17021713 // range of the compilation unit. When we expand the text section, this range changes,
1703 // so the .debug_info section becomes dirty.
1704 self.debug_info_section_dirty = true;
1714 // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty.
1715 self.debug_info_header_dirty = true;
17051716 // This becomes dirty for the same reason. We could potentially make this more
17061717 // fine-grained with the addition of support for more compilation units. It is planned to
17071718 // model each package as a different compilation unit.
......@@ -1815,6 +1826,9 @@ pub const File = struct {
18151826 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
18161827 defer dbg_line_buffer.deinit();
18171828
1829 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
1830 defer dbg_info_buffer.deinit();
1831
18181832 const typed_value = decl.typed_value.most_recent.typed_value;
18191833 const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
18201834 .Fn => true,
......@@ -1871,7 +1885,7 @@ pub const File = struct {
18711885 // do the work of setting prologue_end=true and epilogue_begin=true.
18721886 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
18731887 }
1874 const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer);
1888 const res = try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer);
18751889 const code = switch (res) {
18761890 .externally_managed => |x| x,
18771891 .appended => code_buffer.items,
......@@ -1937,6 +1951,8 @@ pub const File = struct {
19371951 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
19381952 try self.base.file.?.pwriteAll(code, file_offset);
19391953
1954 try self.updateDeclDebugInfo(module, decl, dbg_info_buffer.items);
1955
19401956 // If the Decl is a function, we need to update the .debug_line program.
19411957 if (is_fn) {
19421958 // Perform the relocation based on vaddr.
......@@ -1956,6 +1972,10 @@ pub const File = struct {
19561972
19571973 // Now we have the full contents and may allocate a region to store it.
19581974
1975 // This logic is nearly identical to the logic below in `updateDeclDebugInfo` for
1976 // `TextBlock` and the .debug_info. If you are editing this logic, you
1977 // probably need to edit that logic too.
1978
19591979 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
19601980 const src_fn = &decl.fn_link.elf;
19611981 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
......@@ -1972,7 +1992,7 @@ pub const File = struct {
19721992 src_fn.next = null;
19731993 // Populate where it used to be with NOPs.
19741994 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1975 try self.pwriteWithNops(0, &[0]u8{}, src_fn.len, file_pos);
1995 try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
19761996 // TODO Look at the free list before appending at the end.
19771997 src_fn.prev = last;
19781998 last.next = src_fn;
......@@ -2022,7 +2042,7 @@ pub const File = struct {
20222042 // We only have support for one compilation unit so far, so the offsets are directly
20232043 // from the .debug_line section.
20242044 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2025 try self.pwriteWithNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
2045 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
20262046 }
20272047
20282048 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
......@@ -2030,6 +2050,88 @@ pub const File = struct {
20302050 return self.updateDeclExports(module, decl, decl_exports);
20312051 }
20322052
2053 pub fn updateDeclDebugInfo(self: *Elf, module: *Module, decl: *Module.Decl, dbg_info_buf: []const u8) !void {
2054 const tracy = trace(@src());
2055 defer tracy.end();
2056
2057 // This logic is nearly identical to the logic above in `updateDecl` for
2058 // `SrcFn` and the line number programs. If you are editing this logic, you
2059 // probably need to edit that logic too.
2060
2061 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2062 const text_block = &decl.link.elf;
2063 if (self.dbg_info_decl_last) |last| {
2064 if (text_block.dbg_info_next) |next| {
2065 // Update existing Decl - non-last item.
2066 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
2067 // It grew too big, so we move it to a new location.
2068 if (text_block.dbg_info_prev) |prev| {
2069 _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
2070 prev.dbg_info_next = text_block.dbg_info_next;
2071 }
2072 next.dbg_info_prev = text_block.dbg_info_prev;
2073 text_block.dbg_info_next = null;
2074 // Populate where it used to be with NOPs.
2075 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
2076 try self.pwriteDbgInfoNops(0, &[0]u8{}, text_block.dbg_info_len, file_pos);
2077 // TODO Look at the free list before appending at the end.
2078 text_block.dbg_info_prev = last;
2079 last.dbg_info_next = text_block;
2080 self.dbg_info_decl_last = text_block;
2081
2082 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
2083 }
2084 } else if (text_block.dbg_info_prev == null) {
2085 // Append new Decl.
2086 // TODO Look at the free list before appending at the end.
2087 text_block.dbg_info_prev = last;
2088 last.dbg_info_next = text_block;
2089 self.dbg_info_decl_last = text_block;
2090
2091 text_block.dbg_info_off = last.dbg_info_off + (last.dbg_info_len * alloc_num / alloc_den);
2092 }
2093 } else {
2094 // This is the first Decl of the .debug_info
2095 self.dbg_info_decl_first = text_block;
2096 self.dbg_info_decl_last = text_block;
2097
2098 text_block.dbg_info_off = self.dbgInfoNeededHeaderBytes() * alloc_num / alloc_den;
2099 }
2100
2101 const last_decl = self.dbg_info_decl_last.?;
2102 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len;
2103 if (needed_size != debug_info_sect.sh_size) {
2104 if (needed_size > self.allocatedSize(debug_info_sect.sh_offset)) {
2105 const new_offset = self.findFreeSpace(needed_size, 1);
2106 const existing_size = last_decl.dbg_info_off;
2107 log.debug(.link, "moving .debug_info section: {} bytes from 0x{x} to 0x{x}\n", .{
2108 existing_size,
2109 debug_info_sect.sh_offset,
2110 new_offset,
2111 });
2112 const amt = try self.base.file.?.copyRangeAll(debug_info_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2113 if (amt != existing_size) return error.InputOutput;
2114 debug_info_sect.sh_offset = new_offset;
2115 }
2116 debug_info_sect.sh_size = needed_size;
2117 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2118 self.debug_info_header_dirty = true;
2119 }
2120 const prev_padding_size: u32 = if (text_block.dbg_info_prev) |prev|
2121 text_block.dbg_info_off - (prev.dbg_info_off + prev.dbg_info_len)
2122 else
2123 0;
2124 const next_padding_size: u32 = if (text_block.dbg_info_next) |next|
2125 next.dbg_info_off - (text_block.dbg_info_off + text_block.dbg_info_len)
2126 else
2127 0;
2128
2129 // We only have support for one compilation unit so far, so the offsets are directly
2130 // from the .debug_info section.
2131 const file_pos = debug_info_sect.sh_offset + text_block.dbg_info_off;
2132 try self.pwriteDbgInfoNops(prev_padding_size, dbg_info_buf, next_padding_size, file_pos);
2133 }
2134
20332135 /// Must be called only after a successful call to `updateDecl`.
20342136 pub fn updateDeclExports(
20352137 self: *Elf,
......@@ -2221,6 +2323,9 @@ pub const File = struct {
22212323 }
22222324
22232325 fn writeSymbol(self: *Elf, index: usize) !void {
2326 const tracy = trace(@src());
2327 defer tracy.end();
2328
22242329 const syms_sect = &self.sections.items[self.symtab_section_index.?];
22252330 // Make sure we are not pointlessly writing symbol data that will have to get relocated
22262331 // due to running out of space.
......@@ -2361,18 +2466,27 @@ pub const File = struct {
23612466
23622467 }
23632468
2469 fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
2470 return 120;
2471 }
2472
2473 const min_nop_size = 2;
2474
23642475 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
23652476 /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
23662477 /// are less than 126,976 bytes (if this limit is ever reached, this function can be
23672478 /// improved to make more than one pwritev call, or the limit can be raised by a fixed
23682479 /// amount by increasing the length of `vecs`).
2369 fn pwriteWithNops(
2480 fn pwriteDbgLineNops(
23702481 self: *Elf,
23712482 prev_padding_size: usize,
23722483 buf: []const u8,
23732484 next_padding_size: usize,
23742485 offset: usize,
23752486 ) !void {
2487 const tracy = trace(@src());
2488 defer tracy.end();
2489
23762490 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;
23772491 const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};
23782492 var vecs: [32]std.os.iovec_const = undefined;
......@@ -2439,7 +2553,66 @@ pub const File = struct {
24392553 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
24402554 }
24412555
2442 const min_nop_size = 2;
2556 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
2557 /// bytes of padding.
2558 fn pwriteDbgInfoNops(
2559 self: *Elf,
2560 prev_padding_size: usize,
2561 buf: []const u8,
2562 next_padding_size: usize,
2563 offset: usize,
2564 ) !void {
2565 const tracy = trace(@src());
2566 defer tracy.end();
2567
2568 const page_of_nops = [1]u8{0} ** 4096;
2569 var vecs: [32]std.os.iovec_const = undefined;
2570 var vec_index: usize = 0;
2571 {
2572 var padding_left = prev_padding_size;
2573 while (padding_left > page_of_nops.len) {
2574 vecs[vec_index] = .{
2575 .iov_base = &page_of_nops,
2576 .iov_len = page_of_nops.len,
2577 };
2578 vec_index += 1;
2579 padding_left -= page_of_nops.len;
2580 }
2581 if (padding_left > 0) {
2582 vecs[vec_index] = .{
2583 .iov_base = &page_of_nops,
2584 .iov_len = padding_left,
2585 };
2586 vec_index += 1;
2587 }
2588 }
2589
2590 vecs[vec_index] = .{
2591 .iov_base = buf.ptr,
2592 .iov_len = buf.len,
2593 };
2594 vec_index += 1;
2595
2596 {
2597 var padding_left = next_padding_size;
2598 while (padding_left > page_of_nops.len) {
2599 vecs[vec_index] = .{
2600 .iov_base = &page_of_nops,
2601 .iov_len = page_of_nops.len,
2602 };
2603 vec_index += 1;
2604 padding_left -= page_of_nops.len;
2605 }
2606 if (padding_left > 0) {
2607 vecs[vec_index] = .{
2608 .iov_base = &page_of_nops,
2609 .iov_len = padding_left,
2610 };
2611 vec_index += 1;
2612 }
2613 }
2614 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2615 }
24432616
24442617 };
24452618};