From 86fe47235eafc03ee4808f8c8b34b7903b816023 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 30 Nov 2021 13:59:33 +0100 Subject: [PATCH 1/3] macho: move nlist_64 type/flags helpers to std.macho --- lib/std/macho.zig | 49 +++++++++++++++++++++++ src/link/MachO.zig | 81 ++++++++------------------------------- src/link/MachO/Atom.zig | 4 +- src/link/MachO/Dylib.zig | 2 +- src/link/MachO/Object.zig | 6 +-- 5 files changed, 70 insertions(+), 72 deletions(-) diff --git a/lib/std/macho.zig b/lib/std/macho.zig index b4d7964b5e855bcc88077fe785b9e1e6509e4801..dce6d10cd52661d62ffe0da8774cb1ea3a582509 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -744,6 +744,55 @@ pub const nlist_64 = extern struct { n_sect: u8, n_desc: u16, n_value: u64, + + pub fn stab(sym: nlist_64) bool { + return (N_STAB & sym.n_type) != 0; + } + + pub fn pext(sym: nlist_64) bool { + return (N_PEXT & sym.n_type) != 0; + } + + pub fn ext(sym: nlist_64) bool { + return (N_EXT & sym.n_type) != 0; + } + + pub fn sect(sym: nlist_64) bool { + const type_ = N_TYPE & sym.n_type; + return type_ == N_SECT; + } + + pub fn undf(sym: nlist_64) bool { + const type_ = N_TYPE & sym.n_type; + return type_ == N_UNDF; + } + + pub fn indr(sym: nlist_64) bool { + const type_ = N_TYPE & sym.n_type; + return type_ == N_INDR; + } + + pub fn abs(sym: nlist_64) bool { + const type_ = N_TYPE & sym.n_type; + return type_ == N_ABS; + } + + pub fn weakDef(sym: nlist_64) bool { + return (sym.n_desc & N_WEAK_DEF) != 0; + } + + pub fn weakRef(sym: nlist_64) bool { + return (sym.n_desc & N_WEAK_REF) != 0; + } + + pub fn discarded(sym: nlist_64) bool { + return (sym.n_desc & N_DESC_DISCARDED) != 0; + } + + pub fn tentative(sym: nlist_64) bool { + if (!sym.undf()) return false; + return sym.n_value != 0; + } }; /// Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD diff --git a/src/link/MachO.zig b/src/link/MachO.zig index c464d4f67b4d0b2634b902c1c7c79a937fd783a0..56f6483cd0f9b6e618769c810b4630a6fc1ee061 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -885,7 +885,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { const sym_name = self.getString(sym.n_strx); const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable; - if (symbolIsDiscarded(sym.*)) { + if (sym.discarded()) { sym.* = .{ .n_strx = 0, .n_type = macho.N_UNDF, @@ -2445,21 +2445,21 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { const sym_id = @intCast(u32, id); const sym_name = object.getString(sym.n_strx); - if (symbolIsStab(sym)) { + if (sym.stab()) { log.err("unhandled symbol type: stab", .{}); log.err(" symbol '{s}'", .{sym_name}); log.err(" first definition in '{s}'", .{object.name}); return error.UnhandledSymbolType; } - if (symbolIsIndr(sym)) { + if (sym.indr()) { log.err("unhandled symbol type: indirect", .{}); log.err(" symbol '{s}'", .{sym_name}); log.err(" first definition in '{s}'", .{object.name}); return error.UnhandledSymbolType; } - if (symbolIsAbs(sym)) { + if (sym.abs()) { log.err("unhandled symbol type: absolute", .{}); log.err(" symbol '{s}'", .{sym_name}); log.err(" first definition in '{s}'", .{object.name}); @@ -2467,7 +2467,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { } const n_strx = try self.makeString(sym_name); - if (symbolIsSect(sym)) { + if (sym.sect()) { // Defined symbol regardless of scope lands in the locals symbol table. const local_sym_index = @intCast(u32, self.locals.items.len); try self.locals.append(self.base.allocator, .{ @@ -2482,7 +2482,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { // If the symbol's scope is not local aka translation unit, then we need work out // if we should save the symbol as a global, or potentially flag the error. - if (!symbolIsExt(sym)) continue; + if (!sym.ext()) continue; const local = self.locals.items[local_sym_index]; const resolv = self.symbol_resolver.getPtr(n_strx) orelse { @@ -2507,18 +2507,16 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { .global => { const global = &self.globals.items[resolv.where_index]; - if (symbolIsTentative(global.*)) { + if (global.tentative()) { assert(self.tentatives.swapRemove(resolv.where_index)); - } else if (!(symbolIsWeakDef(sym) or symbolIsPext(sym)) and - !(symbolIsWeakDef(global.*) or symbolIsPext(global.*))) - { + } else if (!(sym.weakDef() or sym.pext()) and !(global.weakDef() or global.pext())) { log.err("symbol '{s}' defined multiple times", .{sym_name}); if (resolv.file) |file| { log.err(" first definition in '{s}'", .{self.objects.items[file].name}); } log.err(" next definition in '{s}'", .{object.name}); return error.MultipleSymbolDefinitions; - } else if (symbolIsWeakDef(sym) or symbolIsPext(sym)) continue; // Current symbol is weak, so skip it. + } else if (sym.weakDef() or sym.pext()) continue; // Current symbol is weak, so skip it. // Otherwise, update the resolver and the global symbol. global.n_type = sym.n_type; @@ -2554,7 +2552,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { .local_sym_index = local_sym_index, .file = object_id, }; - } else if (symbolIsTentative(sym)) { + } else if (sym.tentative()) { // Symbol is a tentative definition. const resolv = self.symbol_resolver.getPtr(n_strx) orelse { const global_sym_index = @intCast(u32, self.globals.items.len); @@ -2577,7 +2575,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { switch (resolv.where) { .global => { const global = &self.globals.items[resolv.where_index]; - if (!symbolIsTentative(global.*)) continue; + if (!global.tentative()) continue; if (global.n_value >= sym.n_value) continue; global.n_desc = sym.n_desc; @@ -3575,9 +3573,9 @@ pub fn updateDeclExports( const sym = &self.globals.items[resolv.where_index]; - if (symbolIsTentative(sym.*)) { + if (sym.tentative()) { assert(self.tentatives.swapRemove(resolv.where_index)); - } else if (!is_weak and !(symbolIsWeakDef(sym.*) or symbolIsPext(sym.*))) { + } else if (!is_weak and !(sym.weakDef() or sym.pext())) { _ = try module.failed_exports.put( module.gpa, exp, @@ -5316,58 +5314,9 @@ pub fn getString(self: *MachO, off: u32) []const u8 { return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.items.ptr + off), 0); } -pub fn symbolIsStab(sym: macho.nlist_64) bool { - return (macho.N_STAB & sym.n_type) != 0; -} - -pub fn symbolIsPext(sym: macho.nlist_64) bool { - return (macho.N_PEXT & sym.n_type) != 0; -} - -pub fn symbolIsExt(sym: macho.nlist_64) bool { - return (macho.N_EXT & sym.n_type) != 0; -} - -pub fn symbolIsSect(sym: macho.nlist_64) bool { - const type_ = macho.N_TYPE & sym.n_type; - return type_ == macho.N_SECT; -} - -pub fn symbolIsUndf(sym: macho.nlist_64) bool { - const type_ = macho.N_TYPE & sym.n_type; - return type_ == macho.N_UNDF; -} - -pub fn symbolIsIndr(sym: macho.nlist_64) bool { - const type_ = macho.N_TYPE & sym.n_type; - return type_ == macho.N_INDR; -} - -pub fn symbolIsAbs(sym: macho.nlist_64) bool { - const type_ = macho.N_TYPE & sym.n_type; - return type_ == macho.N_ABS; -} - -pub fn symbolIsWeakDef(sym: macho.nlist_64) bool { - return (sym.n_desc & macho.N_WEAK_DEF) != 0; -} - -pub fn symbolIsWeakRef(sym: macho.nlist_64) bool { - return (sym.n_desc & macho.N_WEAK_REF) != 0; -} - -pub fn symbolIsDiscarded(sym: macho.nlist_64) bool { - return (sym.n_desc & macho.N_DESC_DISCARDED) != 0; -} - -pub fn symbolIsTentative(sym: macho.nlist_64) bool { - if (!symbolIsUndf(sym)) return false; - return sym.n_value != 0; -} - pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool { - if (!symbolIsSect(sym)) return false; - if (symbolIsExt(sym)) return false; + if (!sym.sect()) return false; + if (sym.ext()) return false; return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L"); } diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 4fffcdb7438c054309b4c05dc83c240bd0914dec..f5148ac8ee46fcdfbe56d9ea8c5ca202521d8833 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -295,7 +295,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC assert(subtractor == null); const sym = context.object.symtab.items[rel.r_symbolnum]; - if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) { + if (sym.sect() and !sym.ext()) { subtractor = context.object.symbol_mapping.get(rel.r_symbolnum).?; } else { const sym_name = context.object.getString(sym.n_strx); @@ -362,7 +362,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC const sym = context.object.symtab.items[rel.r_symbolnum]; const sym_name = context.object.getString(sym.n_strx); - if (MachO.symbolIsSect(sym) and !MachO.symbolIsExt(sym)) { + if (sym.sect() and !sym.ext()) { const sym_index = context.object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable; break :target Relocation.Target{ .local = sym_index }; } diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index a0517eb4c5d9c9ceb5f84302b37a7524033350a3..2835e57f0cd79ba0d3f351ec9b6b9200284777e6 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -226,7 +226,7 @@ fn parseSymbols(self: *Dylib, allocator: *Allocator) !void { _ = try self.file.preadAll(strtab, symtab_cmd.stroff + self.library_offset); for (slice) |sym| { - const add_to_symtab = MachO.symbolIsExt(sym) and (MachO.symbolIsSect(sym) or MachO.symbolIsIndr(sym)); + const add_to_symtab = sym.ext() and (sym.sect() or sym.indr()); if (!add_to_symtab) continue; diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 472c529cd39e801a6a6ac6200dba6ff0182bd0b7..a7db8566004da13a6cc371def59655471cb9c022 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -338,8 +338,8 @@ const NlistWithIndex = struct { // afterwards by address in each group. Normally, dysymtab should // be enough to guarantee the sort, but turns out not every compiler // is kind enough to specify the symbols in the correct order. - if (MachO.symbolIsSect(lhs.nlist)) { - if (MachO.symbolIsSect(rhs.nlist)) { + if (lhs.nlist.sect()) { + if (rhs.nlist.sect()) { // Same group, sort by address. return lhs.nlist.n_value < rhs.nlist.n_value; } else { @@ -414,7 +414,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: *Allocator, macho_file: *MachO) var iundefsym: usize = sorted_all_nlists.items.len; while (iundefsym > 0) : (iundefsym -= 1) { const nlist = sorted_all_nlists.items[iundefsym]; - if (MachO.symbolIsSect(nlist.nlist)) break; + if (nlist.nlist.sect()) break; } break :blk iundefsym; }; -- 2.54.0 From a56749b654bbe432752a57e130c7cf9dda370a15 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 30 Nov 2021 15:02:10 +0100 Subject: [PATCH 2/3] macos: rewrite logic for generating stack traces on macOS In order to be linker-independent, when parsing debug info in each linked OSO, we also create a quick lookup table for symbols defined within the OSO. We then use this lookup to map symbol from the EXE to its defined address within the original OSO which we can then use to extract its associated DWARF info (if any). --- lib/std/debug.zig | 203 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 61 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index d669f7ca4104190543051eab784aace34e21bda1..9f79be332b02eea8bb6405025ccf8e62435cfd86 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -559,7 +559,7 @@ pub const TTY = struct { fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol { var min: usize = 0; - var max: usize = symbols.len - 1; // Exclude sentinel. + var max: usize = symbols.len; while (min < max) { const mid = min + (max - min) / 2; const curr = &symbols[mid]; @@ -850,51 +850,91 @@ fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugI } else { return error.MissingDebugInfo; }; - const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms]; + const syms = @ptrCast( + [*]const macho.nlist_64, + @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff), + )[0..symtab.nsyms]; const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0 .. symtab.strsize - 1 :0]; const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); - var ofile: ?*const macho.nlist_64 = null; - var reloc: u64 = 0; + var ofile: u32 = undefined; + var last_sym: MachoSymbol = undefined; var symbol_index: usize = 0; - var last_len: u64 = 0; + var state: enum { + init, + oso_open, + oso_close, + bnsym, + fun_strx, + fun_size, + ensym, + } = .init; + for (syms) |*sym| { - if (sym.n_type & std.macho.N_STAB != 0) { - switch (sym.n_type) { - std.macho.N_OSO => { - ofile = sym; - reloc = 0; - }, - std.macho.N_FUN => { - if (sym.n_sect == 0) { - last_len = sym.n_value; - } else { - symbols_buf[symbol_index] = MachoSymbol{ - .nlist = sym, + if (!sym.stab()) continue; + + // TODO handle globals N_GSYM, and statics N_STSYM + switch (sym.n_type) { + macho.N_OSO => { + switch (state) { + .init, .oso_close => { + state = .oso_open; + ofile = sym.n_strx; + }, + else => return error.InvalidDebugInfo, + } + }, + macho.N_BNSYM => { + switch (state) { + .oso_open, .ensym => { + state = .bnsym; + last_sym = .{ + .strx = 0, + .addr = sym.n_value, + .size = 0, .ofile = ofile, - .reloc = reloc, }; + }, + else => return error.InvalidDebugInfo, + } + }, + macho.N_FUN => { + switch (state) { + .bnsym => { + state = .fun_strx; + last_sym.strx = sym.n_strx; + }, + .fun_strx => { + state = .fun_size; + last_sym.size = @intCast(u32, sym.n_value); + }, + else => return error.InvalidDebugInfo, + } + }, + macho.N_ENSYM => { + switch (state) { + .fun_size => { + state = .ensym; + symbols_buf[symbol_index] = last_sym; symbol_index += 1; - } - }, - std.macho.N_BNSYM => { - if (reloc == 0) { - reloc = sym.n_value; - } - }, - else => continue, - } + }, + else => return error.InvalidDebugInfo, + } + }, + macho.N_SO => { + switch (state) { + .init, .oso_close => {}, + .oso_open, .ensym => { + state = .oso_close; + }, + else => return error.InvalidDebugInfo, + } + }, + else => {}, } } - const sentinel = try allocator.create(macho.nlist_64); - sentinel.* = macho.nlist_64{ - .n_strx = 0, - .n_type = 36, - .n_sect = 0, - .n_desc = 0, - .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len, - }; + assert(state == .oso_close); const symbols = allocator.shrink(symbols_buf, symbol_index); @@ -946,18 +986,19 @@ fn printLineFromFileAnyOs(out_stream: anytype, line_info: LineInfo) !void { } const MachoSymbol = struct { - nlist: *const macho.nlist_64, - ofile: ?*const macho.nlist_64, - reloc: u64, + strx: u32, + addr: u64, + size: u32, + ofile: u32, /// Returns the address from the macho file fn address(self: MachoSymbol) u64 { - return self.nlist.n_value; + return self.addr; } fn addressLessThan(context: void, lhs: MachoSymbol, rhs: MachoSymbol) bool { _ = context; - return lhs.address() < rhs.address(); + return lhs.addr < rhs.addr; } }; @@ -1231,13 +1272,17 @@ pub const ModuleDebugInfo = switch (native_os) { strings: [:0]const u8, ofiles: OFileTable, - const OFileTable = std.StringHashMap(DW.DwarfInfo); + const OFileTable = std.StringHashMap(OFileInfo); + const OFileInfo = struct { + di: DW.DwarfInfo, + addr_table: std.StringHashMap(u64), + }; pub fn allocator(self: @This()) *mem.Allocator { return self.ofiles.allocator; } - fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo { + fn loadOFile(self: *@This(), o_file_path: []const u8) !OFileInfo { const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking }); const mapped_mem = try mapWholeFile(o_file); @@ -1250,22 +1295,54 @@ pub const ModuleDebugInfo = switch (native_os) { const hdr_base = @ptrCast([*]const u8, hdr); var ptr = hdr_base + @sizeOf(macho.mach_header_64); + var segptr = ptr; var ncmd: u32 = hdr.ncmds; - const segcmd = while (ncmd != 0) : (ncmd -= 1) { + var segcmd: ?*const macho.segment_command_64 = null; + var symtabcmd: ?*const macho.symtab_command = null; + + while (ncmd != 0) : (ncmd -= 1) { const lc = @ptrCast(*const std.macho.load_command, ptr); switch (lc.cmd) { std.macho.LC_SEGMENT_64 => { - break @ptrCast( + segcmd = @ptrCast( *const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr), ); + segptr = ptr; + }, + std.macho.LC_SYMTAB => { + symtabcmd = @ptrCast( + *const std.macho.symtab_command, + @alignCast(@alignOf(std.macho.symtab_command), ptr), + ); }, else => {}, } ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize); - } else { - return error.MissingDebugInfo; - }; + } + + if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo; + + // Parse symbols + const strtab = @ptrCast( + [*]const u8, + hdr_base + symtabcmd.?.stroff, + )[0 .. symtabcmd.?.strsize - 1 :0]; + const symtab = @ptrCast( + [*]const macho.nlist_64, + @alignCast(@alignOf(macho.nlist_64), hdr_base + symtabcmd.?.symoff), + )[0..symtabcmd.?.nsyms]; + + // TODO handle tentative (common) symbols + var addr_table = std.StringHashMap(u64).init(self.allocator()); + try addr_table.ensureTotalCapacity(@intCast(u32, symtab.len)); + for (symtab) |sym| { + if (sym.n_strx == 0) continue; + if (sym.undf() or sym.tentative() or sym.abs()) continue; + const sym_name = mem.sliceTo(strtab[sym.n_strx..], 0); + // TODO is it possible to have a symbol collision? + addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value); + } var opt_debug_line: ?*const macho.section_64 = null; var opt_debug_info: ?*const macho.section_64 = null; @@ -1275,8 +1352,8 @@ pub const ModuleDebugInfo = switch (native_os) { const sections = @ptrCast( [*]const macho.section_64, - @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)), - )[0..segcmd.nsects]; + @alignCast(@alignOf(macho.section_64), segptr + @sizeOf(std.macho.segment_command_64)), + )[0..segcmd.?.nsects]; for (sections) |*sect| { // The section name may not exceed 16 chars and a trailing null may // not be present @@ -1320,11 +1397,15 @@ pub const ModuleDebugInfo = switch (native_os) { }; try DW.openDwarfDebugInfo(&di, self.allocator()); + var info = OFileInfo{ + .di = di, + .addr_table = addr_table, + }; // Add the debug info to the cache - try self.ofiles.putNoClobber(o_file_path, di); + try self.ofiles.putNoClobber(o_file_path, info); - return di; + return info; } pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { @@ -1336,18 +1417,15 @@ pub const ModuleDebugInfo = switch (native_os) { // Find the .o file where this symbol is defined const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse return SymbolInfo{}; + const addr_off = relocated_address - symbol.addr; // Take the symbol name from the N_FUN STAB entry, we're going to // use it if we fail to find the DWARF infos - const stab_symbol = mem.sliceTo(self.strings[symbol.nlist.n_strx..], 0); - - if (symbol.ofile == null) - return SymbolInfo{ .symbol_name = stab_symbol }; - - const o_file_path = mem.sliceTo(self.strings[symbol.ofile.?.n_strx..], 0); + const stab_symbol = mem.sliceTo(self.strings[symbol.strx..], 0); + const o_file_path = mem.sliceTo(self.strings[symbol.ofile..], 0); // Check if its debug infos are already in the cache - var o_file_di = self.ofiles.get(o_file_path) orelse + var o_file_info = self.ofiles.get(o_file_path) orelse (self.loadOFile(o_file_path) catch |err| switch (err) { error.FileNotFound, error.MissingDebugInfo, @@ -1357,19 +1435,22 @@ pub const ModuleDebugInfo = switch (native_os) { }, else => return err, }); + const o_file_di = &o_file_info.di; // Translate again the address, this time into an address inside the // .o file - const relocated_address_o = relocated_address - symbol.reloc; + const relocated_address_o = o_file_info.addr_table.get(stab_symbol) orelse return SymbolInfo{ + .symbol_name = "???", + }; if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| { return SymbolInfo{ .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???", - .compile_unit_name = compile_unit.die.getAttrString(&o_file_di, DW.AT.name) catch |err| switch (err) { + .compile_unit_name = compile_unit.die.getAttrString(o_file_di, DW.AT.name) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => "???", else => return err, }, - .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o) catch |err| switch (err) { + .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o + addr_off) catch |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => null, else => return err, }, -- 2.54.0 From 28623544ce78c5c559af8a47c62e688db9ce5e4a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 30 Nov 2021 16:48:49 +0100 Subject: [PATCH 3/3] macos: remove >= 0x10000000 assertion when printing stack traces I don't think we can guarantee that especially for system dyld dylibs which can be loaded at any address (perhaps even some OS preferential low memory address). Incidentally, this fixes stack trace tests on x86_64 macOS 12. --- lib/std/debug.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 9f79be332b02eea8bb6405025ccf8e62435cfd86..531872581aa1f4cf68ee3e11513d76cb62c7419f 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1412,7 +1412,6 @@ pub const ModuleDebugInfo = switch (native_os) { nosuspend { // Translate the VA into an address into this object const relocated_address = address - self.base_address; - assert(relocated_address >= 0x100000000); // Find the .o file where this symbol is defined const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse -- 2.54.0