authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-29 05:37:19+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-29 05:37:19+02:00
log1a2c47a504c7f549328689201305514831de7513
treebd19a368134a85388b8b23f1f94513a92aa03cd6
parentec735f62e461952c47f997ab6199cd89abbb20c2
parent2b8a05b8d9125b7465f0d3bd44e90d82a06dd5fa

Merge pull request 'fix `std.debug` using function which does not exist on iOS' (#32138) from std-darwin-dyld-dep into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32138 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

5 files changed, 128 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,
test/standalone/build.zig.zon+3
......@@ -153,6 +153,9 @@
153153 .compiler_rt_panic = .{
154154 .path = "compiler_rt_panic",
155155 },
156 .ios = .{
157 .path = "ios",
158 },
156159 .depend_on_main_mod = .{
157160 .path = "depend_on_main_mod",
158161 },
test/standalone/ios/build.zig created+41
......@@ -0,0 +1,41 @@
1const std = @import("std");
2
3pub const requires_symlinks = true;
4pub const requires_ios_sdk = true;
5
6pub fn build(b: *std.Build) void {
7 const test_step = b.step("test", "Test it");
8 b.default_step = test_step;
9
10 const target = b.resolveTargetQuery(.{
11 .cpu_arch = .aarch64,
12 .os_tag = .ios,
13 });
14
15 const exe = b.addExecutable(.{
16 .name = "main",
17 .root_module = b.createModule(.{
18 .root_source_file = b.path("panic.zig"),
19 .optimize = .Debug,
20 .target = target,
21 .link_libc = true,
22 }),
23 });
24
25 const io = b.graph.io;
26
27 if (std.zig.system.darwin.getSdk(b.allocator, io, &target.result)) |sdk| {
28 exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) });
29 exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/Frameworks" }) });
30 exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/SubFrameworks" }) });
31 exe.root_module.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/lib" }) });
32 } else {
33 exe.step.dependOn(&b.addFail("no iOS SDK found").step);
34 }
35
36 exe.root_module.addCSourceFile(.{ .file = b.path("main.m"), .flags = &.{} });
37 exe.root_module.linkFramework("Foundation", .{});
38 exe.root_module.linkFramework("UIKit", .{});
39
40 test_step.dependOn(&b.addInstallArtifact(exe, .{}).step);
41}
test/standalone/ios/main.m created+38
......@@ -0,0 +1,38 @@
1#import <UIKit/UIKit.h>
2
3@interface AppDelegate : UIResponder <UIApplicationDelegate>
4@property (strong, nonatomic) UIWindow *window;
5@end
6
7extern void zig_panic();
8
9int main() {
10 @autoreleasepool {
11 return UIApplicationMain(0, nil, nil, NSStringFromClass([AppDelegate class]));
12 }
13}
14
15@implementation AppDelegate
16
17- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(id)options {
18 CGRect mainScreenBounds = [[UIScreen mainScreen] bounds];
19 self.window = [[UIWindow alloc] initWithFrame:mainScreenBounds];
20 UIViewController *viewController = [[UIViewController alloc] init];
21 viewController.view.frame = mainScreenBounds;
22
23 NSString* msg = @"Hello world";
24
25 UILabel *label = [[UILabel alloc] initWithFrame:mainScreenBounds];
26 [label setText:msg];
27 [viewController.view addSubview: label];
28
29 self.window.rootViewController = viewController;
30
31 [self.window makeKeyAndVisible];
32
33 zig_panic();
34
35 return YES;
36}
37
38@end
test/standalone/ios/panic.zig created+4
......@@ -0,0 +1,4 @@
1export fn zig_panic() void {
2 @panic("called zig_panic");
3}
4pub const _start = {}; // entry point is in main.m