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(...@@ -93,12 +93,28 @@ pub fn getSymbols(
93pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {93pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
94 _ = si;94 _ = si;
95 _ = io;95 _ = io;
96 // This function is marked as deprecated; however, it is significantly more96 return getModuleNameInner(address) orelse return error.MissingDebugInfo;
97 // performant than `dladdr` (since the latter also does a very slow symbol97}
98 // lookup), so let's use it since it's still available.98fn getModuleNameInner(address: usize) ?[]const u8 {
99 return std.mem.span(std.c.dyld_image_path_containing_address(99 switch (builtin.target.os.tag) {
100 @ptrFromInt(address),100 .macos => {
101 ) orelse return error.MissingDebugInfo);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 }
102}118}
103pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {119pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize {
104 const gpa = std.debug.getDebugInfoAllocator();120 const gpa = std.debug.getDebugInfoAllocator();
...@@ -446,12 +462,25 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize {...@@ -446,12 +462,25 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize {
446462
447/// Acquires the mutex on success.463/// Acquires the mutex on success.
448fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!*Module {464fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!*Module {
449 // This function is marked as deprecated; however, it is significantly more465 const text_base: *anyopaque = switch (builtin.target.os.tag) {
450 // performant than `dladdr` (since the latter also does a very slow symbol466 .macos => base: {
451 // lookup), so let's use it since it's still available.467 // This function is marked as deprecated; however, it is significantly more performant
452 const text_base = std.c._dyld_get_image_header_containing_address(468 // than `dladdr` (since the latter also does a very slow symbol lookup), so let's just
453 @ptrFromInt(address),469 // use it for the better performance since it's still available.
454 ) orelse return error.MissingDebugInfo;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 };
455 try si.mutex.lock(io);484 try si.mutex.lock(io);
456 errdefer si.mutex.unlock(io);485 errdefer si.mutex.unlock(io);
457 const gop = try si.modules.getOrPutAdapted(gpa, @intFromPtr(text_base), Module.Adapter{});486 const gop = try si.modules.getOrPutAdapted(gpa, @intFromPtr(text_base), Module.Adapter{});
...@@ -563,9 +592,7 @@ const Module = struct {...@@ -563,9 +592,7 @@ const Module = struct {
563592
564 fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile {593 fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile {
565 if (module.file == null) {594 if (module.file == null) {
566 const path = std.mem.span(595 const path = getModuleNameInner(module.text_base).?;
567 std.c.dyld_image_path_containing_address(@ptrFromInt(module.text_base)).?,
568 );
569 module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) {596 module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) {
570 error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo,597 error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo,
571 error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e,598 error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e,