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;...@@ -4,8 +4,6 @@ const mem = std.mem;
4const os = std.os;4const os = std.os;
5const File = std.fs.File;5const File = std.fs.File;
66
7const ArrayList = std.ArrayList;
8
9// CoffHeader.machine values7// CoffHeader.machine values
10// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx8// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
11const IMAGE_FILE_MACHINE_I386 = 0x014c;9const IMAGE_FILE_MACHINE_I386 = 0x014c;
...@@ -117,7 +115,7 @@ pub const Coff = struct {...@@ -117,7 +115,7 @@ pub const Coff = struct {
117115
118 coff_header: CoffHeader,116 coff_header: CoffHeader,
119 pe_header: OptionalHeader,117 pe_header: OptionalHeader,
120 sections: ArrayList(Section),118 sections: std.ArrayListUnmanaged(Section) = .{},
121119
122 guid: [16]u8,120 guid: [16]u8,
123 age: u32,121 age: u32,
...@@ -128,12 +126,15 @@ pub const Coff = struct {...@@ -128,12 +126,15 @@ pub const Coff = struct {
128 .allocator = allocator,126 .allocator = allocator,
129 .coff_header = undefined,127 .coff_header = undefined,
130 .pe_header = undefined,128 .pe_header = undefined,
131 .sections = ArrayList(Section).init(allocator),
132 .guid = undefined,129 .guid = undefined,
133 .age = undefined,130 .age = undefined,
134 };131 };
135 }132 }
136133
134 pub fn deinit(self: *Coff) void {
135 self.sections.deinit(self.allocator);
136 }
137
137 pub fn loadHeader(self: *Coff) !void {138 pub fn loadHeader(self: *Coff) !void {
138 const pe_pointer_offset = 0x3C;139 const pe_pointer_offset = 0x3C;
139140
...@@ -291,7 +292,7 @@ pub const Coff = struct {...@@ -291,7 +292,7 @@ pub const Coff = struct {
291 if (self.sections.items.len == self.coff_header.number_of_sections)292 if (self.sections.items.len == self.coff_header.number_of_sections)
292 return;293 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
296 const in = self.in_file.reader();297 const in = self.in_file.reader();
297298
lib/std/debug.zig+80-33
...@@ -30,10 +30,8 @@ pub const LineInfo = struct {...@@ -30,10 +30,8 @@ pub const LineInfo = struct {
30 line: u64,30 line: u64,
31 column: u64,31 column: u64,
32 file_name: []const u8,32 file_name: []const u8,
33 allocator: ?mem.Allocator,
3433
35 pub fn deinit(self: LineInfo) void {34 pub fn deinit(self: LineInfo, allocator: mem.Allocator) void {
36 const allocator = self.allocator orelse return;
37 allocator.free(self.file_name);35 allocator.free(self.file_name);
38 }36 }
39};37};
...@@ -43,15 +41,22 @@ pub const SymbolInfo = struct {...@@ -43,15 +41,22 @@ pub const SymbolInfo = struct {
43 compile_unit_name: []const u8 = "???",41 compile_unit_name: []const u8 = "???",
44 line_info: ?LineInfo = null,42 line_info: ?LineInfo = null,
4543
46 pub fn deinit(self: @This()) void {44 pub fn deinit(self: SymbolInfo, allocator: mem.Allocator) void {
47 if (self.line_info) |li| {45 if (self.line_info) |li| {
48 li.deinit();46 li.deinit(allocator);
49 }47 }
50 }48 }
51};49};
52const PdbOrDwarf = union(enum) {50const PdbOrDwarf = union(enum) {
53 pdb: pdb.Pdb,51 pdb: pdb.Pdb,
54 dwarf: DW.DwarfInfo,52 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 }
55};60};
5661
57var stderr_mutex = std.Thread.Mutex{};62var stderr_mutex = std.Thread.Mutex{};
...@@ -677,7 +682,6 @@ test "machoSearchSymbols" {...@@ -677,7 +682,6 @@ test "machoSearchSymbols" {
677 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);682 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
678}683}
679684
680/// TODO resources https://github.com/ziglang/zig/issues/4353
681pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {685pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
682 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {686 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
683 error.MissingDebugInfo, error.InvalidDebugInfo => {687 error.MissingDebugInfo, error.InvalidDebugInfo => {
...@@ -694,8 +698,8 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address...@@ -694,8 +698,8 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address
694 else => return err,698 else => return err,
695 };699 };
696700
697 const symbol_info = try module.getSymbolAtAddress(address);701 const symbol_info = try module.getSymbolAtAddress(debug_info.allocator, address);
698 defer symbol_info.deinit();702 defer symbol_info.deinit(debug_info.allocator);
699703
700 return printLineInfo(704 return printLineInfo(
701 out_stream,705 out_stream,
...@@ -763,7 +767,6 @@ pub const OpenSelfDebugInfoError = error{...@@ -763,7 +767,6 @@ pub const OpenSelfDebugInfoError = error{
763 UnsupportedOperatingSystem,767 UnsupportedOperatingSystem,
764};768};
765769
766/// TODO resources https://github.com/ziglang/zig/issues/4353
767pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {770pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
768 nosuspend {771 nosuspend {
769 if (builtin.strip_debug_info)772 if (builtin.strip_debug_info)
...@@ -788,13 +791,13 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {...@@ -788,13 +791,13 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
788791
789/// This takes ownership of coff_file: users of this function should not close792/// This takes ownership of coff_file: users of this function should not close
790/// it themselves, even on error.793/// it themselves, even on error.
791/// TODO resources https://github.com/ziglang/zig/issues/4353
792/// TODO it's weird to take ownership even on error, rework this code.794/// TODO it's weird to take ownership even on error, rework this code.
793fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {795fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
794 nosuspend {796 nosuspend {
795 errdefer coff_file.close();797 errdefer coff_file.close();
796798
797 const coff_obj = try allocator.create(coff.Coff);799 const coff_obj = try allocator.create(coff.Coff);
800 errdefer allocator.destroy(coff_obj);
798 coff_obj.* = coff.Coff.init(allocator, coff_file);801 coff_obj.* = coff.Coff.init(allocator, coff_file);
799802
800 var di = ModuleDebugInfo{803 var di = ModuleDebugInfo{
...@@ -857,7 +860,6 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {...@@ -857,7 +860,6 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
857860
858/// This takes ownership of elf_file: users of this function should not close861/// This takes ownership of elf_file: users of this function should not close
859/// it themselves, even on error.862/// it themselves, even on error.
860/// TODO resources https://github.com/ziglang/zig/issues/4353
861/// TODO it's weird to take ownership even on error, rework this code.863/// TODO it's weird to take ownership even on error, rework this code.
862pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugInfo {864pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugInfo {
863 nosuspend {865 nosuspend {
...@@ -931,7 +933,6 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -931,7 +933,6 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
931 }933 }
932}934}
933935
934/// TODO resources https://github.com/ziglang/zig/issues/4353
935/// This takes ownership of macho_file: users of this function should not close936/// This takes ownership of macho_file: users of this function should not close
936/// it themselves, even on error.937/// it themselves, even on error.
937/// TODO it's weird to take ownership even on error, rework this code.938/// TODO it's weird to take ownership even on error, rework this code.
...@@ -1144,7 +1145,12 @@ pub const DebugInfo = struct {...@@ -1144,7 +1145,12 @@ pub const DebugInfo = struct {
1144 }1145 }
11451146
1146 pub fn deinit(self: *DebugInfo) void {1147 pub fn deinit(self: *DebugInfo) void {
1147 // TODO: resources https://github.com/ziglang/zig/issues/43531148 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 }
1148 self.address_map.deinit();1154 self.address_map.deinit();
1149 }1155 }
11501156
...@@ -1383,7 +1389,7 @@ pub const DebugInfo = struct {...@@ -1383,7 +1389,7 @@ pub const DebugInfo = struct {
1383pub const ModuleDebugInfo = switch (native_os) {1389pub const ModuleDebugInfo = switch (native_os) {
1384 .macos, .ios, .watchos, .tvos => struct {1390 .macos, .ios, .watchos, .tvos => struct {
1385 base_address: usize,1391 base_address: usize,
1386 mapped_memory: []const u8,1392 mapped_memory: []align(mem.page_size) const u8,
1387 symbols: []const MachoSymbol,1393 symbols: []const MachoSymbol,
1388 strings: [:0]const u8,1394 strings: [:0]const u8,
1389 ofiles: OFileTable,1395 ofiles: OFileTable,
...@@ -1394,11 +1400,19 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1394,11 +1400,19 @@ pub const ModuleDebugInfo = switch (native_os) {
1394 addr_table: std.StringHashMap(u64),1400 addr_table: std.StringHashMap(u64),
1395 };1401 };
13961402
1397 pub fn allocator(self: @This()) mem.Allocator {1403 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1398 return self.ofiles.allocator;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);
1399 }1413 }
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 {
1402 const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking });1416 const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking });
1403 const mapped_mem = try mapWholeFile(o_file);1417 const mapped_mem = try mapWholeFile(o_file);
14041418
...@@ -1450,7 +1464,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1450,7 +1464,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1450 )[0..symtabcmd.?.nsyms];1464 )[0..symtabcmd.?.nsyms];
14511465
1452 // TODO handle tentative (common) symbols1466 // TODO handle tentative (common) symbols
1453 var addr_table = std.StringHashMap(u64).init(self.allocator());1467 var addr_table = std.StringHashMap(u64).init(allocator);
1454 try addr_table.ensureTotalCapacity(@intCast(u32, symtab.len));1468 try addr_table.ensureTotalCapacity(@intCast(u32, symtab.len));
1455 for (symtab) |sym| {1469 for (symtab) |sym| {
1456 if (sym.n_strx == 0) continue;1470 if (sym.n_strx == 0) continue;
...@@ -1519,7 +1533,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1519,7 +1533,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1519 null,1533 null,
1520 };1534 };
15211535
1522 try DW.openDwarfDebugInfo(&di, self.allocator());1536 try DW.openDwarfDebugInfo(&di, allocator);
1523 var info = OFileInfo{1537 var info = OFileInfo{
1524 .di = di,1538 .di = di,
1525 .addr_table = addr_table,1539 .addr_table = addr_table,
...@@ -1531,7 +1545,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1531,7 +1545,7 @@ pub const ModuleDebugInfo = switch (native_os) {
1531 return info;1545 return info;
1532 }1546 }
15331547
1534 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {1548 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
1535 nosuspend {1549 nosuspend {
1536 // Translate the VA into an address into this object1550 // Translate the VA into an address into this object
1537 const relocated_address = address - self.base_address;1551 const relocated_address = address - self.base_address;
...@@ -1548,7 +1562,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1548,7 +1562,7 @@ pub const ModuleDebugInfo = switch (native_os) {
15481562
1549 // Check if its debug infos are already in the cache1563 // Check if its debug infos are already in the cache
1550 var o_file_info = self.ofiles.get(o_file_path) orelse1564 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) {
1552 error.FileNotFound,1566 error.FileNotFound,
1553 error.MissingDebugInfo,1567 error.MissingDebugInfo,
1554 error.InvalidDebugInfo,1568 error.InvalidDebugInfo,
...@@ -1568,10 +1582,17 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1568,10 +1582,17 @@ pub const ModuleDebugInfo = switch (native_os) {
1568 if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {1582 if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {
1569 return SymbolInfo{1583 return SymbolInfo{
1570 .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???",1584 .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) {
1572 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1589 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1573 },1590 },
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) {
1575 error.MissingDebugInfo, error.InvalidDebugInfo => null,1596 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1576 else => return err,1597 else => return err,
1577 },1598 },
...@@ -1592,18 +1613,20 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1592,18 +1613,20 @@ pub const ModuleDebugInfo = switch (native_os) {
1592 debug_data: PdbOrDwarf,1613 debug_data: PdbOrDwarf,
1593 coff: *coff.Coff,1614 coff: *coff.Coff,
15941615
1595 pub fn allocator(self: @This()) mem.Allocator {1616 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1596 return self.coff.allocator;1617 self.debug_data.deinit(allocator);
1618 self.coff.deinit();
1619 allocator.destroy(self.coff);
1597 }1620 }
15981621
1599 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {1622 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
1600 // Translate the VA into an address into this object1623 // Translate the VA into an address into this object
1601 const relocated_address = address - self.base_address;1624 const relocated_address = address - self.base_address;
16021625
1603 switch (self.debug_data) {1626 switch (self.debug_data) {
1604 .dwarf => |*dwarf| {1627 .dwarf => |*dwarf| {
1605 const dwarf_address = relocated_address + self.coff.pe_header.image_base;1628 const dwarf_address = relocated_address + self.coff.pe_header.image_base;
1606 return getSymbolFromDwarf(dwarf_address, dwarf);1629 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
1607 },1630 },
1608 .pdb => {1631 .pdb => {
1609 // fallthrough to pdb handling1632 // fallthrough to pdb handling
...@@ -1649,17 +1672,28 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1649,17 +1672,28 @@ pub const ModuleDebugInfo = switch (native_os) {
1649 .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct {1672 .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct {
1650 base_address: usize,1673 base_address: usize,
1651 dwarf: DW.DwarfInfo,1674 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 {
1655 // Translate the VA into an address into this object1683 // Translate the VA into an address into this object
1656 const relocated_address = address - self.base_address;1684 const relocated_address = address - self.base_address;
1657 return getSymbolFromDwarf(relocated_address, &self.dwarf);1685 return getSymbolFromDwarf(allocator, relocated_address, &self.dwarf);
1658 }1686 }
1659 },1687 },
1660 .wasi => struct {1688 .wasi => struct {
1661 pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {1689 fn deinit(self: *@This(), allocator: mem.Allocator) void {
1662 _ = self;1690 _ = self;
1691 _ = allocator;
1692 }
1693
1694 pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
1695 _ = self;
1696 _ = allocator;
1663 _ = address;1697 _ = address;
1664 return SymbolInfo{};1698 return SymbolInfo{};
1665 }1699 }
...@@ -1667,14 +1701,14 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1667,14 +1701,14 @@ pub const ModuleDebugInfo = switch (native_os) {
1667 else => DW.DwarfInfo,1701 else => DW.DwarfInfo,
1668};1702};
16691703
1670fn getSymbolFromDwarf(address: u64, di: *DW.DwarfInfo) !SymbolInfo {1704fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo) !SymbolInfo {
1671 if (nosuspend di.findCompileUnit(address)) |compile_unit| {1705 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
1672 return SymbolInfo{1706 return SymbolInfo{
1673 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",1707 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
1674 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) {1708 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) {
1675 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1709 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1676 },1710 },
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) {
1678 error.MissingDebugInfo, error.InvalidDebugInfo => null,1712 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1679 else => return err,1713 else => return err,
1680 },1714 },
...@@ -1895,3 +1929,16 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {...@@ -1895,3 +1929,16 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {
1895 );1929 );
1896 std.debug.print("{} sp = 0x{x}\n", .{ prefix, sp });1930 std.debug.print("{} sp = 0x{x}\n", .{ prefix, sp });
1897}1931}
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;...@@ -7,8 +7,6 @@ const mem = std.mem;
7const math = std.math;7const math = std.math;
8const leb = @import("leb128.zig");8const leb = @import("leb128.zig");
99
10const ArrayList = std.ArrayList;
11
12pub const TAG = @import("dwarf/TAG.zig");10pub const TAG = @import("dwarf/TAG.zig");
13pub const AT = @import("dwarf/AT.zig");11pub const AT = @import("dwarf/AT.zig");
14pub const OP = @import("dwarf/OP.zig");12pub const OP = @import("dwarf/OP.zig");
...@@ -157,6 +155,12 @@ const PcRange = struct {...@@ -157,6 +155,12 @@ const PcRange = struct {
157const Func = struct {155const Func = struct {
158 pc_range: ?PcRange,156 pc_range: ?PcRange,
159 name: ?[]const u8,157 name: ?[]const u8,
158
159 fn deinit(func: *Func, allocator: mem.Allocator) void {
160 if (func.name) |name| {
161 allocator.free(name);
162 }
163 }
160};164};
161165
162const CompileUnit = struct {166const CompileUnit = struct {
...@@ -166,19 +170,30 @@ const CompileUnit = struct {...@@ -166,19 +170,30 @@ const CompileUnit = struct {
166 pc_range: ?PcRange,170 pc_range: ?PcRange,
167};171};
168172
169const AbbrevTable = ArrayList(AbbrevTableEntry);173const AbbrevTable = std.ArrayList(AbbrevTableEntry);
170174
171const AbbrevTableHeader = struct {175const AbbrevTableHeader = struct {
172 // offset from .debug_abbrev176 // offset from .debug_abbrev
173 offset: u64,177 offset: u64,
174 table: AbbrevTable,178 table: AbbrevTable,
179
180 fn deinit(header: *AbbrevTableHeader) void {
181 for (header.table.items) |*entry| {
182 entry.deinit();
183 }
184 header.table.deinit();
185 }
175};186};
176187
177const AbbrevTableEntry = struct {188const AbbrevTableEntry = struct {
178 has_children: bool,189 has_children: bool,
179 abbrev_code: u64,190 abbrev_code: u64,
180 tag_id: u64,191 tag_id: u64,
181 attrs: ArrayList(AbbrevAttr),192 attrs: std.ArrayList(AbbrevAttr),
193
194 fn deinit(entry: *AbbrevTableEntry) void {
195 entry.attrs.deinit();
196 }
182};197};
183198
184const AbbrevAttr = struct {199const AbbrevAttr = struct {
...@@ -213,15 +228,22 @@ const Constant = struct {...@@ -213,15 +228,22 @@ const Constant = struct {
213};228};
214229
215const Die = struct {230const Die = struct {
231 // Arena for Die's Attr's and FormValue's.
232 arena: std.heap.ArenaAllocator,
216 tag_id: u64,233 tag_id: u64,
217 has_children: bool,234 has_children: bool,
218 attrs: ArrayList(Attr),235 attrs: std.ArrayListUnmanaged(Attr) = .{},
219236
220 const Attr = struct {237 const Attr = struct {
221 id: u64,238 id: u64,
222 value: FormValue,239 value: FormValue,
223 };240 };
224241
242 fn deinit(self: *Die, allocator: mem.Allocator) void {
243 self.arena.deinit();
244 self.attrs.deinit(allocator);
245 }
246
225 fn getAttr(self: *const Die, id: u64) ?*const FormValue {247 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
226 for (self.attrs.items) |*attr| {248 for (self.attrs.items) |*attr| {
227 if (attr.id == id) return &attr.value;249 if (attr.id == id) return &attr.value;
...@@ -292,7 +314,6 @@ const LineNumberProgram = struct {...@@ -292,7 +314,6 @@ const LineNumberProgram = struct {
292 default_is_stmt: bool,314 default_is_stmt: bool,
293 target_address: u64,315 target_address: u64,
294 include_dirs: []const []const u8,316 include_dirs: []const []const u8,
295 file_entries: *ArrayList(FileEntry),
296317
297 prev_valid: bool,318 prev_valid: bool,
298 prev_address: u64,319 prev_address: u64,
...@@ -323,7 +344,7 @@ const LineNumberProgram = struct {...@@ -323,7 +344,7 @@ const LineNumberProgram = struct {
323 self.prev_end_sequence = undefined;344 self.prev_end_sequence = undefined;
324 }345 }
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 {
327 return LineNumberProgram{348 return LineNumberProgram{
328 .address = 0,349 .address = 0,
329 .file = 1,350 .file = 1,
...@@ -333,7 +354,6 @@ const LineNumberProgram = struct {...@@ -333,7 +354,6 @@ const LineNumberProgram = struct {
333 .basic_block = false,354 .basic_block = false,
334 .end_sequence = false,355 .end_sequence = false,
335 .include_dirs = include_dirs,356 .include_dirs = include_dirs,
336 .file_entries = file_entries,
337 .default_is_stmt = is_stmt,357 .default_is_stmt = is_stmt,
338 .target_address = target_address,358 .target_address = target_address,
339 .prev_valid = false,359 .prev_valid = false,
...@@ -347,24 +367,28 @@ const LineNumberProgram = struct {...@@ -347,24 +367,28 @@ const LineNumberProgram = struct {
347 };367 };
348 }368 }
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 {
351 if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) {375 if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) {
352 const file_entry = if (self.prev_file == 0) {376 const file_entry = if (self.prev_file == 0) {
353 return error.MissingDebugInfo;377 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) {
355 return error.InvalidDebugInfo;379 return error.InvalidDebugInfo;
356 } else &self.file_entries.items[self.prev_file - 1];380 } else &file_entries[self.prev_file - 1];
357381
358 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {382 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
359 return error.InvalidDebugInfo;383 return error.InvalidDebugInfo;
360 } else self.include_dirs[file_entry.dir_index];384 } 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 });385
362 errdefer self.file_entries.allocator.free(file_name);386 const file_name = try fs.path.join(allocator, &[_][]const u8{ dir_name, file_entry.file_name });
387
363 return debug.LineInfo{388 return debug.LineInfo{
364 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,389 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
365 .column = self.prev_column,390 .column = self.prev_column,
366 .file_name = file_name,391 .file_name = file_name,
367 .allocator = self.file_entries.allocator,
368 };392 };
369 }393 }
370394
...@@ -419,8 +443,7 @@ fn parseFormValueBlock(allocator: mem.Allocator, in_stream: anytype, endian: std...@@ -419,8 +443,7 @@ fn parseFormValueBlock(allocator: mem.Allocator, in_stream: anytype, endian: std
419 return parseFormValueBlockLen(allocator, in_stream, block_len);443 return parseFormValueBlockLen(allocator, in_stream, block_len);
420}444}
421445
422fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue {446fn parseFormValueConstant(in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue {
423 _ = allocator;
424 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.447 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
425 // `nosuspend` should be removed from all the function calls once it is fixed.448 // `nosuspend` should be removed from all the function calls once it is fixed.
426 return FormValue{449 return FormValue{
...@@ -447,8 +470,7 @@ fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed:...@@ -447,8 +470,7 @@ fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed:
447}470}
448471
449// TODO the nosuspends here are workarounds472// TODO the nosuspends here are workarounds
450fn parseFormValueRef(allocator: mem.Allocator, in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue {473fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue {
451 _ = allocator;
452 return FormValue{474 return FormValue{
453 .Ref = switch (size) {475 .Ref = switch (size) {
454 1 => try nosuspend in_stream.readInt(u8, endian),476 1 => try nosuspend in_stream.readInt(u8, endian),
...@@ -472,13 +494,13 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -472,13 +494,13 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
472 const block_len = try nosuspend leb.readULEB128(usize, in_stream);494 const block_len = try nosuspend leb.readULEB128(usize, in_stream);
473 return parseFormValueBlockLen(allocator, in_stream, block_len);495 return parseFormValueBlockLen(allocator, in_stream, block_len);
474 },496 },
475 FORM.data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1),497 FORM.data1 => parseFormValueConstant(in_stream, false, endian, 1),
476 FORM.data2 => parseFormValueConstant(allocator, in_stream, false, endian, 2),498 FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),
477 FORM.data4 => parseFormValueConstant(allocator, in_stream, false, endian, 4),499 FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),
478 FORM.data8 => parseFormValueConstant(allocator, in_stream, false, endian, 8),500 FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8),
479 FORM.udata, FORM.sdata => {501 FORM.udata, FORM.sdata => {
480 const signed = form_id == FORM.sdata;502 const signed = form_id == FORM.sdata;
481 return parseFormValueConstant(allocator, in_stream, signed, endian, -1);503 return parseFormValueConstant(in_stream, signed, endian, -1);
482 },504 },
483 FORM.exprloc => {505 FORM.exprloc => {
484 const size = try nosuspend leb.readULEB128(usize, in_stream);506 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...@@ -489,11 +511,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
489 FORM.flag_present => FormValue{ .Flag = true },511 FORM.flag_present => FormValue{ .Flag = true },
490 FORM.sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) },512 FORM.sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) },
491513
492 FORM.ref1 => parseFormValueRef(allocator, in_stream, endian, 1),514 FORM.ref1 => parseFormValueRef(in_stream, endian, 1),
493 FORM.ref2 => parseFormValueRef(allocator, in_stream, endian, 2),515 FORM.ref2 => parseFormValueRef(in_stream, endian, 2),
494 FORM.ref4 => parseFormValueRef(allocator, in_stream, endian, 4),516 FORM.ref4 => parseFormValueRef(in_stream, endian, 4),
495 FORM.ref8 => parseFormValueRef(allocator, in_stream, endian, 8),517 FORM.ref8 => parseFormValueRef(in_stream, endian, 8),
496 FORM.ref_udata => parseFormValueRef(allocator, in_stream, endian, -1),518 FORM.ref_udata => parseFormValueRef(in_stream, endian, -1),
497519
498 FORM.ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) },520 FORM.ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) },
499 FORM.ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) },521 FORM.ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) },
...@@ -536,12 +558,24 @@ pub const DwarfInfo = struct {...@@ -536,12 +558,24 @@ pub const DwarfInfo = struct {
536 debug_line_str: ?[]const u8,558 debug_line_str: ?[]const u8,
537 debug_ranges: ?[]const u8,559 debug_ranges: ?[]const u8,
538 // Filled later by the initializer560 // Filled later by the initializer
539 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,561 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
540 compile_unit_list: ArrayList(CompileUnit) = undefined,562 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
541 func_list: ArrayList(Func) = undefined,563 func_list: std.ArrayListUnmanaged(Func) = .{},
542564
543 pub fn allocator(self: DwarfInfo) mem.Allocator {565 pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void {
544 return self.abbrev_table_list.allocator;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);
545 }579 }
546580
547 pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {581 pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
...@@ -556,12 +590,16 @@ pub const DwarfInfo = struct {...@@ -556,12 +590,16 @@ pub const DwarfInfo = struct {
556 return null;590 return null;
557 }591 }
558592
559 fn scanAllFunctions(di: *DwarfInfo) !void {593 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
560 var stream = io.fixedBufferStream(di.debug_info);594 var stream = io.fixedBufferStream(di.debug_info);
561 const in = &stream.reader();595 const in = &stream.reader();
562 const seekable = &stream.seekableStream();596 const seekable = &stream.seekableStream();
563 var this_unit_offset: u64 = 0;597 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
565 while (this_unit_offset < try seekable.getEndPos()) {603 while (this_unit_offset < try seekable.getEndPos()) {
566 try seekable.seekTo(this_unit_offset);604 try seekable.seekTo(this_unit_offset);
567605
...@@ -580,26 +618,30 @@ pub const DwarfInfo = struct {...@@ -580,26 +618,30 @@ pub const DwarfInfo = struct {
580 const unit_type = try in.readInt(u8, di.endian);618 const unit_type = try in.readInt(u8, di.endian);
581 if (unit_type != UT.compile) return error.InvalidDebugInfo;619 if (unit_type != UT.compile) return error.InvalidDebugInfo;
582 address_size = try in.readByte();620 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);
584 },625 },
585 else => {626 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);
587 address_size = try in.readByte();631 address_size = try in.readByte();
588 },632 },
589 }633 }
590 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;634 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
591635
592 const compile_unit_pos = try seekable.getPos();636 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
595 try seekable.seekTo(compile_unit_pos);639 try seekable.seekTo(compile_unit_pos);
596640
597 const next_unit_pos = this_unit_offset + next_offset;641 const next_unit_pos = this_unit_offset + next_offset;
598642
599 while ((try seekable.getPos()) < next_unit_pos) {643 while ((try seekable.getPos()) < next_unit_pos) {
600 const die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse continue;644 const die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue;
601 defer die_obj.attrs.deinit();
602
603 const after_die_offset = try seekable.getPos();645 const after_die_offset = try seekable.getPos();
604646
605 switch (die_obj.tag_id) {647 switch (die_obj.tag_id) {
...@@ -607,23 +649,33 @@ pub const DwarfInfo = struct {...@@ -607,23 +649,33 @@ pub const DwarfInfo = struct {
607 const fn_name = x: {649 const fn_name = x: {
608 var depth: i32 = 3;650 var depth: i32 = 3;
609 var this_die_obj = die_obj;651 var this_die_obj = die_obj;
610 // Prenvent endless loops652 // Prevent endless loops
611 while (depth > 0) : (depth -= 1) {653 while (depth > 0) : (depth -= 1) {
612 if (this_die_obj.getAttr(AT.name)) |_| {654 if (this_die_obj.getAttr(AT.name)) |_| {
613 const name = try this_die_obj.getAttrString(di, AT.name);655 const name = try this_die_obj.getAttrString(di, AT.name);
614 break :x name;656 break :x try allocator.dupe(u8, name);
615 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {657 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
616 // Follow the DIE it points to and repeat658 // Follow the DIE it points to and repeat
617 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);659 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
618 if (ref_offset > next_offset) return error.InvalidDebugInfo;660 if (ref_offset > next_offset) return error.InvalidDebugInfo;
619 try seekable.seekTo(this_unit_offset + ref_offset);661 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;
621 } else if (this_die_obj.getAttr(AT.specification)) |_| {668 } else if (this_die_obj.getAttr(AT.specification)) |_| {
622 // Follow the DIE it points to and repeat669 // Follow the DIE it points to and repeat
623 const ref_offset = try this_die_obj.getAttrRef(AT.specification);670 const ref_offset = try this_die_obj.getAttrRef(AT.specification);
624 if (ref_offset > next_offset) return error.InvalidDebugInfo;671 if (ref_offset > next_offset) return error.InvalidDebugInfo;
625 try seekable.seekTo(this_unit_offset + ref_offset);672 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;
627 } else {679 } else {
628 break :x null;680 break :x null;
629 }681 }
...@@ -656,7 +708,7 @@ pub const DwarfInfo = struct {...@@ -656,7 +708,7 @@ pub const DwarfInfo = struct {
656 }708 }
657 };709 };
658710
659 try di.func_list.append(Func{711 try di.func_list.append(allocator, Func{
660 .name = fn_name,712 .name = fn_name,
661 .pc_range = pc_range,713 .pc_range = pc_range,
662 });714 });
...@@ -671,7 +723,7 @@ pub const DwarfInfo = struct {...@@ -671,7 +723,7 @@ pub const DwarfInfo = struct {
671 }723 }
672 }724 }
673725
674 fn scanAllCompileUnits(di: *DwarfInfo) !void {726 fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void {
675 var stream = io.fixedBufferStream(di.debug_info);727 var stream = io.fixedBufferStream(di.debug_info);
676 const in = &stream.reader();728 const in = &stream.reader();
677 const seekable = &stream.seekableStream();729 const seekable = &stream.seekableStream();
...@@ -695,22 +747,30 @@ pub const DwarfInfo = struct {...@@ -695,22 +747,30 @@ pub const DwarfInfo = struct {
695 const unit_type = try in.readInt(u8, di.endian);747 const unit_type = try in.readInt(u8, di.endian);
696 if (unit_type != UT.compile) return error.InvalidDebugInfo;748 if (unit_type != UT.compile) return error.InvalidDebugInfo;
697 address_size = try in.readByte();749 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);
699 },754 },
700 else => {755 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);
702 address_size = try in.readByte();760 address_size = try in.readByte();
703 },761 },
704 }762 }
705 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;763 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
706764
707 const compile_unit_pos = try seekable.getPos();765 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
710 try seekable.seekTo(compile_unit_pos);768 try seekable.seekTo(compile_unit_pos);
711769
712 const compile_unit_die = try di.allocator().create(Die);770 const compile_unit_die = try allocator.create(Die);
713 compile_unit_die.* = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;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
715 if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo;775 if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo;
716776
...@@ -738,7 +798,7 @@ pub const DwarfInfo = struct {...@@ -738,7 +798,7 @@ pub const DwarfInfo = struct {
738 }798 }
739 };799 };
740800
741 try di.compile_unit_list.append(CompileUnit{801 try di.compile_unit_list.append(allocator, CompileUnit{
742 .version = version,802 .version = version,
743 .is_64 = is_64,803 .is_64 = is_64,
744 .pc_range = pc_range,804 .pc_range = pc_range,
...@@ -797,27 +857,33 @@ pub const DwarfInfo = struct {...@@ -797,27 +857,33 @@ pub const DwarfInfo = struct {
797857
798 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,858 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
799 /// seeks in the stream and parses it.859 /// 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 {
801 for (di.abbrev_table_list.items) |*header| {861 for (di.abbrev_table_list.items) |*header| {
802 if (header.offset == abbrev_offset) {862 if (header.offset == abbrev_offset) {
803 return &header.table;863 return &header.table;
804 }864 }
805 }865 }
806 try di.abbrev_table_list.append(AbbrevTableHeader{866 try di.abbrev_table_list.append(allocator, AbbrevTableHeader{
807 .offset = abbrev_offset,867 .offset = abbrev_offset,
808 .table = try di.parseAbbrevTable(abbrev_offset),868 .table = try di.parseAbbrevTable(allocator, abbrev_offset),
809 });869 });
810 return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1].table;870 return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1].table;
811 }871 }
812872
813 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {873 fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable {
814 var stream = io.fixedBufferStream(di.debug_abbrev);874 var stream = io.fixedBufferStream(di.debug_abbrev);
815 const in = &stream.reader();875 const in = &stream.reader();
816 const seekable = &stream.seekableStream();876 const seekable = &stream.seekableStream();
817877
818 try seekable.seekTo(offset);878 try seekable.seekTo(offset);
819 var result = AbbrevTable.init(di.allocator());879 var result = AbbrevTable.init(allocator);
820 errdefer result.deinit();880 errdefer {
881 for (result.items) |*entry| {
882 entry.attrs.deinit();
883 }
884 result.deinit();
885 }
886
821 while (true) {887 while (true) {
822 const abbrev_code = try leb.readULEB128(u64, in);888 const abbrev_code = try leb.readULEB128(u64, in);
823 if (abbrev_code == 0) return result;889 if (abbrev_code == 0) return result;
...@@ -825,7 +891,7 @@ pub const DwarfInfo = struct {...@@ -825,7 +891,7 @@ pub const DwarfInfo = struct {
825 .abbrev_code = abbrev_code,891 .abbrev_code = abbrev_code,
826 .tag_id = try leb.readULEB128(u64, in),892 .tag_id = try leb.readULEB128(u64, in),
827 .has_children = (try in.readByte()) == CHILDREN.yes,893 .has_children = (try in.readByte()) == CHILDREN.yes,
828 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),894 .attrs = std.ArrayList(AbbrevAttr).init(allocator),
829 });895 });
830 const attrs = &result.items[result.items.len - 1].attrs;896 const attrs = &result.items[result.items.len - 1].attrs;
831897
...@@ -844,21 +910,34 @@ pub const DwarfInfo = struct {...@@ -844,21 +910,34 @@ pub const DwarfInfo = struct {
844 }910 }
845 }911 }
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 {
848 const abbrev_code = try leb.readULEB128(u64, in_stream);920 const abbrev_code = try leb.readULEB128(u64, in_stream);
849 if (abbrev_code == 0) return null;921 if (abbrev_code == 0) return null;
850 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;922 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
851923
852 var result = Die{924 var result = Die{
925 // Lives as long as the Die.
926 .arena = std.heap.ArenaAllocator.init(allocator),
853 .tag_id = table_entry.tag_id,927 .tag_id = table_entry.tag_id,
854 .has_children = table_entry.has_children,928 .has_children = table_entry.has_children,
855 .attrs = ArrayList(Die.Attr).init(di.allocator()),
856 };929 };
857 try result.attrs.resize(table_entry.attrs.items.len);930 try result.attrs.resize(allocator, table_entry.attrs.items.len);
858 for (table_entry.attrs.items) |attr, i| {931 for (table_entry.attrs.items) |attr, i| {
859 result.attrs.items[i] = Die.Attr{932 result.attrs.items[i] = Die.Attr{
860 .id = attr.attr_id,933 .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 ),
862 };941 };
863 if (attr.form_id == FORM.implicit_const) {942 if (attr.form_id == FORM.implicit_const) {
864 result.attrs.items[i].value.Const.payload = @bitCast(u64, attr.payload);943 result.attrs.items[i].value.Const.payload = @bitCast(u64, attr.payload);
...@@ -867,7 +946,12 @@ pub const DwarfInfo = struct {...@@ -867,7 +946,12 @@ pub const DwarfInfo = struct {
867 return result;946 return result;
868 }947 }
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 {
871 var stream = io.fixedBufferStream(di.debug_line);955 var stream = io.fixedBufferStream(di.debug_line);
872 const in = &stream.reader();956 const in = &stream.reader();
873 const seekable = &stream.seekableStream();957 const seekable = &stream.seekableStream();
...@@ -906,8 +990,8 @@ pub const DwarfInfo = struct {...@@ -906,8 +990,8 @@ pub const DwarfInfo = struct {
906990
907 const opcode_base = try in.readByte();991 const opcode_base = try in.readByte();
908992
909 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);993 const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1);
910 defer di.allocator().free(standard_opcode_lengths);994 defer allocator.free(standard_opcode_lengths);
911995
912 {996 {
913 var i: usize = 0;997 var i: usize = 0;
...@@ -916,19 +1000,28 @@ pub const DwarfInfo = struct {...@@ -916,19 +1000,28 @@ pub const DwarfInfo = struct {
916 }1000 }
917 }1001 }
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);
920 try include_directories.append(compile_unit_cwd);1008 try include_directories.append(compile_unit_cwd);
1009
921 while (true) {1010 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));
923 if (dir.len == 0) break;1012 if (dir.len == 0) break;
924 try include_directories.append(dir);1013 try include_directories.append(dir);
925 }1014 }
9261015
927 var file_entries = ArrayList(FileEntry).init(di.allocator());1016 var file_entries = std.ArrayList(FileEntry).init(arena);
928 var prog = LineNumberProgram.init(default_is_stmt, include_directories.items, &file_entries, target_address);1017 var prog = LineNumberProgram.init(
1018 default_is_stmt,
1019 include_directories.items,
1020 target_address,
1021 );
9291022
930 while (true) {1023 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));
932 if (file_name.len == 0) break;1025 if (file_name.len == 0) break;
933 const dir_index = try leb.readULEB128(usize, in);1026 const dir_index = try leb.readULEB128(usize, in);
934 const mtime = try leb.readULEB128(usize, in);1027 const mtime = try leb.readULEB128(usize, in);
...@@ -955,7 +1048,7 @@ pub const DwarfInfo = struct {...@@ -955,7 +1048,7 @@ pub const DwarfInfo = struct {
955 switch (sub_op) {1048 switch (sub_op) {
956 LNE.end_sequence => {1049 LNE.end_sequence => {
957 prog.end_sequence = true;1050 prog.end_sequence = true;
958 if (try prog.checkLineMatch()) |info| return info;1051 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
959 prog.reset();1052 prog.reset();
960 },1053 },
961 LNE.set_address => {1054 LNE.set_address => {
...@@ -963,7 +1056,7 @@ pub const DwarfInfo = struct {...@@ -963,7 +1056,7 @@ pub const DwarfInfo = struct {
963 prog.address = addr;1056 prog.address = addr;
964 },1057 },
965 LNE.define_file => {1058 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));
967 const dir_index = try leb.readULEB128(usize, in);1060 const dir_index = try leb.readULEB128(usize, in);
968 const mtime = try leb.readULEB128(usize, in);1061 const mtime = try leb.readULEB128(usize, in);
969 const len_bytes = try leb.readULEB128(usize, in);1062 const len_bytes = try leb.readULEB128(usize, in);
...@@ -986,12 +1079,12 @@ pub const DwarfInfo = struct {...@@ -986,12 +1079,12 @@ pub const DwarfInfo = struct {
986 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);1079 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
987 prog.line += inc_line;1080 prog.line += inc_line;
988 prog.address += inc_addr;1081 prog.address += inc_addr;
989 if (try prog.checkLineMatch()) |info| return info;1082 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
990 prog.basic_block = false;1083 prog.basic_block = false;
991 } else {1084 } else {
992 switch (opcode) {1085 switch (opcode) {
993 LNS.copy => {1086 LNS.copy => {
994 if (try prog.checkLineMatch()) |info| return info;1087 if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info;
995 prog.basic_block = false;1088 prog.basic_block = false;
996 },1089 },
997 LNS.advance_pc => {1090 LNS.advance_pc => {
...@@ -1068,13 +1161,8 @@ pub const DwarfInfo = struct {...@@ -1068,13 +1161,8 @@ pub const DwarfInfo = struct {
1068};1161};
10691162
1070/// Initialize DWARF info. The caller has the responsibility to initialize most1163/// Initialize DWARF info. The caller has the responsibility to initialize most
1071/// the DwarfInfo fields before calling. These fields can be left undefined:1164/// the DwarfInfo fields before calling.
1072/// * abbrev_table_list
1073/// * compile_unit_list
1074pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {1165pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
1075 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);1166 try di.scanAllFunctions(allocator);
1076 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);1167 try di.scanAllCompileUnits(allocator);
1077 di.func_list = ArrayList(Func).init(allocator);
1078 try di.scanAllFunctions();
1079 try di.scanAllCompileUnits();
1080}1168}
lib/std/pdb.zig+21-1
...@@ -498,6 +498,15 @@ pub const Pdb = struct {...@@ -498,6 +498,15 @@ pub const Pdb = struct {
498 symbols: []u8,498 symbols: []u8,
499 subsect_info: []u8,499 subsect_info: []u8,
500 checksum_offset: ?usize,500 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 }
501 };510 };
502511
503 pub fn init(allocator: mem.Allocator, path: []const u8) !Pdb {512 pub fn init(allocator: mem.Allocator, path: []const u8) !Pdb {
...@@ -519,6 +528,10 @@ pub const Pdb = struct {...@@ -519,6 +528,10 @@ pub const Pdb = struct {
519528
520 pub fn deinit(self: *Pdb) void {529 pub fn deinit(self: *Pdb) void {
521 self.in_file.close();530 self.in_file.close();
531 self.msf.deinit(self.allocator);
532 for (self.modules) |*module| {
533 module.deinit(self.allocator);
534 }
522 self.allocator.free(self.modules);535 self.allocator.free(self.modules);
523 self.allocator.free(self.sect_contribs);536 self.allocator.free(self.sect_contribs);
524 }537 }
...@@ -764,7 +777,6 @@ pub const Pdb = struct {...@@ -764,7 +777,6 @@ pub const Pdb = struct {
764 const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);777 const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
765778
766 return debug.LineInfo{779 return debug.LineInfo{
767 .allocator = self.allocator,
768 .file_name = source_file_name,780 .file_name = source_file_name,
769 .line = flags.Start,781 .line = flags.Start,
770 .column = column,782 .column = column,
...@@ -942,6 +954,14 @@ const Msf = struct {...@@ -942,6 +954,14 @@ const Msf = struct {
942 .streams = streams,954 .streams = streams,
943 };955 };
944 }956 }
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 }
945};965};
946966
947fn blockCountFromSize(size: u32, block_size: u32) u32 {967fn blockCountFromSize(size: u32, block_size: u32) u32 {
src/link/MachO/Object.zig+1-3
...@@ -131,9 +131,7 @@ const DebugInfo = struct {...@@ -131,9 +131,7 @@ const DebugInfo = struct {
131 allocator.free(self.debug_line);131 allocator.free(self.debug_line);
132 allocator.free(self.debug_line_str);132 allocator.free(self.debug_line_str);
133 allocator.free(self.debug_ranges);133 allocator.free(self.debug_ranges);
134 self.inner.abbrev_table_list.deinit();134 self.inner.deinit(allocator);
135 self.inner.compile_unit_list.deinit();
136 self.inner.func_list.deinit();
137 }135 }
138};136};
139137