diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index c35ae03e9b24a5f3bfb4649a56620f15c487cf05..431108cd3f6164769359902f1abccdec720516df 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -93,12 +93,28 @@ pub fn getSymbols( pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { _ = si; _ = io; - // This function is marked as deprecated; however, it is significantly more - // performant than `dladdr` (since the latter also does a very slow symbol - // lookup), so let's use it since it's still available. - return std.mem.span(std.c.dyld_image_path_containing_address( - @ptrFromInt(address), - ) orelse return error.MissingDebugInfo); + return getModuleNameInner(address) orelse return error.MissingDebugInfo; +} +fn getModuleNameInner(address: usize) ?[]const u8 { + switch (builtin.target.os.tag) { + .macos => { + // This function is marked as deprecated; however, it is significantly more performant + // than `dladdr` (since the latter also does a very slow symbol lookup), so let's just + // use it for the better performance since it's still available. + return std.mem.span(std.c.dyld_image_path_containing_address( + @ptrFromInt(address), + ) orelse return null); + }, + else => { + // On other Darwin systems, the function used above is entirely unavailable, so we have + // no choice but to use the slow `dladdr`. + var info: std.c.dl_info = undefined; + if (std.c.dladdr(@ptrFromInt(address), &info) == 0) { + return null; + } + return std.mem.span(info.fname); + }, + } } pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { const gpa = std.debug.getDebugInfoAllocator(); @@ -446,12 +462,25 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize { /// Acquires the mutex on success. fn findModule(si: *SelfInfo, gpa: Allocator, io: Io, address: usize) Error!*Module { - // This function is marked as deprecated; however, it is significantly more - // performant than `dladdr` (since the latter also does a very slow symbol - // lookup), so let's use it since it's still available. - const text_base = std.c._dyld_get_image_header_containing_address( - @ptrFromInt(address), - ) orelse return error.MissingDebugInfo; + const text_base: *anyopaque = switch (builtin.target.os.tag) { + .macos => base: { + // This function is marked as deprecated; however, it is significantly more performant + // than `dladdr` (since the latter also does a very slow symbol lookup), so let's just + // use it for the better performance since it's still available. + break :base std.c._dyld_get_image_header_containing_address( + @ptrFromInt(address), + ) orelse return error.MissingDebugInfo; + }, + else => base: { + // On other Darwin systems, the function used above is entirely unavailable, so we have + // no choice but to use the slow `dladdr`. + var info: std.c.dl_info = undefined; + if (std.c.dladdr(@ptrFromInt(address), &info) == 0) { + return error.MissingDebugInfo; + } + break :base info.fbase; + }, + }; try si.mutex.lock(io); errdefer si.mutex.unlock(io); const gop = try si.modules.getOrPutAdapted(gpa, @intFromPtr(text_base), Module.Adapter{}); @@ -563,9 +592,7 @@ const Module = struct { fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile { if (module.file == null) { - const path = std.mem.span( - std.c.dyld_image_path_containing_address(@ptrFromInt(module.text_base)).?, - ); + const path = getModuleNameInner(module.text_base).?; module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) { error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e, diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 175a106f3e544374e88a8aa1ab76d3a2abfc4895..072bcd0309cf4decce854badf096994606a1e550 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -153,6 +153,9 @@ .compiler_rt_panic = .{ .path = "compiler_rt_panic", }, + .ios = .{ + .path = "ios", + }, .depend_on_main_mod = .{ .path = "depend_on_main_mod", }, diff --git a/test/standalone/ios/build.zig b/test/standalone/ios/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..cd1d52aec973ab44c8c4f30d0224c6e0f34b5268 --- /dev/null +++ b/test/standalone/ios/build.zig @@ -0,0 +1,41 @@ +const std = @import("std"); + +pub const requires_symlinks = true; +pub const requires_ios_sdk = true; + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test it"); + b.default_step = test_step; + + const target = b.resolveTargetQuery(.{ + .cpu_arch = .aarch64, + .os_tag = .ios, + }); + + const exe = b.addExecutable(.{ + .name = "main", + .root_module = b.createModule(.{ + .root_source_file = b.path("panic.zig"), + .optimize = .Debug, + .target = target, + .link_libc = true, + }), + }); + + const io = b.graph.io; + + if (std.zig.system.darwin.getSdk(b.allocator, io, &target.result)) |sdk| { + exe.root_module.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/include" }) }); + exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/Frameworks" }) }); + exe.root_module.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/System/Library/SubFrameworks" }) }); + exe.root_module.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ sdk, "/usr/lib" }) }); + } else { + exe.step.dependOn(&b.addFail("no iOS SDK found").step); + } + + exe.root_module.addCSourceFile(.{ .file = b.path("main.m"), .flags = &.{} }); + exe.root_module.linkFramework("Foundation", .{}); + exe.root_module.linkFramework("UIKit", .{}); + + test_step.dependOn(&b.addInstallArtifact(exe, .{}).step); +} diff --git a/test/standalone/ios/main.m b/test/standalone/ios/main.m new file mode 100644 index 0000000000000000000000000000000000000000..82b9a8c20fcd49a4c447178a841c84d366377e30 --- /dev/null +++ b/test/standalone/ios/main.m @@ -0,0 +1,38 @@ +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end + +extern void zig_panic(); + +int main() { + @autoreleasepool { + return UIApplicationMain(0, nil, nil, NSStringFromClass([AppDelegate class])); + } +} + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(id)options { + CGRect mainScreenBounds = [[UIScreen mainScreen] bounds]; + self.window = [[UIWindow alloc] initWithFrame:mainScreenBounds]; + UIViewController *viewController = [[UIViewController alloc] init]; + viewController.view.frame = mainScreenBounds; + + NSString* msg = @"Hello world"; + + UILabel *label = [[UILabel alloc] initWithFrame:mainScreenBounds]; + [label setText:msg]; + [viewController.view addSubview: label]; + + self.window.rootViewController = viewController; + + [self.window makeKeyAndVisible]; + + zig_panic(); + + return YES; +} + +@end diff --git a/test/standalone/ios/panic.zig b/test/standalone/ios/panic.zig new file mode 100644 index 0000000000000000000000000000000000000000..5acb60da2dd9d9cb4dfcf8800b70a7dcea977e95 --- /dev/null +++ b/test/standalone/ios/panic.zig @@ -0,0 +1,4 @@ +export fn zig_panic() void { + @panic("called zig_panic"); +} +pub const _start = {}; // entry point is in main.m