authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-30 10:08:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-28 08:54:23+01:00
log89f86e46d278a35a613bbc662cdd3f65ffc76ed7
treedfde60a1161cd65aeb0bf975a62c4a4310133ed0
parent3f1dead2fc5922b588fbfb108f421ca957d6934a
signaturelock-open Commit is signed but in an unrecognized format.

std: don't use dyld functions on non-macOS Darwin

65922a2d4 started using some (deprecated but still available) dyld functions for stack unwinding and debug information on Darwin targets, because they are significantly faster than `dladdr` (which is the "correct" thing to use). However, these functions are unavailable on Darwin targets other than macOS, for instance on iOS. Therefore, on those targets, we must fall back to the slow `dladdr` path.

1 files changed, 42 insertions(+), 15 deletions(-)

lib/std/debug/SelfInfo/MachO.zig+42-15
......@@ -93,12 +93,28 @@ pub fn getSymbols(
9393pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
9494 _ = si;
9595 _ = io;
96 // This function is marked as deprecated; however, it is significantly more
97 // performant than `dladdr` (since the latter also does a very slow symbol
98 // lookup), so let's use it since it's still available.
99 return std.mem.span(std.c.dyld_image_path_containing_address(
100 @ptrFromInt(address),
101 ) orelse return error.MissingDebugInfo);
96 return getModuleNameInner(address) orelse return error.MissingDebugInfo;
97}
98fn getModuleNameInner(address: usize) ?[]const u8 {
99 switch (builtin.target.os.tag) {
100 .macos => {
101 // This function is marked as deprecated; however, it is significantly more performant
102 // than `dladdr` (since the latter also does a very slow symbol lookup), so let's just
103 // use it for the better performance since it's still available.
104 return std.mem.span(std.c.dyld_image_path_containing_address(
105 @ptrFromInt(address),
106 ) orelse return null);
107 },
108 else => {
109 // On other Darwin systems, the function used above is entirely unavailable, so we have
110 // no choice but to use the slow `dladdr`.
111 var info: std.c.dl_info = undefined;
112 if (std.c.dladdr(@ptrFromInt(address), &info) == 0) {
113 return null;
114 }
115 return std.mem.span(info.fname);
116 },
117 }
102118}
103119pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
104120 const gpa = std.debug.getDebugInfoAllocator();
......@@ -446,12 +462,25 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize {
446462
447463/// Acquires the mutex on success.
448464fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!*Module {
449 // This function is marked as deprecated; however, it is significantly more
450 // performant than `dladdr` (since the latter also does a very slow symbol
451 // lookup), so let's use it since it's still available.
452 const text_base = std.c._dyld_get_image_header_containing_address(
453 @ptrFromInt(address),
454 ) orelse return error.MissingDebugInfo;
465 const text_base: *anyopaque = switch (builtin.target.os.tag) {
466 .macos => base: {
467 // This function is marked as deprecated; however, it is significantly more performant
468 // than `dladdr` (since the latter also does a very slow symbol lookup), so let's just
469 // use it for the better performance since it's still available.
470 break :base std.c._dyld_get_image_header_containing_address(
471 @ptrFromInt(address),
472 ) orelse return error.MissingDebugInfo;
473 },
474 else => base: {
475 // On other Darwin systems, the function used above is entirely unavailable, so we have
476 // no choice but to use the slow `dladdr`.
477 var info: std.c.dl_info = undefined;
478 if (std.c.dladdr(@ptrFromInt(address), &info) == 0) {
479 return error.MissingDebugInfo;
480 }
481 break :base info.fbase;
482 },
483 };
455484 try si.mutex.lock(io);
456485 errdefer si.mutex.unlock(io);
457486 const gop = try si.modules.getOrPutAdapted(gpa, @intFromPtr(text_base), Module.Adapter{});
......@@ -563,9 +592,7 @@ const Module = struct {
563592
564593 fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile {
565594 if (module.file == null) {
566 const path = std.mem.span(
567 std.c.dyld_image_path_containing_address(@ptrFromInt(module.text_base)).?,
568 );
595 const path = getModuleNameInner(module.text_base).?;
569596 module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) {
570597 error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo,
571598 error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e,