From 07f05426fc0c28ad19f87002d5d4d0366e54b7c9 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Sat, 11 Apr 2026 18:05:24 +0200 Subject: [PATCH] Support ld64.ldd STABS layout in MachOFile.load Apple's ld emit N_BNSYM and N_ENSYM to mark the start and end of functions, while ld64.lld doesn't. This resulted in MachOFile.load bailing out on unsupported STABS layout when the linker used is ld64.lld. This commit supports both layouts. --- lib/std/debug/MachOFile.zig | 54 +++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/std/debug/MachOFile.zig b/lib/std/debug/MachOFile.zig index 69842902f3e104a5a622c6fa6f58b660b52e90a1..b561821969d7aaf9ba07125875c90b9ad1b2d785 100644 --- a/lib/std/debug/MachOFile.zig +++ b/lib/std/debug/MachOFile.zig @@ -158,6 +158,10 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) } // TODO handle globals N_GSYM, and statics N_STSYM + // + // NOTE: ld64.lld and Apple's ld differ in STABS layout. + // Apple's ld emit N_BNSYM and N_ENSYM to mark the start and end of + // functions, while ld64.lld doesn't. switch (sym.n_type.stab) { .oso => switch (state) { .init, .oso_close => { @@ -178,6 +182,14 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) else => return error.InvalidMachO, }, .fun => switch (state) { + .oso_open => { + state = .fun_strx; + last_sym = .{ + .strx = sym.n_strx, + .addr = sym.n_value, + .ofile = ofile, + }; + }, .bnsym => { state = .fun_strx; last_sym.strx = sym.n_strx; @@ -185,20 +197,24 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) .fun_strx => { state = .fun_size; }, + .fun_size => { + if (last_sym.strx != 0) { + appendStabSymbol(&symbols, &symbol_names, strings, last_sym); + } + last_sym = .{ + .strx = sym.n_strx, + .addr = sym.n_value, + .ofile = ofile, + }; + state = .fun_strx; + }, else => return error.InvalidMachO, }, .ensym => switch (state) { .fun_size => { state = .ensym; if (last_sym.strx != 0) { - const name = std.mem.sliceTo(strings[last_sym.strx..], 0); - const gop = symbol_names.getOrPutAssumeCapacity(name); - if (!gop.found_existing) { - assert(gop.index == symbols.items.len); - symbols.appendAssumeCapacity(last_sym); - } else { - symbols.items[gop.index] = last_sym; - } + appendStabSymbol(&symbols, &symbol_names, strings, last_sym); } }, else => return error.InvalidMachO, @@ -208,6 +224,12 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) .oso_open, .ensym => { state = .oso_close; }, + .fun_size => { + state = .oso_close; + if (last_sym.strx != 0) { + appendStabSymbol(&symbols, &symbol_names, strings, last_sym); + } + }, else => return error.InvalidMachO, }, else => {}, @@ -356,6 +378,22 @@ test { _ = Symbol; } +fn appendStabSymbol( + symbols: *std.ArrayList(Symbol), + symbol_names: *std.StringArrayHashMapUnmanaged(void), + strings: []const u8, + last_sym: Symbol, +) void { + const name = std.mem.sliceTo(strings[last_sym.strx..], 0); + const gop = symbol_names.getOrPutAssumeCapacity(name); + if (!gop.found_existing) { + assert(gop.index == symbols.items.len); + symbols.appendAssumeCapacity(last_sym); + } else { + symbols.items[gop.index] = last_sym; + } +} + fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile { const all_mapped_memory, const mapped_ofile = map: { const open_paren = paren: { -- 2.54.0