authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-04-22 06:34:06+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-22 06:34:06+02:00
log5c501e8dad51f421784bb6fc9671b01016e5ee7f
tree59e2651ee410149813570066783ab33ce3279e0b
parent9c5fe5b5a435729f2bfc61a45dc6ebd0969faf89
parent74bfb8ba07cea0029b86f147834c2b271b38eba7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11485 from ziglang/fix-4353


5 files changed, 279 insertions(+), 125 deletions(-)

lib/std/coff.zig+6-5
......@@ -4,8 +4,6 @@ const mem = std.mem;
44const os = std.os;
55const File = std.fs.File;
66
7const ArrayList = std.ArrayList;
8
97// CoffHeader.machine values
108// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
119const IMAGE_FILE_MACHINE_I386 = 0x014c;
......@@ -117,7 +115,7 @@ pub const Coff = struct {
117115
118116 coff_header: CoffHeader,
119117 pe_header: OptionalHeader,
120 sections: ArrayList(Section),
118 sections: std.ArrayListUnmanaged(Section) = .{},
121119
122120 guid: [16]u8,
123121 age: u32,
......@@ -128,12 +126,15 @@ pub const Coff = struct {
128126 .allocator = allocator,
129127 .coff_header = undefined,
130128 .pe_header = undefined,
131 .sections = ArrayList(Section).init(allocator),
132129 .guid = undefined,
133130 .age = undefined,
134131 };
135132 }
136133
134 pub fn deinit(self: *Coff) void {
135 self.sections.deinit(self.allocator);
136 }
137
137138 pub fn loadHeader(self: *Coff) !void {
138139 const pe_pointer_offset = 0x3C;
139140
......@@ -291,7 +292,7 @@ pub const Coff = struct {
291292 if (self.sections.items.len == self.coff_header.number_of_sections)
292293 return;
293294
294 try self.sections.ensureTotalCapacityPrecise(self.coff_header.number_of_sections);
295 try self.sections.ensureTotalCapacityPrecise(self.allocator, self.coff_header.number_of_sections);
295296
296297 const in = self.in_file.reader();
297298
lib/std/debug.zig+80-33
......@@ -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,15 +41,22 @@ 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: SymbolInfo, allocator: mem.Allocator) void {
4745 if (self.line_info) |li| {
48 li.deinit();
46 li.deinit(allocator);
4947 }
5048 }
5149};
5250const PdbOrDwarf = union(enum) {
5351 pdb: pdb.Pdb,
5452 dwarf: DW.DwarfInfo,
53
54 fn deinit(self: *PdbOrDwarf, allocator: mem.Allocator) void {
55 switch (self.*) {
56 .pdb => |*inner| inner.deinit(),
57 .dwarf => |*inner| inner.deinit(allocator),
58 }
59 }
5560};
5661
5762var stderr_mutex = std.Thread.Mutex{};
......@@ -677,7 +682,6 @@ test "machoSearchSymbols" {
677682 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
678683}
679684
680/// TODO resources https://github.com/ziglang/zig/issues/4353
681685pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
682686 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
683687 error.MissingDebugInfo, error.InvalidDebugInfo => {
......@@ -694,8 +698,8 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address
694698 else => return err,
695699 };
696700
697 const symbol_info = try module.getSymbolAtAddress(address);
698 defer symbol_info.deinit();
701 const symbol_info = try module.getSymbolAtAddress(debug_info.allocator, address);
702 defer symbol_info.deinit(debug_info.allocator);
699703
700704 return printLineInfo(
701705 out_stream,
......@@ -763,7 +767,6 @@ pub const OpenSelfDebugInfoError = error{
763767 UnsupportedOperatingSystem,
764768};
765769
766/// TODO resources https://github.com/ziglang/zig/issues/4353
767770pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
768771 nosuspend {
769772 if (builtin.strip_debug_info)
......@@ -788,13 +791,13 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
788791
789792/// This takes ownership of coff_file: users of this function should not close
790793/// it themselves, even on error.
791/// TODO resources https://github.com/ziglang/zig/issues/4353
792794/// TODO it's weird to take ownership even on error, rework this code.
793795fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
794796 nosuspend {
795797 errdefer coff_file.close();
796798
797799 const coff_obj = try allocator.create(coff.Coff);
800 errdefer allocator.destroy(coff_obj);
798801 coff_obj.* = coff.Coff.init(allocator, coff_file);
799802
800803 var di = ModuleDebugInfo{
......@@ -857,7 +860,6 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
857860
858861/// This takes ownership of elf_file: users of this function should not close
859862/// it themselves, even on error.
860/// TODO resources https://github.com/ziglang/zig/issues/4353
861863/// TODO it's weird to take ownership even on error, rework this code.
862864pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugInfo {
863865 nosuspend {
......@@ -931,7 +933,6 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
931933 }
932934}
933935
934/// TODO resources https://github.com/ziglang/zig/issues/4353
935936/// This takes ownership of macho_file: users of this function should not close
936937/// it themselves, even on error.
937938/// TODO it's weird to take ownership even on error, rework this code.
......@@ -1144,7 +1145,12 @@ pub const DebugInfo = struct {
11441145 }
11451146
11461147 pub fn deinit(self: *DebugInfo) void {
1147 // TODO: resources https://github.com/ziglang/zig/issues/4353
1148 var it = self.address_map.iterator();
1149 while (it.next()) |entry| {
1150 const mdi = entry.value_ptr.*;
1151 mdi.deinit(self.allocator);
1152 self.allocator.destroy(mdi);
1153 }
11481154 self.address_map.deinit();
11491155 }
11501156
......@@ -1383,7 +1389,7 @@ pub const DebugInfo = struct {
13831389pub const ModuleDebugInfo = switch (native_os) {
13841390 .macos, .ios, .watchos, .tvos => struct {
13851391 base_address: usize,
1386 mapped_memory: []const u8,
1392 mapped_memory: []align(mem.page_size) const u8,
13871393 symbols: []const MachoSymbol,
13881394 strings: [:0]const u8,
13891395 ofiles: OFileTable,
......@@ -1394,11 +1400,19 @@ pub const ModuleDebugInfo = switch (native_os) {
13941400 addr_table: std.StringHashMap(u64),
13951401 };
13961402
1397 pub fn allocator(self: @This()) mem.Allocator {
1398 return self.ofiles.allocator;
1403 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1404 var it = self.ofiles.iterator();
1405 while (it.next()) |entry| {
1406 const ofile = entry.value_ptr;
1407 ofile.di.deinit(allocator);
1408 ofile.addr_table.deinit();
1409 }
1410 self.ofiles.deinit();
1411 allocator.free(self.symbols);
1412 os.munmap(self.mapped_memory);
13991413 }
14001414
1401 fn loadOFile(self: *@This(), o_file_path: []const u8) !OFileInfo {
1415 fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo {
14021416 const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking });
14031417 const mapped_mem = try mapWholeFile(o_file);
14041418
......@@ -1450,7 +1464,7 @@ pub const ModuleDebugInfo = switch (native_os) {
14501464 )[0..symtabcmd.?.nsyms];
14511465
14521466 // TODO handle tentative (common) symbols
1453 var addr_table = std.StringHashMap(u64).init(self.allocator());
1467 var addr_table = std.StringHashMap(u64).init(allocator);
14541468 try addr_table.ensureTotalCapacity(@intCast(u32, symtab.len));
14551469 for (symtab) |sym| {
14561470 if (sym.n_strx == 0) continue;
......@@ -1519,7 +1533,7 @@ pub const ModuleDebugInfo = switch (native_os) {
15191533 null,
15201534 };
15211535
1522 try DW.openDwarfDebugInfo(&di, self.allocator());
1536 try DW.openDwarfDebugInfo(&di, allocator);
15231537 var info = OFileInfo{
15241538 .di = di,
15251539 .addr_table = addr_table,
......@@ -1531,7 +1545,7 @@ pub const ModuleDebugInfo = switch (native_os) {
15311545 return info;
15321546 }
15331547
1534 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1548 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
15351549 nosuspend {
15361550 // Translate the VA into an address into this object
15371551 const relocated_address = address - self.base_address;
......@@ -1548,7 +1562,7 @@ pub const ModuleDebugInfo = switch (native_os) {
15481562
15491563 // Check if its debug infos are already in the cache
15501564 var o_file_info = self.ofiles.get(o_file_path) orelse
1551 (self.loadOFile(o_file_path) catch |err| switch (err) {
1565 (self.loadOFile(allocator, o_file_path) catch |err| switch (err) {
15521566 error.FileNotFound,
15531567 error.MissingDebugInfo,
15541568 error.InvalidDebugInfo,
......@@ -1568,10 +1582,17 @@ pub const ModuleDebugInfo = switch (native_os) {
15681582 if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {
15691583 return SymbolInfo{
15701584 .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) {
1585 .compile_unit_name = compile_unit.die.getAttrString(
1586 o_file_di,
1587 DW.AT.name,
1588 ) catch |err| switch (err) {
15721589 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
15731590 },
1574 .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o + addr_off) catch |err| switch (err) {
1591 .line_info = o_file_di.getLineNumberInfo(
1592 allocator,
1593 compile_unit.*,
1594 relocated_address_o + addr_off,
1595 ) catch |err| switch (err) {
15751596 error.MissingDebugInfo, error.InvalidDebugInfo => null,
15761597 else => return err,
15771598 },
......@@ -1592,18 +1613,20 @@ pub const ModuleDebugInfo = switch (native_os) {
15921613 debug_data: PdbOrDwarf,
15931614 coff: *coff.Coff,
15941615
1595 pub fn allocator(self: @This()) mem.Allocator {
1596 return self.coff.allocator;
1616 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1617 self.debug_data.deinit(allocator);
1618 self.coff.deinit();
1619 allocator.destroy(self.coff);
15971620 }
15981621
1599 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1622 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
16001623 // Translate the VA into an address into this object
16011624 const relocated_address = address - self.base_address;
16021625
16031626 switch (self.debug_data) {
16041627 .dwarf => |*dwarf| {
16051628 const dwarf_address = relocated_address + self.coff.pe_header.image_base;
1606 return getSymbolFromDwarf(dwarf_address, dwarf);
1629 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
16071630 },
16081631 .pdb => {
16091632 // fallthrough to pdb handling
......@@ -1649,17 +1672,28 @@ pub const ModuleDebugInfo = switch (native_os) {
16491672 .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct {
16501673 base_address: usize,
16511674 dwarf: DW.DwarfInfo,
1652 mapped_memory: []const u8,
1675 mapped_memory: []align(mem.page_size) const u8,
1676
1677 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1678 self.dwarf.deinit(allocator);
1679 os.munmap(self.mapped_memory);
1680 }
16531681
1654 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1682 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
16551683 // Translate the VA into an address into this object
16561684 const relocated_address = address - self.base_address;
1657 return getSymbolFromDwarf(relocated_address, &self.dwarf);
1685 return getSymbolFromDwarf(allocator, relocated_address, &self.dwarf);
16581686 }
16591687 },
16601688 .wasi => struct {
1661 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1689 fn deinit(self: *@This(), allocator: mem.Allocator) void {
16621690 _ = self;
1691 _ = allocator;
1692 }
1693
1694 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
1695 _ = self;
1696 _ = allocator;
16631697 _ = address;
16641698 return SymbolInfo{};
16651699 }
......@@ -1667,14 +1701,14 @@ pub const ModuleDebugInfo = switch (native_os) {
16671701 else => DW.DwarfInfo,
16681702};
16691703
1670fn getSymbolFromDwarf(address: u64, di: *DW.DwarfInfo) !SymbolInfo {
1704fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo) !SymbolInfo {
16711705 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
16721706 return SymbolInfo{
16731707 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
16741708 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) {
16751709 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
16761710 },
1677 .line_info = nosuspend di.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) {
1711 .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {
16781712 error.MissingDebugInfo, error.InvalidDebugInfo => null,
16791713 else => return err,
16801714 },
......@@ -1895,3 +1929,16 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {
18951929 );
18961930 std.debug.print("{} sp = 0x{x}\n", .{ prefix, sp });
18971931}
1932
1933test "#4353: std.debug should manage resources correctly" {
1934 if (builtin.os.tag == .wasi) return error.SkipZigTest;
1935
1936 const writer = std.io.null_writer;
1937 var di = try openSelfDebugInfo(testing.allocator);
1938 defer di.deinit();
1939 try printSourceAtAddress(&di, writer, showMyTrace(), detectTTYConfig());
1940}
1941
1942noinline fn showMyTrace() usize {
1943 return @returnAddress();
1944}
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}
lib/std/pdb.zig+21-1
......@@ -498,6 +498,15 @@ pub const Pdb = struct {
498498 symbols: []u8,
499499 subsect_info: []u8,
500500 checksum_offset: ?usize,
501
502 pub fn deinit(self: *Module, allocator: mem.Allocator) void {
503 allocator.free(self.module_name);
504 allocator.free(self.obj_file_name);
505 if (self.populated) {
506 allocator.free(self.symbols);
507 allocator.free(self.subsect_info);
508 }
509 }
501510 };
502511
503512 pub fn init(allocator: mem.Allocator, path: []const u8) !Pdb {
......@@ -519,6 +528,10 @@ pub const Pdb = struct {
519528
520529 pub fn deinit(self: *Pdb) void {
521530 self.in_file.close();
531 self.msf.deinit(self.allocator);
532 for (self.modules) |*module| {
533 module.deinit(self.allocator);
534 }
522535 self.allocator.free(self.modules);
523536 self.allocator.free(self.sect_contribs);
524537 }
......@@ -764,7 +777,6 @@ pub const Pdb = struct {
764777 const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
765778
766779 return debug.LineInfo{
767 .allocator = self.allocator,
768780 .file_name = source_file_name,
769781 .line = flags.Start,
770782 .column = column,
......@@ -942,6 +954,14 @@ const Msf = struct {
942954 .streams = streams,
943955 };
944956 }
957
958 fn deinit(self: *Msf, allocator: mem.Allocator) void {
959 allocator.free(self.directory.blocks);
960 for (self.streams) |*stream| {
961 allocator.free(stream.blocks);
962 }
963 allocator.free(self.streams);
964 }
945965};
946966
947967fn blockCountFromSize(size: u32, block_size: u32) u32 {
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