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(...@@ -50,6 +50,7 @@ pub fn generateSymbol(
50 typed_value: TypedValue,50 typed_value: TypedValue,
51 code: *std.ArrayList(u8),51 code: *std.ArrayList(u8),
52 dbg_line: *std.ArrayList(u8),52 dbg_line: *std.ArrayList(u8),
53 dbg_info: *std.ArrayList(u8),
53) GenerateSymbolError!Result {54) GenerateSymbolError!Result {
54 const tracy = trace(@src());55 const tracy = trace(@src());
55 defer tracy.end();56 defer tracy.end();
...@@ -57,61 +58,62 @@ pub fn generateSymbol(...@@ -57,61 +58,62 @@ pub fn generateSymbol(
57 switch (typed_value.ty.zigTypeTag()) {58 switch (typed_value.ty.zigTypeTag()) {
58 .Fn => {59 .Fn => {
59 switch (bin_file.base.options.target.cpu.arch) {60 switch (bin_file.base.options.target.cpu.arch) {
60 //.arm => return Function(.arm).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),
61 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),62 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
62 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line),63 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
63 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line),64 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
64 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line),65 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
65 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line),66 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
66 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line),67 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
67 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line),68 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
68 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),69 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
69 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line),70 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
70 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line),71 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
71 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line),72 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
72 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line),73 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
73 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line),74 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
74 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line),75 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
75 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line),76 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
76 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line),77 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
77 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line),78 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
78 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line),79 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
79 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line),80 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
80 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line),81 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
81 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line),82 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
82 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line),83 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
83 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line),84 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
84 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line),85 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
85 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line),86 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
86 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line),87 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
87 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line),88 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
88 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line),89 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
89 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line),90 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
90 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line),91 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
91 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line),92 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
92 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line),93 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
93 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line),94 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
94 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line),95 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
95 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line),96 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
96 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line),97 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
97 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line),98 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
98 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line),99 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
99 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line),100 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
100 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line),101 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
101 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line),102 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
102 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line),103 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
103 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line),104 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
104 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line),105 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
105 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line),106 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
106 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line),107 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
107 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line),108 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
108 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line),109 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
109 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line),110 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
110 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line),111 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info),
111 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."),112 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."),
112 }113 }
113 },114 },
114 .Array => {115 .Array => {
116 // TODO populate .debug_info for the array
115 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {117 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
116 if (typed_value.ty.arraySentinel()) |sentinel| {118 if (typed_value.ty.arraySentinel()) |sentinel| {
117 try code.ensureCapacity(code.items.len + payload.data.len + 1);119 try code.ensureCapacity(code.items.len + payload.data.len + 1);
...@@ -120,7 +122,7 @@ pub fn generateSymbol(...@@ -120,7 +122,7 @@ pub fn generateSymbol(
120 switch (try generateSymbol(bin_file, src, .{122 switch (try generateSymbol(bin_file, src, .{
121 .ty = typed_value.ty.elemType(),123 .ty = typed_value.ty.elemType(),
122 .val = sentinel,124 .val = sentinel,
123 }, code, dbg_line)) {125 }, code, dbg_line, dbg_info)) {
124 .appended => return Result{ .appended = {} },126 .appended => return Result{ .appended = {} },
125 .externally_managed => |slice| {127 .externally_managed => |slice| {
126 code.appendSliceAssumeCapacity(slice);128 code.appendSliceAssumeCapacity(slice);
...@@ -142,6 +144,8 @@ pub fn generateSymbol(...@@ -142,6 +144,8 @@ pub fn generateSymbol(
142 };144 };
143 },145 },
144 .Pointer => {146 .Pointer => {
147 // TODO populate .debug_info for the pointer
148
145 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {149 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
146 const decl = payload.decl;150 const decl = payload.decl;
147 if (decl.analysis != .complete) return error.AnalysisFail;151 if (decl.analysis != .complete) return error.AnalysisFail;
...@@ -177,6 +181,8 @@ pub fn generateSymbol(...@@ -177,6 +181,8 @@ pub fn generateSymbol(
177 };181 };
178 },182 },
179 .Int => {183 .Int => {
184 // TODO populate .debug_info for the integer
185
180 const info = typed_value.ty.intInfo(bin_file.base.options.target);186 const info = typed_value.ty.intInfo(bin_file.base.options.target);
181 if (info.bits == 8 and !info.signed) {187 if (info.bits == 8 and !info.signed) {
182 const x = typed_value.val.toUnsignedInt();188 const x = typed_value.val.toUnsignedInt();
...@@ -218,6 +224,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -218,6 +224,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
218 mod_fn: *const Module.Fn,224 mod_fn: *const Module.Fn,
219 code: *std.ArrayList(u8),225 code: *std.ArrayList(u8),
220 dbg_line: *std.ArrayList(u8),226 dbg_line: *std.ArrayList(u8),
227 dbg_info: *std.ArrayList(u8),
221 err_msg: ?*ErrorMsg,228 err_msg: ?*ErrorMsg,
222 args: []MCValue,229 args: []MCValue,
223 ret_mcv: MCValue,230 ret_mcv: MCValue,
...@@ -387,6 +394,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -387,6 +394,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
387 typed_value: TypedValue,394 typed_value: TypedValue,
388 code: *std.ArrayList(u8),395 code: *std.ArrayList(u8),
389 dbg_line: *std.ArrayList(u8),396 dbg_line: *std.ArrayList(u8),
397 dbg_info: *std.ArrayList(u8),
390 ) GenerateSymbolError!Result {398 ) GenerateSymbolError!Result {
391 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;399 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 {...@@ -424,6 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
424 .mod_fn = module_fn,432 .mod_fn = module_fn,
425 .code = code,433 .code = code,
426 .dbg_line = dbg_line,434 .dbg_line = dbg_line,
435 .dbg_info = dbg_info,
427 .err_msg = null,436 .err_msg = null,
428 .args = undefined, // populated after `resolveCallingConventionValues`437 .args = undefined, // populated after `resolveCallingConventionValues`
429 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`438 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
src-self-hosted/link.zig+223-50
...@@ -342,9 +342,10 @@ pub const File = struct {...@@ -342,9 +342,10 @@ pub const File = struct {
342 shstrtab_dirty: bool = false,342 shstrtab_dirty: bool = false,
343 debug_strtab_dirty: bool = false,343 debug_strtab_dirty: bool = false,
344 offset_table_count_dirty: bool = false,344 offset_table_count_dirty: bool = false,
345 debug_info_section_dirty: bool = false,
346 debug_abbrev_section_dirty: bool = false,345 debug_abbrev_section_dirty: bool = false,
347 debug_aranges_section_dirty: bool = false,346 debug_aranges_section_dirty: bool = false,
347
348 debug_info_header_dirty: bool = false,
348 debug_line_header_dirty: bool = false,349 debug_line_header_dirty: bool = false,
349350
350 error_flags: ErrorFlags = ErrorFlags{},351 error_flags: ErrorFlags = ErrorFlags{},
...@@ -364,7 +365,7 @@ pub const File = struct {...@@ -364,7 +365,7 @@ pub const File = struct {
364 /// overcapacity can be negative. A simple way to have negative overcapacity is to365 /// overcapacity can be negative. A simple way to have negative overcapacity is to
365 /// allocate a fresh text block, which will have ideal capacity, and then grow it366 /// allocate a fresh text block, which will have ideal capacity, and then grow it
366 /// by 1 byte. It will then have -1 overcapacity.367 /// 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) = .{},
368 last_text_block: ?*TextBlock = null,369 last_text_block: ?*TextBlock = null,
369370
370 /// A list of `SrcFn` whose Line Number Programs have surplus capacity.371 /// A list of `SrcFn` whose Line Number Programs have surplus capacity.
...@@ -373,6 +374,12 @@ pub const File = struct {...@@ -373,6 +374,12 @@ pub const File = struct {
373 dbg_line_fn_first: ?*SrcFn = null,374 dbg_line_fn_first: ?*SrcFn = null,
374 dbg_line_fn_last: ?*SrcFn = null,375 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
376 /// `alloc_num / alloc_den` is the factor of padding when allocating.383 /// `alloc_num / alloc_den` is the factor of padding when allocating.
377 const alloc_num = 4;384 const alloc_num = 4;
378 const alloc_den = 3;385 const alloc_den = 3;
...@@ -398,11 +405,24 @@ pub const File = struct {...@@ -398,11 +405,24 @@ pub const File = struct {
398 prev: ?*TextBlock,405 prev: ?*TextBlock,
399 next: ?*TextBlock,406 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
401 pub const empty = TextBlock{417 pub const empty = TextBlock{
402 .local_sym_index = 0,418 .local_sym_index = 0,
403 .offset_table_index = undefined,419 .offset_table_index = undefined,
404 .prev = null,420 .prev = null,
405 .next = null,421 .next = null,
422 .dbg_info_prev = null,
423 .dbg_info_next = null,
424 .dbg_info_off = undefined,
425 .dbg_info_len = undefined,
406 };426 };
407427
408 /// Returns how much room there is to grow in virtual address space.428 /// Returns how much room there is to grow in virtual address space.
...@@ -566,6 +586,7 @@ pub const File = struct {...@@ -566,6 +586,7 @@ pub const File = struct {
566 self.offset_table_free_list.deinit(self.base.allocator);586 self.offset_table_free_list.deinit(self.base.allocator);
567 self.text_block_free_list.deinit(self.base.allocator);587 self.text_block_free_list.deinit(self.base.allocator);
568 self.dbg_line_fn_free_list.deinit(self.base.allocator);588 self.dbg_line_fn_free_list.deinit(self.base.allocator);
589 self.dbg_info_decl_free_list.deinit(self.base.allocator);
569 self.offset_table.deinit(self.base.allocator);590 self.offset_table.deinit(self.base.allocator);
570 }591 }
571592
...@@ -854,7 +875,7 @@ pub const File = struct {...@@ -854,7 +875,7 @@ pub const File = struct {
854 .sh_entsize = 0,875 .sh_entsize = 0,
855 });876 });
856 self.shdr_table_dirty = true;877 self.shdr_table_dirty = true;
857 self.debug_info_section_dirty = true;878 self.debug_info_header_dirty = true;
858 }879 }
859 if (self.debug_abbrev_section_index == null) {880 if (self.debug_abbrev_section_index == null) {
860 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);881 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
...@@ -1019,21 +1040,36 @@ pub const File = struct {...@@ -1019,21 +1040,36 @@ pub const File = struct {
10191040
1020 self.debug_abbrev_section_dirty = false;1041 self.debug_abbrev_section_dirty = false;
1021 }1042 }
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.?;
1023 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];1049 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
10241050
1025 var di_buf = std.ArrayList(u8).init(self.base.allocator);1051 var di_buf = std.ArrayList(u8).init(self.base.allocator);
1026 defer di_buf.deinit();1052 defer di_buf.deinit();
10271053
1028 // Enough for a 64-bit header and main compilation unit without resizing.1054 // We have a function to compute the upper bound size, because it's needed
1029 try di_buf.ensureCapacity(100);1055 // for determining where to put the offset of the first `LinkBlock`.
1056 try di_buf.ensureCapacity(self.dbgInfoNeededHeaderBytes());
10301057
1031 // initial length - length of the .debug_info contribution for this compilation unit,1058 // initial length - length of the .debug_info contribution for this compilation unit,
1032 // not including the initial length itself.1059 // not including the initial length itself.
1033 // We have to come back and write it later after we know the size.1060 // We have to come back and write it later after we know the size.
1034 const init_len_index = di_buf.items.len;1061 const after_init_len = di_buf.items.len + init_len_size;
1035 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;
1036 const after_init_len = di_buf.items.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 }
1037 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version1073 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 4, target_endian); // DWARF version
1038 const abbrev_offset = self.debug_abbrev_table_offset.?;1074 const abbrev_offset = self.debug_abbrev_table_offset.?;
1039 switch (self.ptr_width) {1075 switch (self.ptr_width) {
...@@ -1068,39 +1104,15 @@ pub const File = struct {...@@ -1068,39 +1104,15 @@ pub const File = struct {
1068 // Until then we say it is C99.1104 // Until then we say it is C99.
1069 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);1105 mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian);
10701106
1071 const init_len = di_buf.items.len - after_init_len;1107 if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) {
1072 switch (self.ptr_width) {1108 // Move the first N decls to the end to make more padding for the header.
1073 .p32 => {1109 @panic("TODO: handle .debug_info header exceeding its padding");
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.?);
1100 }1110 }
11011111 const jmp_amt = first_dbg_info_decl.dbg_info_off - di_buf.items.len;
1102 self.debug_info_section_dirty = false;1112 try self.pwriteDbgInfoNops(0, di_buf.items, jmp_amt, debug_info_sect.sh_offset);
1113 self.debug_info_header_dirty = false;
1103 }1114 }
1115
1104 if (self.debug_aranges_section_dirty) {1116 if (self.debug_aranges_section_dirty) {
1105 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];1117 const debug_aranges_sect = &self.sections.items[self.debug_aranges_section_index.?];
11061118
...@@ -1266,7 +1278,7 @@ pub const File = struct {...@@ -1266,7 +1278,7 @@ pub const File = struct {
1266 @panic("TODO: handle .debug_line header exceeding its padding");1278 @panic("TODO: handle .debug_line header exceeding its padding");
1267 }1279 }
1268 const jmp_amt = dbg_line_prg_off - di_buf.items.len;1280 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);
1270 self.debug_line_header_dirty = false;1282 self.debug_line_header_dirty = false;
1271 }1283 }
12721284
...@@ -1417,8 +1429,7 @@ pub const File = struct {...@@ -1417,8 +1429,7 @@ pub const File = struct {
1417 // The point of flush() is to commit changes, so in theory, nothing should1429 // The point of flush() is to commit changes, so in theory, nothing should
1418 // be dirty after this. However, it is possible for some things to remain1430 // be dirty after this. However, it is possible for some things to remain
1419 // dirty because they fail to be written in the event of compile errors,1431 // dirty because they fail to be written in the event of compile errors,
1420 // such as debug_line_header_dirty.1432 // such as debug_line_header_dirty and debug_info_header_dirty.
1421 assert(!self.debug_info_section_dirty);
1422 assert(!self.debug_abbrev_section_dirty);1433 assert(!self.debug_abbrev_section_dirty);
1423 assert(!self.debug_aranges_section_dirty);1434 assert(!self.debug_aranges_section_dirty);
1424 assert(!self.phdr_table_dirty);1435 assert(!self.phdr_table_dirty);
...@@ -1700,8 +1711,8 @@ pub const File = struct {...@@ -1700,8 +1711,8 @@ pub const File = struct {
17001711
1701 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address1712 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
1702 // range of the compilation unit. When we expand the text section, this range changes,1713 // range of the compilation unit. When we expand the text section, this range changes,
1703 // so the .debug_info section becomes dirty.1714 // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty.
1704 self.debug_info_section_dirty = true;1715 self.debug_info_header_dirty = true;
1705 // This becomes dirty for the same reason. We could potentially make this more1716 // This becomes dirty for the same reason. We could potentially make this more
1706 // fine-grained with the addition of support for more compilation units. It is planned to1717 // fine-grained with the addition of support for more compilation units. It is planned to
1707 // model each package as a different compilation unit.1718 // model each package as a different compilation unit.
...@@ -1815,6 +1826,9 @@ pub const File = struct {...@@ -1815,6 +1826,9 @@ pub const File = struct {
1815 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);1826 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
1816 defer dbg_line_buffer.deinit();1827 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
1818 const typed_value = decl.typed_value.most_recent.typed_value;1832 const typed_value = decl.typed_value.most_recent.typed_value;
1819 const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {1833 const is_fn: bool = switch (typed_value.ty.zigTypeTag()) {
1820 .Fn => true,1834 .Fn => true,
...@@ -1871,7 +1885,7 @@ pub const File = struct {...@@ -1871,7 +1885,7 @@ pub const File = struct {
1871 // do the work of setting prologue_end=true and epilogue_begin=true.1885 // do the work of setting prologue_end=true and epilogue_begin=true.
1872 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);1886 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
1873 }1887 }
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);
1875 const code = switch (res) {1889 const code = switch (res) {
1876 .externally_managed => |x| x,1890 .externally_managed => |x| x,
1877 .appended => code_buffer.items,1891 .appended => code_buffer.items,
...@@ -1937,6 +1951,8 @@ pub const File = struct {...@@ -1937,6 +1951,8 @@ pub const File = struct {
1937 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;1951 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
1938 try self.base.file.?.pwriteAll(code, file_offset);1952 try self.base.file.?.pwriteAll(code, file_offset);
19391953
1954 try self.updateDeclDebugInfo(module, decl, dbg_info_buffer.items);
1955
1940 // If the Decl is a function, we need to update the .debug_line program.1956 // If the Decl is a function, we need to update the .debug_line program.
1941 if (is_fn) {1957 if (is_fn) {
1942 // Perform the relocation based on vaddr.1958 // Perform the relocation based on vaddr.
...@@ -1956,6 +1972,10 @@ pub const File = struct {...@@ -1956,6 +1972,10 @@ pub const File = struct {
19561972
1957 // Now we have the full contents and may allocate a region to store it.1973 // 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
1959 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];1979 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
1960 const src_fn = &decl.fn_link.elf;1980 const src_fn = &decl.fn_link.elf;
1961 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);1981 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
...@@ -1972,7 +1992,7 @@ pub const File = struct {...@@ -1972,7 +1992,7 @@ pub const File = struct {
1972 src_fn.next = null;1992 src_fn.next = null;
1973 // Populate where it used to be with NOPs.1993 // Populate where it used to be with NOPs.
1974 const file_pos = debug_line_sect.sh_offset + src_fn.off;1994 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);
1976 // TODO Look at the free list before appending at the end.1996 // TODO Look at the free list before appending at the end.
1977 src_fn.prev = last;1997 src_fn.prev = last;
1978 last.next = src_fn;1998 last.next = src_fn;
...@@ -2022,7 +2042,7 @@ pub const File = struct {...@@ -2022,7 +2042,7 @@ pub const File = struct {
2022 // We only have support for one compilation unit so far, so the offsets are directly2042 // We only have support for one compilation unit so far, so the offsets are directly
2023 // from the .debug_line section.2043 // from the .debug_line section.
2024 const file_pos = debug_line_sect.sh_offset + src_fn.off;2044 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);
2026 }2046 }
20272047
2028 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.2048 // 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 {...@@ -2030,6 +2050,88 @@ pub const File = struct {
2030 return self.updateDeclExports(module, decl, decl_exports);2050 return self.updateDeclExports(module, decl, decl_exports);
2031 }2051 }
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
2033 /// Must be called only after a successful call to `updateDecl`.2135 /// Must be called only after a successful call to `updateDecl`.
2034 pub fn updateDeclExports(2136 pub fn updateDeclExports(
2035 self: *Elf,2137 self: *Elf,
...@@ -2221,6 +2323,9 @@ pub const File = struct {...@@ -2221,6 +2323,9 @@ pub const File = struct {
2221 }2323 }
22222324
2223 fn writeSymbol(self: *Elf, index: usize) !void {2325 fn writeSymbol(self: *Elf, index: usize) !void {
2326 const tracy = trace(@src());
2327 defer tracy.end();
2328
2224 const syms_sect = &self.sections.items[self.symtab_section_index.?];2329 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2225 // Make sure we are not pointlessly writing symbol data that will have to get relocated2330 // Make sure we are not pointlessly writing symbol data that will have to get relocated
2226 // due to running out of space.2331 // due to running out of space.
...@@ -2361,18 +2466,27 @@ pub const File = struct {...@@ -2361,18 +2466,27 @@ pub const File = struct {
23612466
2362 }2467 }
23632468
2469 fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
2470 return 120;
2471 }
2472
2473 const min_nop_size = 2;
2474
2364 /// Writes to the file a buffer, prefixed and suffixed by the specified number of2475 /// Writes to the file a buffer, prefixed and suffixed by the specified number of
2365 /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes2476 /// bytes of NOPs. Asserts each padding size is at least `min_nop_size` and total padding bytes
2366 /// are less than 126,976 bytes (if this limit is ever reached, this function can be2477 /// are less than 126,976 bytes (if this limit is ever reached, this function can be
2367 /// improved to make more than one pwritev call, or the limit can be raised by a fixed2478 /// improved to make more than one pwritev call, or the limit can be raised by a fixed
2368 /// amount by increasing the length of `vecs`).2479 /// amount by increasing the length of `vecs`).
2369 fn pwriteWithNops(2480 fn pwriteDbgLineNops(
2370 self: *Elf,2481 self: *Elf,
2371 prev_padding_size: usize,2482 prev_padding_size: usize,
2372 buf: []const u8,2483 buf: []const u8,
2373 next_padding_size: usize,2484 next_padding_size: usize,
2374 offset: usize,2485 offset: usize,
2375 ) !void {2486 ) !void {
2487 const tracy = trace(@src());
2488 defer tracy.end();
2489
2376 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;2490 const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096;
2377 const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};2491 const three_byte_nop = [3]u8{DW.LNS_advance_pc, 0b1000_0000, 0};
2378 var vecs: [32]std.os.iovec_const = undefined;2492 var vecs: [32]std.os.iovec_const = undefined;
...@@ -2439,7 +2553,66 @@ pub const File = struct {...@@ -2439,7 +2553,66 @@ pub const File = struct {
2439 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);2553 try self.base.file.?.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
2440 }2554 }
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
2444 };2617 };
2445};2618};