authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-02 15:54:36+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-30 13:44:49+01:00
log84b65860cfa4b7e61cb98347778331d67137d7e8
tree164290d3b2e86f06e74e02f2ca9d315edaed4e5b
parent55a7affea41a4a1f4e117d7ee55c1c0e8b869203
signaturelock-open Commit is signed but in an unrecognized format.

the world if ElfModule didn't suck:


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};
154154
155pub const Symbol = struct {155pub const Symbol = struct {
156 // MLUGG TODO: remove the defaults and audit everywhere. also grep for '???' across std156 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};
161160
162/// Deprecated because it returns the optimization mode of the standard161/// 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
10401039
1041fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: UnwindError, tty_config: tty.Config) !void {1040fn 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
10541054
1055pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void {1055pub 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
1086fn printLineInfo(1078fn 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;
14891489
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 debug1492 /// 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 debug1493 /// 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;
15051527
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>/debuginfo1628 // $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 symbols1630 // 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);
16321652 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);
16351653
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 };
16401656
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 }
16431662
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 {
16591678
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);
16681687
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 }
16721691
1673 // use the path from .gnu_debuglink, in the same search order as gdb1692 // 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;
16771697
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();
16831706
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 {
16981721
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);
17051728
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 }
17101733
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;
17131736
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};
17801762
1781pub fn getSymbol(di: *Dwarf, allocator: Allocator, endian: Endian, address: u64) !std.debug.Symbol {1763pub 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 {
4141
42const Section = enum { debug_frame, eh_frame };42const Section = enum { debug_frame, eh_frame };
4343
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`. This46/// 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}
8078
79pub 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 header86/// This represents the decoded .eh_frame_hdr header
82pub const EhFrameHeader = struct {87pub 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;
207212
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 this213 // 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;
2525
26pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info {26pub 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);
165161
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 }
403398
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);
407402
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}
12481256
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.
1250fn mapFileOrSelfExe(opt_path: ?[]const u8) ![]align(std.heap.page_size_min) const u8 {1258fn 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 else1261 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();
12561268
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;
12581270
1259 return posix.mmap(1271 return posix.mmap(
1260 null,1272 null,