authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-04-21 00:06:52+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-04-21 00:06:52+02:00
log26153ce73a1b9c49bdf89055b8ab7f4d3173f153
treecae4284d09b99171caf060e1c0504ee53e4ec890
parent1a1b5ee264d8b2219c34d53cc9602692e6d2ba24

dwarf: clean up allocations in std.dwarf module

While this code probably could do with some love and a redesign, this commit fixes the allocations by making sure we explicitly pass an allocator where required, and we use arenas for temporary or narrowly-scoped objects such as a `Die` (for `Die` in particular, not every `FormValue` will be allocated - we could duplicate, or we can use an arena which is the proposal of this commit).

3 files changed, 185 insertions(+), 94 deletions(-)

lib/std/debug.zig+13-8
......@@ -30,10 +30,8 @@ pub const LineInfo = struct {
3030 line: u64,
3131 column: u64,
3232 file_name: []const u8,
33 allocator: ?mem.Allocator,
3433
35 pub fn deinit(self: LineInfo) void {
36 const allocator = self.allocator orelse return;
34 pub fn deinit(self: LineInfo, allocator: mem.Allocator) void {
3735 allocator.free(self.file_name);
3836 }
3937};
......@@ -43,9 +41,9 @@ pub const SymbolInfo = struct {
4341 compile_unit_name: []const u8 = "???",
4442 line_info: ?LineInfo = null,
4543
46 pub fn deinit(self: @This()) void {
44 pub fn deinit(self: @This(), allocator: mem.Allocator) void {
4745 if (self.line_info) |li| {
48 li.deinit();
46 li.deinit(allocator);
4947 }
5048 }
5149};
......@@ -695,7 +693,7 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address
695693 };
696694
697695 const symbol_info = try module.getSymbolAtAddress(address);
698 defer symbol_info.deinit();
696 defer symbol_info.deinit(debug_info.allocator);
699697
700698 return printLineInfo(
701699 out_stream,
......@@ -1568,10 +1566,17 @@ pub const ModuleDebugInfo = switch (native_os) {
15681566 if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {
15691567 return SymbolInfo{
15701568 .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???",
1571 .compile_unit_name = compile_unit.die.getAttrString(o_file_di, DW.AT.name) catch |err| switch (err) {
1569 .compile_unit_name = compile_unit.die.getAttrString(
1570 o_file_di,
1571 DW.AT.name,
1572 ) catch |err| switch (err) {
15721573 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
15731574 },
1574 .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o + addr_off) catch |err| switch (err) {
1575 .line_info = o_file_di.getLineNumberInfo(
1576 self.allocator(),
1577 compile_unit.*,
1578 relocated_address_o + addr_off,
1579 ) catch |err| switch (err) {
15751580 error.MissingDebugInfo, error.InvalidDebugInfo => null,
15761581 else => return err,
15771582 },
lib/std/dwarf.zig+171-83
......@@ -7,8 +7,6 @@ const mem = std.mem;
77const math = std.math;
88const leb = @import("leb128.zig");
99
10const ArrayList = std.ArrayList;
11
1210pub const TAG = @import("dwarf/TAG.zig");
1311pub const AT = @import("dwarf/AT.zig");
1412pub const OP = @import("dwarf/OP.zig");
......@@ -157,6 +155,12 @@ const PcRange = struct {
157155const Func = struct {
158156 pc_range: ?PcRange,
159157 name: ?[]const u8,
158
159 fn deinit(func: *Func, allocator: mem.Allocator) void {
160 if (func.name) |name| {
161 allocator.free(name);
162 }
163 }
160164};
161165
162166const CompileUnit = struct {
......@@ -166,19 +170,30 @@ const CompileUnit = struct {
166170 pc_range: ?PcRange,
167171};
168172
169const AbbrevTable = ArrayList(AbbrevTableEntry);
173const AbbrevTable = std.ArrayList(AbbrevTableEntry);
170174
171175const AbbrevTableHeader = struct {
172176 // offset from .debug_abbrev
173177 offset: u64,
174178 table: AbbrevTable,
179
180 fn deinit(header: *AbbrevTableHeader) void {
181 for (header.table.items) |*entry| {
182 entry.deinit();
183 }
184 header.table.deinit();
185 }
175186};
176187
177188const AbbrevTableEntry = struct {
178189 has_children: bool,
179190 abbrev_code: u64,
180191 tag_id: u64,
181 attrs: ArrayList(AbbrevAttr),
192 attrs: std.ArrayList(AbbrevAttr),
193
194 fn deinit(entry: *AbbrevTableEntry) void {
195 entry.attrs.deinit();
196 }
182197};
183198
184199const AbbrevAttr = struct {
......@@ -213,15 +228,22 @@ const Constant = struct {
213228};
214229
215230const Die = struct {
231 // Arena for Die's Attr's and FormValue's.
232 arena: std.heap.ArenaAllocator,
216233 tag_id: u64,
217234 has_children: bool,
218 attrs: ArrayList(Attr),
235 attrs: std.ArrayListUnmanaged(Attr) = .{},
219236
220237 const Attr = struct {
221238 id: u64,
222239 value: FormValue,
223240 };
224241
242 fn deinit(self: *Die, allocator: mem.Allocator) void {
243 self.arena.deinit();
244 self.attrs.deinit(allocator);
245 }
246
225247 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
226248 for (self.attrs.items) |*attr| {
227249 if (attr.id == id) return &attr.value;
......@@ -292,7 +314,6 @@ const LineNumberProgram = struct {
292314 default_is_stmt: bool,
293315 target_address: u64,
294316 include_dirs: []const []const u8,
295 file_entries: *ArrayList(FileEntry),
296317
297318 prev_valid: bool,
298319 prev_address: u64,
......@@ -323,7 +344,7 @@ const LineNumberProgram = struct {
323344 self.prev_end_sequence = undefined;
324345 }
325346
326 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: u64) LineNumberProgram {
347 pub fn init(is_stmt: bool, include_dirs: []const []const u8, target_address: u64) LineNumberProgram {
327348 return LineNumberProgram{
328349 .address = 0,
329350 .file = 1,
......@@ -333,7 +354,6 @@ const LineNumberProgram = struct {
333354 .basic_block = false,
334355 .end_sequence = false,
335356 .include_dirs = include_dirs,
336 .file_entries = file_entries,
337357 .default_is_stmt = is_stmt,
338358 .target_address = target_address,
339359 .prev_valid = false,
......@@ -347,24 +367,28 @@ const LineNumberProgram = struct {
347367 };
348368 }
349369
350 pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo {
370 pub fn checkLineMatch(
371 self: *LineNumberProgram,
372 allocator: mem.Allocator,
373 file_entries: []const FileEntry,
374 ) !?debug.LineInfo {
351375 if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) {
352376 const file_entry = if (self.prev_file == 0) {
353377 return error.MissingDebugInfo;
354 } else if (self.prev_file - 1 >= self.file_entries.items.len) {
378 } else if (self.prev_file - 1 >= file_entries.len) {
355379 return error.InvalidDebugInfo;
356 } else &self.file_entries.items[self.prev_file - 1];
380 } else &file_entries[self.prev_file - 1];
357381
358382 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
359383 return error.InvalidDebugInfo;
360384 } else self.include_dirs[file_entry.dir_index];
361 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
362 errdefer self.file_entries.allocator.free(file_name);
385
386 const file_name = try fs.path.join(allocator, &[_][]const u8{ dir_name, file_entry.file_name });
387
363388 return debug.LineInfo{
364389 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
365390 .column = self.prev_column,
366391 .file_name = file_name,
367 .allocator = self.file_entries.allocator,
368392 };
369393 }
370394
......@@ -419,8 +443,7 @@ fn parseFormValueBlock(allocator: mem.Allocator, in_stream: anytype, endian: std
419443 return parseFormValueBlockLen(allocator, in_stream, block_len);
420444}
421445
422fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue {
423 _ = allocator;
446fn parseFormValueConstant(in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue {
424447 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
425448 // `nosuspend` should be removed from all the function calls once it is fixed.
426449 return FormValue{
......@@ -447,8 +470,7 @@ fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed:
447470}
448471
449472// TODO the nosuspends here are workarounds
450fn parseFormValueRef(allocator: mem.Allocator, in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue {
451 _ = allocator;
473fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue {
452474 return FormValue{
453475 .Ref = switch (size) {
454476 1 => try nosuspend in_stream.readInt(u8, endian),
......@@ -472,13 +494,13 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
472494 const block_len = try nosuspend leb.readULEB128(usize, in_stream);
473495 return parseFormValueBlockLen(allocator, in_stream, block_len);
474496 },
475 FORM.data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1),
476 FORM.data2 => parseFormValueConstant(allocator, in_stream, false, endian, 2),
477 FORM.data4 => parseFormValueConstant(allocator, in_stream, false, endian, 4),
478 FORM.data8 => parseFormValueConstant(allocator, in_stream, false, endian, 8),
497 FORM.data1 => parseFormValueConstant(in_stream, false, endian, 1),
498 FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),
499 FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),
500 FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8),
479501 FORM.udata, FORM.sdata => {
480502 const signed = form_id == FORM.sdata;
481 return parseFormValueConstant(allocator, in_stream, signed, endian, -1);
503 return parseFormValueConstant(in_stream, signed, endian, -1);
482504 },
483505 FORM.exprloc => {
484506 const size = try nosuspend leb.readULEB128(usize, in_stream);
......@@ -489,11 +511,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
489511 FORM.flag_present => FormValue{ .Flag = true },
490512 FORM.sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) },
491513
492 FORM.ref1 => parseFormValueRef(allocator, in_stream, endian, 1),
493 FORM.ref2 => parseFormValueRef(allocator, in_stream, endian, 2),
494 FORM.ref4 => parseFormValueRef(allocator, in_stream, endian, 4),
495 FORM.ref8 => parseFormValueRef(allocator, in_stream, endian, 8),
496 FORM.ref_udata => parseFormValueRef(allocator, in_stream, endian, -1),
514 FORM.ref1 => parseFormValueRef(in_stream, endian, 1),
515 FORM.ref2 => parseFormValueRef(in_stream, endian, 2),
516 FORM.ref4 => parseFormValueRef(in_stream, endian, 4),
517 FORM.ref8 => parseFormValueRef(in_stream, endian, 8),
518 FORM.ref_udata => parseFormValueRef(in_stream, endian, -1),
497519
498520 FORM.ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) },
499521 FORM.ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) },
......@@ -536,12 +558,24 @@ pub const DwarfInfo = struct {
536558 debug_line_str: ?[]const u8,
537559 debug_ranges: ?[]const u8,
538560 // Filled later by the initializer
539 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
540 compile_unit_list: ArrayList(CompileUnit) = undefined,
541 func_list: ArrayList(Func) = undefined,
561 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
562 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
563 func_list: std.ArrayListUnmanaged(Func) = .{},
542564
543 pub fn allocator(self: DwarfInfo) mem.Allocator {
544 return self.abbrev_table_list.allocator;
565 pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void {
566 for (di.abbrev_table_list.items) |*abbrev| {
567 abbrev.deinit();
568 }
569 di.abbrev_table_list.deinit(allocator);
570 for (di.compile_unit_list.items) |*cu| {
571 cu.die.deinit(allocator);
572 allocator.destroy(cu.die);
573 }
574 di.compile_unit_list.deinit(allocator);
575 for (di.func_list.items) |*func| {
576 func.deinit(allocator);
577 }
578 di.func_list.deinit(allocator);
545579 }
546580
547581 pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
......@@ -556,12 +590,16 @@ pub const DwarfInfo = struct {
556590 return null;
557591 }
558592
559 fn scanAllFunctions(di: *DwarfInfo) !void {
593 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
560594 var stream = io.fixedBufferStream(di.debug_info);
561595 const in = &stream.reader();
562596 const seekable = &stream.seekableStream();
563597 var this_unit_offset: u64 = 0;
564598
599 var tmp_arena = std.heap.ArenaAllocator.init(allocator);
600 defer tmp_arena.deinit();
601 const arena = tmp_arena.allocator();
602
565603 while (this_unit_offset < try seekable.getEndPos()) {
566604 try seekable.seekTo(this_unit_offset);
567605
......@@ -580,26 +618,30 @@ pub const DwarfInfo = struct {
580618 const unit_type = try in.readInt(u8, di.endian);
581619 if (unit_type != UT.compile) return error.InvalidDebugInfo;
582620 address_size = try in.readByte();
583 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
621 debug_abbrev_offset = if (is_64)
622 try in.readInt(u64, di.endian)
623 else
624 try in.readInt(u32, di.endian);
584625 },
585626 else => {
586 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
627 debug_abbrev_offset = if (is_64)
628 try in.readInt(u64, di.endian)
629 else
630 try in.readInt(u32, di.endian);
587631 address_size = try in.readByte();
588632 },
589633 }
590634 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
591635
592636 const compile_unit_pos = try seekable.getPos();
593 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
637 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
594638
595639 try seekable.seekTo(compile_unit_pos);
596640
597641 const next_unit_pos = this_unit_offset + next_offset;
598642
599643 while ((try seekable.getPos()) < next_unit_pos) {
600 const die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse continue;
601 defer die_obj.attrs.deinit();
602
644 const die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue;
603645 const after_die_offset = try seekable.getPos();
604646
605647 switch (die_obj.tag_id) {
......@@ -607,23 +649,33 @@ pub const DwarfInfo = struct {
607649 const fn_name = x: {
608650 var depth: i32 = 3;
609651 var this_die_obj = die_obj;
610 // Prenvent endless loops
652 // Prevent endless loops
611653 while (depth > 0) : (depth -= 1) {
612654 if (this_die_obj.getAttr(AT.name)) |_| {
613655 const name = try this_die_obj.getAttrString(di, AT.name);
614 break :x name;
656 break :x try allocator.dupe(u8, name);
615657 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
616658 // Follow the DIE it points to and repeat
617659 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
618660 if (ref_offset > next_offset) return error.InvalidDebugInfo;
619661 try seekable.seekTo(this_unit_offset + ref_offset);
620 this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
662 this_die_obj = (try di.parseDie(
663 arena,
664 in,
665 abbrev_table,
666 is_64,
667 )) orelse return error.InvalidDebugInfo;
621668 } else if (this_die_obj.getAttr(AT.specification)) |_| {
622669 // Follow the DIE it points to and repeat
623670 const ref_offset = try this_die_obj.getAttrRef(AT.specification);
624671 if (ref_offset > next_offset) return error.InvalidDebugInfo;
625672 try seekable.seekTo(this_unit_offset + ref_offset);
626 this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
673 this_die_obj = (try di.parseDie(
674 arena,
675 in,
676 abbrev_table,
677 is_64,
678 )) orelse return error.InvalidDebugInfo;
627679 } else {
628680 break :x null;
629681 }
......@@ -656,7 +708,7 @@ pub const DwarfInfo = struct {
656708 }
657709 };
658710
659 try di.func_list.append(Func{
711 try di.func_list.append(allocator, Func{
660712 .name = fn_name,
661713 .pc_range = pc_range,
662714 });
......@@ -671,7 +723,7 @@ pub const DwarfInfo = struct {
671723 }
672724 }
673725
674 fn scanAllCompileUnits(di: *DwarfInfo) !void {
726 fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void {
675727 var stream = io.fixedBufferStream(di.debug_info);
676728 const in = &stream.reader();
677729 const seekable = &stream.seekableStream();
......@@ -695,22 +747,30 @@ pub const DwarfInfo = struct {
695747 const unit_type = try in.readInt(u8, di.endian);
696748 if (unit_type != UT.compile) return error.InvalidDebugInfo;
697749 address_size = try in.readByte();
698 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
750 debug_abbrev_offset = if (is_64)
751 try in.readInt(u64, di.endian)
752 else
753 try in.readInt(u32, di.endian);
699754 },
700755 else => {
701 debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
756 debug_abbrev_offset = if (is_64)
757 try in.readInt(u64, di.endian)
758 else
759 try in.readInt(u32, di.endian);
702760 address_size = try in.readByte();
703761 },
704762 }
705763 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
706764
707765 const compile_unit_pos = try seekable.getPos();
708 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
766 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
709767
710768 try seekable.seekTo(compile_unit_pos);
711769
712 const compile_unit_die = try di.allocator().create(Die);
713 compile_unit_die.* = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
770 const compile_unit_die = try allocator.create(Die);
771 errdefer allocator.destroy(compile_unit_die);
772 compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse
773 return error.InvalidDebugInfo;
714774
715775 if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo;
716776
......@@ -738,7 +798,7 @@ pub const DwarfInfo = struct {
738798 }
739799 };
740800
741 try di.compile_unit_list.append(CompileUnit{
801 try di.compile_unit_list.append(allocator, CompileUnit{
742802 .version = version,
743803 .is_64 = is_64,
744804 .pc_range = pc_range,
......@@ -797,27 +857,33 @@ pub const DwarfInfo = struct {
797857
798858 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
799859 /// seeks in the stream and parses it.
800 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
860 fn getAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, abbrev_offset: u64) !*const AbbrevTable {
801861 for (di.abbrev_table_list.items) |*header| {
802862 if (header.offset == abbrev_offset) {
803863 return &header.table;
804864 }
805865 }
806 try di.abbrev_table_list.append(AbbrevTableHeader{
866 try di.abbrev_table_list.append(allocator, AbbrevTableHeader{
807867 .offset = abbrev_offset,
808 .table = try di.parseAbbrevTable(abbrev_offset),
868 .table = try di.parseAbbrevTable(allocator, abbrev_offset),
809869 });
810870 return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1].table;
811871 }
812872
813 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
873 fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable {
814874 var stream = io.fixedBufferStream(di.debug_abbrev);
815875 const in = &stream.reader();
816876 const seekable = &stream.seekableStream();
817877
818878 try seekable.seekTo(offset);
819 var result = AbbrevTable.init(di.allocator());
820 errdefer result.deinit();
879 var result = AbbrevTable.init(allocator);
880 errdefer {
881 for (result.items) |*entry| {
882 entry.attrs.deinit();
883 }
884 result.deinit();
885 }
886
821887 while (true) {
822888 const abbrev_code = try leb.readULEB128(u64, in);
823889 if (abbrev_code == 0) return result;
......@@ -825,7 +891,7 @@ pub const DwarfInfo = struct {
825891 .abbrev_code = abbrev_code,
826892 .tag_id = try leb.readULEB128(u64, in),
827893 .has_children = (try in.readByte()) == CHILDREN.yes,
828 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
894 .attrs = std.ArrayList(AbbrevAttr).init(allocator),
829895 });
830896 const attrs = &result.items[result.items.len - 1].attrs;
831897
......@@ -844,21 +910,34 @@ pub const DwarfInfo = struct {
844910 }
845911 }
846912
847 fn parseDie(di: *DwarfInfo, in_stream: anytype, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
913 fn parseDie(
914 di: *DwarfInfo,
915 allocator: mem.Allocator,
916 in_stream: anytype,
917 abbrev_table: *const AbbrevTable,
918 is_64: bool,
919 ) !?Die {
848920 const abbrev_code = try leb.readULEB128(u64, in_stream);
849921 if (abbrev_code == 0) return null;
850922 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
851923
852924 var result = Die{
925 // Lives as long as the Die.
926 .arena = std.heap.ArenaAllocator.init(allocator),
853927 .tag_id = table_entry.tag_id,
854928 .has_children = table_entry.has_children,
855 .attrs = ArrayList(Die.Attr).init(di.allocator()),
856929 };
857 try result.attrs.resize(table_entry.attrs.items.len);
930 try result.attrs.resize(allocator, table_entry.attrs.items.len);
858931 for (table_entry.attrs.items) |attr, i| {
859932 result.attrs.items[i] = Die.Attr{
860933 .id = attr.attr_id,
861 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, di.endian, is_64),
934 .value = try parseFormValue(
935 result.arena.allocator(),
936 in_stream,
937 attr.form_id,
938 di.endian,
939 is_64,
940 ),
862941 };
863942 if (attr.form_id == FORM.implicit_const) {
864943 result.attrs.items[i].value.Const.payload = @bitCast(u64, attr.payload);
......@@ -867,7 +946,12 @@ pub const DwarfInfo = struct {
867946 return result;
868947 }
869948
870 pub fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: u64) !debug.LineInfo {
949 pub fn getLineNumberInfo(
950 di: *DwarfInfo,
951 allocator: mem.Allocator,
952 compile_unit: CompileUnit,
953 target_address: u64,
954 ) !debug.LineInfo {
871955 var stream = io.fixedBufferStream(di.debug_line);
872956 const in = &stream.reader();
873957 const seekable = &stream.seekableStream();
......@@ -906,8 +990,8 @@ pub const DwarfInfo = struct {
906990
907991 const opcode_base = try in.readByte();
908992
909 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
910 defer di.allocator().free(standard_opcode_lengths);
993 const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1);
994 defer allocator.free(standard_opcode_lengths);
911995
912996 {
913997 var i: usize = 0;
......@@ -916,19 +1000,28 @@ pub const DwarfInfo = struct {
9161000 }
9171001 }
9181002
919 var include_directories = ArrayList([]const u8).init(di.allocator());
1003 var tmp_arena = std.heap.ArenaAllocator.init(allocator);
1004 defer tmp_arena.deinit();
1005 const arena = tmp_arena.allocator();
1006
1007 var include_directories = std.ArrayList([]const u8).init(arena);
9201008 try include_directories.append(compile_unit_cwd);
1009
9211010 while (true) {
922 const dir = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
1011 const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
9231012 if (dir.len == 0) break;
9241013 try include_directories.append(dir);
9251014 }
9261015
927 var file_entries = ArrayList(FileEntry).init(di.allocator());
928 var prog = LineNumberProgram.init(default_is_stmt, include_directories.items, &file_entries, target_address);
1016 var file_entries = std.ArrayList(FileEntry).init(arena);
1017 var prog = LineNumberProgram.init(
1018 default_is_stmt,
1019 include_directories.items,
1020 target_address,
1021 );
9291022
9301023 while (true) {
931 const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
1024 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
9321025 if (file_name.len == 0) break;
9331026 const dir_index = try leb.readULEB128(usize, in);
9341027 const mtime = try leb.readULEB128(usize, in);
......@@ -955,7 +1048,7 @@ pub const DwarfInfo = struct {
9551048 switch (sub_op) {
9561049 LNE.end_sequence => {
9571050 prog.end_sequence = true;
958 if (try prog.checkLineMatch()) |info| return info;
1051 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
9591052 prog.reset();
9601053 },
9611054 LNE.set_address => {
......@@ -963,7 +1056,7 @@ pub const DwarfInfo = struct {
9631056 prog.address = addr;
9641057 },
9651058 LNE.define_file => {
966 const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
1059 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
9671060 const dir_index = try leb.readULEB128(usize, in);
9681061 const mtime = try leb.readULEB128(usize, in);
9691062 const len_bytes = try leb.readULEB128(usize, in);
......@@ -986,12 +1079,12 @@ pub const DwarfInfo = struct {
9861079 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
9871080 prog.line += inc_line;
9881081 prog.address += inc_addr;
989 if (try prog.checkLineMatch()) |info| return info;
1082 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
9901083 prog.basic_block = false;
9911084 } else {
9921085 switch (opcode) {
9931086 LNS.copy => {
994 if (try prog.checkLineMatch()) |info| return info;
1087 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
9951088 prog.basic_block = false;
9961089 },
9971090 LNS.advance_pc => {
......@@ -1068,13 +1161,8 @@ pub const DwarfInfo = struct {
10681161};
10691162
10701163/// Initialize DWARF info. The caller has the responsibility to initialize most
1071/// the DwarfInfo fields before calling. These fields can be left undefined:
1072/// * abbrev_table_list
1073/// * compile_unit_list
1164/// the DwarfInfo fields before calling.
10741165pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
1075 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
1076 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
1077 di.func_list = ArrayList(Func).init(allocator);
1078 try di.scanAllFunctions();
1079 try di.scanAllCompileUnits();
1166 try di.scanAllFunctions(allocator);
1167 try di.scanAllCompileUnits(allocator);
10801168}
src/link/MachO/Object.zig+1-3
......@@ -131,9 +131,7 @@ const DebugInfo = struct {
131131 allocator.free(self.debug_line);
132132 allocator.free(self.debug_line_str);
133133 allocator.free(self.debug_ranges);
134 self.inner.abbrev_table_list.deinit();
135 self.inner.compile_unit_list.deinit();
136 self.inner.func_list.deinit();
134 self.inner.deinit(allocator);
137135 }
138136};
139137