| author | |
| committer | |
| log | 84b65860cfa4b7e61cb98347778331d67137d7e8 |
| tree | 164290d3b2e86f06e74e02f2ca9d315edaed4e5b |
| parent | 55a7affea41a4a1f4e117d7ee55c1c0e8b869203 |
| signature |
5 files changed, 126 insertions(+), 137 deletions(-)
lib/std/debug.zig+18-26| ... | @@ -153,10 +153,9 @@ pub const SourceLocation = struct { | ... | @@ -153,10 +153,9 @@ pub const SourceLocation = struct { |
| 153 | }; | 153 | }; |
| 154 | 154 | ||
| 155 | pub const Symbol = struct { | 155 | pub const Symbol = struct { |
| 156 | // MLUGG TODO: remove the defaults and audit everywhere. also grep for '???' across std | 156 | name: ?[]const u8, |
| 157 | name: []const u8 = "???", | 157 | compile_unit_name: ?[]const u8, |
| 158 | compile_unit_name: []const u8 = "???", | 158 | source_location: ?SourceLocation, |
| 159 | source_location: ?SourceLocation = null, | ||
| 160 | }; | 159 | }; |
| 161 | 160 | ||
| 162 | /// Deprecated because it returns the optimization mode of the standard | 161 | /// Deprecated because it returns the optimization mode of the standard |
| ... | @@ -1040,10 +1039,11 @@ fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writ | ... | @@ -1040,10 +1039,11 @@ fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writ |
| 1040 | 1039 | ||
| 1041 | fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: UnwindError, tty_config: tty.Config) !void { | 1040 | fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: UnwindError, tty_config: tty.Config) !void { |
| 1042 | const module_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) { | 1041 | const module_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) { |
| 1043 | error.Unexpected, error.OutOfMemory => |e| return e, | ||
| 1044 | error.MissingDebugInfo => "???", | 1042 | error.MissingDebugInfo => "???", |
| 1043 | error.Unexpected, error.OutOfMemory => |e| return e, | ||
| 1045 | }; | 1044 | }; |
| 1046 | try tty_config.setColor(writer, .dim); | 1045 | try tty_config.setColor(writer, .dim); |
| 1046 | // MLUGG TODO this makes no sense given that MissingUnwindInfo exists? | ||
| 1047 | if (unwind_err == error.MissingDebugInfo) { | 1047 | if (unwind_err == error.MissingDebugInfo) { |
| 1048 | try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); | 1048 | try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); |
| 1049 | } else { | 1049 | } else { |
| ... | @@ -1054,35 +1054,27 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwi | ... | @@ -1054,35 +1054,27 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwi |
| 1054 | 1054 | ||
| 1055 | pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void { | 1055 | pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void { |
| 1056 | const gpa = getDebugInfoAllocator(); | 1056 | const gpa = getDebugInfoAllocator(); |
| 1057 | if (debug_info.getSymbolAtAddress(gpa, address)) |symbol_info| { | 1057 | const symbol: Symbol = debug_info.getSymbolAtAddress(gpa, address) catch |err| switch (err) { |
| 1058 | defer if (symbol_info.source_location) |sl| gpa.free(sl.file_name); | 1058 | error.MissingDebugInfo, error.InvalidDebugInfo => .{ |
| 1059 | return printLineInfo( | 1059 | .name = null, |
| 1060 | writer, | 1060 | .compile_unit_name = null, |
| 1061 | symbol_info.source_location, | 1061 | .source_location = null, |
| 1062 | address, | 1062 | }, |
| 1063 | symbol_info.name, | ||
| 1064 | symbol_info.compile_unit_name, | ||
| 1065 | tty_config, | ||
| 1066 | ); | ||
| 1067 | } else |err| switch (err) { | ||
| 1068 | error.MissingDebugInfo, error.InvalidDebugInfo => {}, | ||
| 1069 | else => |e| return e, | 1063 | else => |e| return e, |
| 1070 | } | ||
| 1071 | // Unknown source location, but perhaps we can at least get a module name | ||
| 1072 | const compile_unit_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) { | ||
| 1073 | error.MissingDebugInfo => "???", | ||
| 1074 | error.Unexpected, error.OutOfMemory => |e| return e, | ||
| 1075 | }; | 1064 | }; |
| 1065 | defer if (symbol.source_location) |sl| gpa.free(sl.file_name); | ||
| 1076 | return printLineInfo( | 1066 | return printLineInfo( |
| 1077 | writer, | 1067 | writer, |
| 1078 | null, | 1068 | symbol.source_location, |
| 1079 | address, | 1069 | address, |
| 1080 | "???", | 1070 | symbol.name orelse "???", |
| 1081 | compile_unit_name, | 1071 | symbol.compile_unit_name orelse debug_info.getModuleNameForAddress(gpa, address) catch |err| switch (err) { |
| 1072 | error.MissingDebugInfo => "???", | ||
| 1073 | error.Unexpected, error.OutOfMemory => |e| return e, | ||
| 1074 | }, | ||
| 1082 | tty_config, | 1075 | tty_config, |
| 1083 | ); | 1076 | ); |
| 1084 | } | 1077 | } |
| 1085 | |||
| 1086 | fn printLineInfo( | 1078 | fn printLineInfo( |
| 1087 | writer: *Writer, | 1079 | writer: *Writer, |
| 1088 | source_location: ?SourceLocation, | 1080 | source_location: ?SourceLocation, |
lib/std/debug/Dwarf.zig+68-86| ... | @@ -1487,20 +1487,42 @@ pub const ElfModule = struct { | ... | @@ -1487,20 +1487,42 @@ pub const ElfModule = struct { |
| 1487 | MemoryMappingNotSupported, | 1487 | MemoryMappingNotSupported, |
| 1488 | } || Allocator.Error || std.fs.File.OpenError || OpenError; | 1488 | } || Allocator.Error || std.fs.File.OpenError || OpenError; |
| 1489 | 1489 | ||
| 1490 | /// Reads debug info from an already mapped ELF file. | 1490 | /// Reads debug info from an ELF file given its path. |
| 1491 | /// | 1491 | /// |
| 1492 | /// If the required sections aren't present but a reference to external debug | 1492 | /// If the required sections aren't present but a reference to external debug |
| 1493 | /// info is, then this this function will recurse to attempt to load the debug | 1493 | /// info is, then this this function will recurse to attempt to load the debug |
| 1494 | /// sections from an external file. | 1494 | /// sections from an external file. |
| 1495 | pub fn load( | 1495 | pub fn load( |
| 1496 | gpa: Allocator, | 1496 | gpa: Allocator, |
| 1497 | mapped_mem: []align(std.heap.page_size_min) const u8, | 1497 | elf_file_path: Path, |
| 1498 | build_id: ?[]const u8, | 1498 | build_id: ?[]const u8, |
| 1499 | expected_crc: ?u32, | 1499 | expected_crc: ?u32, |
| 1500 | parent_sections: ?*Dwarf.SectionArray, | 1500 | parent_sections: ?*Dwarf.SectionArray, |
| 1501 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, | 1501 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, |
| 1502 | elf_filename: ?[]const u8, | ||
| 1503 | ) LoadError!ElfModule { | 1502 | ) LoadError!ElfModule { |
| 1503 | const mapped_mem: []align(std.heap.page_size_min) const u8 = mapped: { | ||
| 1504 | const elf_file = try elf_file_path.root_dir.handle.openFile(elf_file_path.sub_path, .{}); | ||
| 1505 | defer elf_file.close(); | ||
| 1506 | |||
| 1507 | const file_len = cast( | ||
| 1508 | usize, | ||
| 1509 | elf_file.getEndPos() catch return bad(), | ||
| 1510 | ) orelse return error.Overflow; | ||
| 1511 | |||
| 1512 | break :mapped std.posix.mmap( | ||
| 1513 | null, | ||
| 1514 | file_len, | ||
| 1515 | std.posix.PROT.READ, | ||
| 1516 | .{ .TYPE = .SHARED }, | ||
| 1517 | elf_file.handle, | ||
| 1518 | 0, | ||
| 1519 | ) catch |err| switch (err) { | ||
| 1520 | error.MappingAlreadyExists => unreachable, | ||
| 1521 | else => |e| return e, | ||
| 1522 | }; | ||
| 1523 | }; | ||
| 1524 | errdefer std.posix.munmap(mapped_mem); | ||
| 1525 | |||
| 1504 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo; | 1526 | if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo; |
| 1505 | 1527 | ||
| 1506 | const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]); | 1528 | const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]); |
| ... | @@ -1606,39 +1628,36 @@ pub const ElfModule = struct { | ... | @@ -1606,39 +1628,36 @@ pub const ElfModule = struct { |
| 1606 | // $XDG_CACHE_HOME/debuginfod_client/<buildid>/debuginfo | 1628 | // $XDG_CACHE_HOME/debuginfod_client/<buildid>/debuginfo |
| 1607 | // This only opportunisticly tries to load from the debuginfod cache, but doesn't try to populate it. | 1629 | // This only opportunisticly tries to load from the debuginfod cache, but doesn't try to populate it. |
| 1608 | // One can manually run `debuginfod-find debuginfo PATH` to download the symbols | 1630 | // One can manually run `debuginfod-find debuginfo PATH` to download the symbols |
| 1609 | if (build_id) |id| blk: { | 1631 | debuginfod: { |
| 1610 | var debuginfod_dir: std.fs.Dir = switch (builtin.os.tag) { | 1632 | const id = build_id orelse break :debuginfod; |
| 1611 | .wasi, .windows => break :blk, | 1633 | switch (builtin.os.tag) { |
| 1612 | else => dir: { | 1634 | .wasi, .windows => break :debuginfod, |
| 1613 | if (std.posix.getenv("DEBUGINFOD_CACHE_PATH")) |path| { | 1635 | else => {}, |
| 1614 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; | 1636 | } |
| 1615 | } | 1637 | const id_dir_path: []u8 = p: { |
| 1616 | if (std.posix.getenv("XDG_CACHE_HOME")) |cache_path| { | 1638 | if (std.posix.getenv("DEBUGINFOD_CACHE_PATH")) |path| { |
| 1617 | if (cache_path.len > 0) { | 1639 | break :p try std.fmt.allocPrint(gpa, "{s}/{x}", .{ path, id }); |
| 1618 | const path = std.fs.path.join(gpa, &[_][]const u8{ cache_path, "debuginfod_client" }) catch break :blk; | 1640 | } |
| 1619 | defer gpa.free(path); | 1641 | if (std.posix.getenv("XDG_CACHE_HOME")) |cache_path| { |
| 1620 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; | 1642 | if (cache_path.len > 0) { |
| 1621 | } | 1643 | break :p try std.fmt.allocPrint(gpa, "{s}/debuginfod_client/{x}", .{ cache_path, id }); |
| 1622 | } | ||
| 1623 | if (std.posix.getenv("HOME")) |home_path| { | ||
| 1624 | const path = std.fs.path.join(gpa, &[_][]const u8{ home_path, ".cache", "debuginfod_client" }) catch break :blk; | ||
| 1625 | defer gpa.free(path); | ||
| 1626 | break :dir std.fs.openDirAbsolute(path, .{}) catch break :blk; | ||
| 1627 | } | 1644 | } |
| 1628 | break :blk; | 1645 | } |
| 1629 | }, | 1646 | if (std.posix.getenv("HOME")) |home_path| { |
| 1647 | break :p try std.fmt.allocPrint(gpa, "{s}/.cache/debuginfod_client/{x}", .{ home_path, id }); | ||
| 1648 | } | ||
| 1649 | break :debuginfod; | ||
| 1630 | }; | 1650 | }; |
| 1631 | defer debuginfod_dir.close(); | 1651 | defer gpa.free(id_dir_path); |
| 1632 | 1652 | if (!std.fs.path.isAbsolute(id_dir_path)) break :debuginfod; | |
| 1633 | const filename = std.fmt.allocPrint(gpa, "{x}/debuginfo", .{id}) catch break :blk; | ||
| 1634 | defer gpa.free(filename); | ||
| 1635 | 1653 | ||
| 1636 | const path: Path = .{ | 1654 | var id_dir = std.fs.openDirAbsolute(id_dir_path, .{}) catch break :debuginfod; |
| 1637 | .root_dir = .{ .path = null, .handle = debuginfod_dir }, | 1655 | defer id_dir.close(); |
| 1638 | .sub_path = filename, | ||
| 1639 | }; | ||
| 1640 | 1656 | ||
| 1641 | return loadPath(gpa, path, null, separate_debug_crc, &sections, mapped_mem) catch break :blk; | 1657 | return load(gpa, .{ |
| 1658 | .root_dir = .{ .path = id_dir_path, .handle = id_dir }, | ||
| 1659 | .sub_path = "debuginfo", | ||
| 1660 | }, null, separate_debug_crc, &sections, mapped_mem) catch break :debuginfod; | ||
| 1642 | } | 1661 | } |
| 1643 | 1662 | ||
| 1644 | const global_debug_directories = [_][]const u8{ | 1663 | const global_debug_directories = [_][]const u8{ |
| ... | @@ -1659,33 +1678,37 @@ pub const ElfModule = struct { | ... | @@ -1659,33 +1678,37 @@ pub const ElfModule = struct { |
| 1659 | 1678 | ||
| 1660 | for (global_debug_directories) |global_directory| { | 1679 | for (global_debug_directories) |global_directory| { |
| 1661 | const path: Path = .{ | 1680 | const path: Path = .{ |
| 1662 | .root_dir = std.Build.Cache.Directory.cwd(), | 1681 | .root_dir = .cwd(), |
| 1663 | .sub_path = try std.fs.path.join(gpa, &.{ | 1682 | .sub_path = try std.fs.path.join(gpa, &.{ |
| 1664 | global_directory, ".build-id", &id_prefix_buf, filename, | 1683 | global_directory, ".build-id", &id_prefix_buf, filename, |
| 1665 | }), | 1684 | }), |
| 1666 | }; | 1685 | }; |
| 1667 | defer gpa.free(path.sub_path); | 1686 | defer gpa.free(path.sub_path); |
| 1668 | 1687 | ||
| 1669 | return loadPath(gpa, path, null, separate_debug_crc, &sections, mapped_mem) catch continue; | 1688 | return load(gpa, path, null, separate_debug_crc, &sections, mapped_mem) catch continue; |
| 1670 | } | 1689 | } |
| 1671 | } | 1690 | } |
| 1672 | 1691 | ||
| 1673 | // use the path from .gnu_debuglink, in the same search order as gdb | 1692 | // use the path from .gnu_debuglink, in the same search order as gdb |
| 1674 | if (separate_debug_filename) |separate_filename| blk: { | 1693 | separate: { |
| 1675 | if (elf_filename != null and mem.eql(u8, elf_filename.?, separate_filename)) | 1694 | const separate_filename = separate_debug_filename orelse break :separate; |
| 1695 | if (mem.eql(u8, std.fs.path.basename(elf_file_path.sub_path), separate_filename)) | ||
| 1676 | return error.MissingDebugInfo; | 1696 | return error.MissingDebugInfo; |
| 1677 | 1697 | ||
| 1678 | exe_dir: { | 1698 | exe_dir: { |
| 1679 | var exe_dir_buf: [std.fs.max_path_bytes]u8 = undefined; | 1699 | const exe_dir_path = try std.fs.path.resolve(gpa, &.{ |
| 1680 | const exe_dir_path = std.fs.selfExeDirPath(&exe_dir_buf) catch break :exe_dir; | 1700 | elf_file_path.root_dir.path orelse ".", |
| 1701 | std.fs.path.dirname(elf_file_path.sub_path) orelse ".", | ||
| 1702 | }); | ||
| 1703 | defer gpa.free(exe_dir_path); | ||
| 1681 | var exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch break :exe_dir; | 1704 | var exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch break :exe_dir; |
| 1682 | defer exe_dir.close(); | 1705 | defer exe_dir.close(); |
| 1683 | 1706 | ||
| 1684 | // <exe_dir>/<gnu_debuglink> | 1707 | // <exe_dir>/<gnu_debuglink> |
| 1685 | if (loadPath( | 1708 | if (load( |
| 1686 | gpa, | 1709 | gpa, |
| 1687 | .{ | 1710 | .{ |
| 1688 | .root_dir = .{ .path = null, .handle = exe_dir }, | 1711 | .root_dir = .{ .path = exe_dir_path, .handle = exe_dir }, |
| 1689 | .sub_path = separate_filename, | 1712 | .sub_path = separate_filename, |
| 1690 | }, | 1713 | }, |
| 1691 | null, | 1714 | null, |
| ... | @@ -1698,27 +1721,27 @@ pub const ElfModule = struct { | ... | @@ -1698,27 +1721,27 @@ pub const ElfModule = struct { |
| 1698 | 1721 | ||
| 1699 | // <exe_dir>/.debug/<gnu_debuglink> | 1722 | // <exe_dir>/.debug/<gnu_debuglink> |
| 1700 | const path: Path = .{ | 1723 | const path: Path = .{ |
| 1701 | .root_dir = .{ .path = null, .handle = exe_dir }, | 1724 | .root_dir = .{ .path = exe_dir_path, .handle = exe_dir }, |
| 1702 | .sub_path = try std.fs.path.join(gpa, &.{ ".debug", separate_filename }), | 1725 | .sub_path = try std.fs.path.join(gpa, &.{ ".debug", separate_filename }), |
| 1703 | }; | 1726 | }; |
| 1704 | defer gpa.free(path.sub_path); | 1727 | defer gpa.free(path.sub_path); |
| 1705 | 1728 | ||
| 1706 | if (loadPath(gpa, path, null, separate_debug_crc, &sections, mapped_mem)) |em| { | 1729 | if (load(gpa, path, null, separate_debug_crc, &sections, mapped_mem)) |em| { |
| 1707 | return em; | 1730 | return em; |
| 1708 | } else |_| {} | 1731 | } else |_| {} |
| 1709 | } | 1732 | } |
| 1710 | 1733 | ||
| 1711 | var cwd_buf: [std.fs.max_path_bytes]u8 = undefined; | 1734 | var cwd_buf: [std.fs.max_path_bytes]u8 = undefined; |
| 1712 | const cwd_path = std.posix.realpath(".", &cwd_buf) catch break :blk; | 1735 | const cwd_path = std.posix.realpath(".", &cwd_buf) catch break :separate; |
| 1713 | 1736 | ||
| 1714 | // <global debug directory>/<absolute folder of current binary>/<gnu_debuglink> | 1737 | // <global debug directory>/<absolute folder of current binary>/<gnu_debuglink> |
| 1715 | for (global_debug_directories) |global_directory| { | 1738 | for (global_debug_directories) |global_directory| { |
| 1716 | const path: Path = .{ | 1739 | const path: Path = .{ |
| 1717 | .root_dir = std.Build.Cache.Directory.cwd(), | 1740 | .root_dir = .cwd(), |
| 1718 | .sub_path = try std.fs.path.join(gpa, &.{ global_directory, cwd_path, separate_filename }), | 1741 | .sub_path = try std.fs.path.join(gpa, &.{ global_directory, cwd_path, separate_filename }), |
| 1719 | }; | 1742 | }; |
| 1720 | defer gpa.free(path.sub_path); | 1743 | defer gpa.free(path.sub_path); |
| 1721 | if (loadPath(gpa, path, null, separate_debug_crc, &sections, mapped_mem)) |em| { | 1744 | if (load(gpa, path, null, separate_debug_crc, &sections, mapped_mem)) |em| { |
| 1722 | return em; | 1745 | return em; |
| 1723 | } else |_| {} | 1746 | } else |_| {} |
| 1724 | } | 1747 | } |
| ... | @@ -1735,47 +1758,6 @@ pub const ElfModule = struct { | ... | @@ -1735,47 +1758,6 @@ pub const ElfModule = struct { |
| 1735 | .dwarf = dwarf, | 1758 | .dwarf = dwarf, |
| 1736 | }; | 1759 | }; |
| 1737 | } | 1760 | } |
| 1738 | |||
| 1739 | pub fn loadPath( | ||
| 1740 | gpa: Allocator, | ||
| 1741 | elf_file_path: Path, | ||
| 1742 | build_id: ?[]const u8, | ||
| 1743 | expected_crc: ?u32, | ||
| 1744 | parent_sections: *Dwarf.SectionArray, | ||
| 1745 | parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8, | ||
| 1746 | ) LoadError!ElfModule { | ||
| 1747 | const elf_file = elf_file_path.root_dir.handle.openFile(elf_file_path.sub_path, .{}) catch |err| switch (err) { | ||
| 1748 | error.FileNotFound => return missing(), | ||
| 1749 | else => return err, | ||
| 1750 | }; | ||
| 1751 | defer elf_file.close(); | ||
| 1752 | |||
| 1753 | const end_pos = elf_file.getEndPos() catch return bad(); | ||
| 1754 | const file_len = cast(usize, end_pos) orelse return error.Overflow; | ||
| 1755 | |||
| 1756 | const mapped_mem = std.posix.mmap( | ||
| 1757 | null, | ||
| 1758 | file_len, | ||
| 1759 | std.posix.PROT.READ, | ||
| 1760 | .{ .TYPE = .SHARED }, | ||
| 1761 | elf_file.handle, | ||
| 1762 | 0, | ||
| 1763 | ) catch |err| switch (err) { | ||
| 1764 | error.MappingAlreadyExists => unreachable, | ||
| 1765 | else => |e| return e, | ||
| 1766 | }; | ||
| 1767 | errdefer std.posix.munmap(mapped_mem); | ||
| 1768 | |||
| 1769 | return load( | ||
| 1770 | gpa, | ||
| 1771 | mapped_mem, | ||
| 1772 | build_id, | ||
| 1773 | expected_crc, | ||
| 1774 | parent_sections, | ||
| 1775 | parent_mapped_mem, | ||
| 1776 | elf_file_path.sub_path, | ||
| 1777 | ); | ||
| 1778 | } | ||
| 1779 | }; | 1761 | }; |
| 1780 | 1762 | ||
| 1781 | pub fn getSymbol(di: *Dwarf, allocator: Allocator, endian: Endian, address: u64) !std.debug.Symbol { | 1763 | pub fn getSymbol(di: *Dwarf, allocator: Allocator, endian: Endian, address: u64) !std.debug.Symbol { |
lib/std/debug/Dwarf/Unwind.zig+7-4| ... | @@ -41,8 +41,6 @@ const SortedFdeEntry = struct { | ... | @@ -41,8 +41,6 @@ const SortedFdeEntry = struct { |
| 41 | 41 | ||
| 42 | const Section = enum { debug_frame, eh_frame }; | 42 | const Section = enum { debug_frame, eh_frame }; |
| 43 | 43 | ||
| 44 | // MLUGG TODO deinit? | ||
| 45 | |||
| 46 | /// Initialize with unwind information from the contents of a `.debug_frame` or `.eh_frame` section. | 44 | /// Initialize with unwind information from the contents of a `.debug_frame` or `.eh_frame` section. |
| 47 | /// | 45 | /// |
| 48 | /// If the `.eh_frame_hdr` section is available, consider instead using `initEhFrameHdr`. This | 46 | /// If the `.eh_frame_hdr` section is available, consider instead using `initEhFrameHdr`. This |
| ... | @@ -78,6 +76,13 @@ pub fn initEhFrameHdr(header: EhFrameHeader, section_vaddr: u64, section_bytes_p | ... | @@ -78,6 +76,13 @@ pub fn initEhFrameHdr(header: EhFrameHeader, section_vaddr: u64, section_bytes_p |
| 78 | }; | 76 | }; |
| 79 | } | 77 | } |
| 80 | 78 | ||
| 79 | pub fn deinit(unwind: *Unwind, gpa: Allocator) void { | ||
| 80 | if (unwind.lookup) |lookup| switch (lookup) { | ||
| 81 | .eh_frame_hdr => {}, | ||
| 82 | .sorted_fdes => |fdes| gpa.free(fdes), | ||
| 83 | }; | ||
| 84 | } | ||
| 85 | |||
| 81 | /// This represents the decoded .eh_frame_hdr header | 86 | /// This represents the decoded .eh_frame_hdr header |
| 82 | pub const EhFrameHeader = struct { | 87 | pub const EhFrameHeader = struct { |
| 83 | eh_frame_vaddr: u64, | 88 | eh_frame_vaddr: u64, |
| ... | @@ -205,8 +210,6 @@ pub const EntryHeader = union(enum) { | ... | @@ -205,8 +210,6 @@ pub const EntryHeader = union(enum) { |
| 205 | const unit_header = try Dwarf.readUnitHeader(r, endian); | 210 | const unit_header = try Dwarf.readUnitHeader(r, endian); |
| 206 | if (unit_header.unit_length == 0) return .terminator; | 211 | if (unit_header.unit_length == 0) return .terminator; |
| 207 | 212 | ||
| 208 | // TODO MLUGG: seriously, just... check the formats of everything in BOTH LSB Core and DWARF. this is a fucking *mess*. maybe add spec references. | ||
| 209 | |||
| 210 | // Next is a value which will disambiguate CIEs and FDEs. Annoyingly, LSB Core makes this | 213 | // Next is a value which will disambiguate CIEs and FDEs. Annoyingly, LSB Core makes this |
| 211 | // value always 4-byte, whereas DWARF makes it depend on the `dwarf.Format`. | 214 | // value always 4-byte, whereas DWARF makes it depend on the `dwarf.Format`. |
| 212 | const cie_ptr_or_id_size: u8 = switch (section) { | 215 | const cie_ptr_or_id_size: u8 = switch (section) { |
lib/std/debug/Info.zig+1-1| ... | @@ -25,7 +25,7 @@ pub const LoadError = Dwarf.ElfModule.LoadError; | ... | @@ -25,7 +25,7 @@ pub const LoadError = Dwarf.ElfModule.LoadError; |
| 25 | 25 | ||
| 26 | pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info { | 26 | pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info { |
| 27 | var sections: Dwarf.SectionArray = Dwarf.null_section_array; | 27 | var sections: Dwarf.SectionArray = Dwarf.null_section_array; |
| 28 | var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null); | 28 | var elf_module = try Dwarf.ElfModule.load(gpa, path, null, null, &sections, null); |
| 29 | try elf_module.dwarf.populateRanges(gpa); | 29 | try elf_module.dwarf.populateRanges(gpa); |
| 30 | var info: Info = .{ | 30 | var info: Info = .{ |
| 31 | .address_map = .{}, | 31 | .address_map = .{}, |
lib/std/debug/SelfInfo.zig+32-20| ... | @@ -156,11 +156,7 @@ const Module = switch (native_os) { | ... | @@ -156,11 +156,7 @@ const Module = switch (native_os) { |
| 156 | return error.MissingDebugInfo; | 156 | return error.MissingDebugInfo; |
| 157 | } | 157 | } |
| 158 | fn loadLocationInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void { | 158 | fn loadLocationInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void { |
| 159 | const mapped_mem = mapFileOrSelfExe(module.name) catch |err| switch (err) { | 159 | const mapped_mem = try mapDebugInfoFile(module.name); |
| 160 | error.FileNotFound => return error.MissingDebugInfo, | ||
| 161 | error.FileTooBig => return error.InvalidDebugInfo, | ||
| 162 | else => |e| return e, | ||
| 163 | }; | ||
| 164 | errdefer posix.munmap(mapped_mem); | 160 | errdefer posix.munmap(mapped_mem); |
| 165 | 161 | ||
| 166 | const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr)); | 162 | const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr)); |
| ... | @@ -311,7 +307,6 @@ const Module = switch (native_os) { | ... | @@ -311,7 +307,6 @@ const Module = switch (native_os) { |
| 311 | gop.value_ptr.* = DebugInfo.loadOFile(gpa, o_file_path) catch |err| { | 307 | gop.value_ptr.* = DebugInfo.loadOFile(gpa, o_file_path) catch |err| { |
| 312 | defer _ = di.full.?.ofiles.pop().?; | 308 | defer _ = di.full.?.ofiles.pop().?; |
| 313 | switch (err) { | 309 | switch (err) { |
| 314 | error.FileNotFound, | ||
| 315 | error.MissingDebugInfo, | 310 | error.MissingDebugInfo, |
| 316 | error.InvalidDebugInfo, | 311 | error.InvalidDebugInfo, |
| 317 | => return sym_only_result, | 312 | => return sym_only_result, |
| ... | @@ -402,7 +397,7 @@ const Module = switch (native_os) { | ... | @@ -402,7 +397,7 @@ const Module = switch (native_os) { |
| 402 | } | 397 | } |
| 403 | 398 | ||
| 404 | fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { | 399 | fn loadOFile(gpa: Allocator, o_file_path: []const u8) !OFile { |
| 405 | const mapped_mem = try mapFileOrSelfExe(o_file_path); | 400 | const mapped_mem = try mapDebugInfoFile(o_file_path); |
| 406 | errdefer posix.munmap(mapped_mem); | 401 | errdefer posix.munmap(mapped_mem); |
| 407 | 402 | ||
| 408 | if (mapped_mem.len < @sizeOf(macho.mach_header_64)) return error.InvalidDebugInfo; | 403 | if (mapped_mem.len < @sizeOf(macho.mach_header_64)) return error.InvalidDebugInfo; |
| ... | @@ -595,14 +590,27 @@ const Module = switch (native_os) { | ... | @@ -595,14 +590,27 @@ const Module = switch (native_os) { |
| 595 | return error.MissingDebugInfo; | 590 | return error.MissingDebugInfo; |
| 596 | } | 591 | } |
| 597 | fn loadLocationInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void { | 592 | fn loadLocationInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void { |
| 598 | const filename: ?[]const u8 = if (module.name.len > 0) module.name else null; | 593 | if (module.name.len > 0) { |
| 599 | const mapped_mem = mapFileOrSelfExe(filename) catch |err| switch (err) { | 594 | di.em = Dwarf.ElfModule.load(gpa, .{ |
| 600 | error.FileNotFound => return error.MissingDebugInfo, | 595 | .root_dir = .cwd(), |
| 601 | error.FileTooBig => return error.InvalidDebugInfo, | 596 | .sub_path = module.name, |
| 602 | else => |e| return e, | 597 | }, module.build_id, null, null, null) catch |err| switch (err) { |
| 603 | }; | 598 | error.FileNotFound => return error.MissingDebugInfo, |
| 604 | errdefer posix.munmap(mapped_mem); | 599 | error.Overflow => return error.InvalidDebugInfo, |
| 605 | di.em = try .load(gpa, mapped_mem, module.build_id, null, null, null, filename); | 600 | else => |e| return e, |
| 601 | }; | ||
| 602 | } else { | ||
| 603 | const path = try std.fs.selfExePathAlloc(gpa); | ||
| 604 | defer gpa.free(path); | ||
| 605 | di.em = Dwarf.ElfModule.load(gpa, .{ | ||
| 606 | .root_dir = .cwd(), | ||
| 607 | .sub_path = path, | ||
| 608 | }, module.build_id, null, null, null) catch |err| switch (err) { | ||
| 609 | error.FileNotFound => return error.MissingDebugInfo, | ||
| 610 | error.Overflow => return error.InvalidDebugInfo, | ||
| 611 | else => |e| return e, | ||
| 612 | }; | ||
| 613 | } | ||
| 606 | } | 614 | } |
| 607 | fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol { | 615 | fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol { |
| 608 | if (di.em == null) try module.loadLocationInfo(gpa, di); | 616 | if (di.em == null) try module.loadLocationInfo(gpa, di); |
| ... | @@ -1247,14 +1255,18 @@ fn applyOffset(base: usize, offset: i64) !usize { | ... | @@ -1247,14 +1255,18 @@ fn applyOffset(base: usize, offset: i64) !usize { |
| 1247 | } | 1255 | } |
| 1248 | 1256 | ||
| 1249 | /// Uses `mmap` to map the file at `opt_path` (or, if `null`, the self executable image) into memory. | 1257 | /// Uses `mmap` to map the file at `opt_path` (or, if `null`, the self executable image) into memory. |
| 1250 | fn mapFileOrSelfExe(opt_path: ?[]const u8) ![]align(std.heap.page_size_min) const u8 { | 1258 | fn mapDebugInfoFile(opt_path: ?[]const u8) ![]align(std.heap.page_size_min) const u8 { |
| 1251 | const file = if (opt_path) |path| | 1259 | const open_result = if (opt_path) |path| |
| 1252 | try fs.cwd().openFile(path, .{}) | 1260 | fs.cwd().openFile(path, .{}) |
| 1253 | else | 1261 | else |
| 1254 | try fs.openSelfExe(.{}); | 1262 | fs.openSelfExe(.{}); |
| 1263 | const file = open_result catch |err| switch (err) { | ||
| 1264 | error.FileNotFound => return error.MissingDebugInfo, | ||
| 1265 | else => |e| return e, | ||
| 1266 | }; | ||
| 1255 | defer file.close(); | 1267 | defer file.close(); |
| 1256 | 1268 | ||
| 1257 | const file_len = math.cast(usize, try file.getEndPos()) orelse return error.FileTooBig; | 1269 | const file_len = math.cast(usize, try file.getEndPos()) orelse return error.InvalidDebugInfo; |
| 1258 | 1270 | ||
| 1259 | return posix.mmap( | 1271 | return posix.mmap( |
| 1260 | null, | 1272 | null, |