diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2025-09-26 12:00:41 +0100 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2025-09-30 13:44:56 +0100 |
| commit | 8950831d3c4af4dd169e0a404e25e8aa9b045caa (patch) | |
| tree | 50d8df70cffdd5d42b5bd73737356a44b1936501 /lib/std/debug | |
| parent | 156cd8f678ebdcccc48382d093a3ef7e45c85a45 (diff) | |
| download | zig-8950831d3c4af4dd169e0a404e25e8aa9b045caa.tar.gz zig-8950831d3c4af4dd169e0a404e25e8aa9b045caa.zip | |
Dwarf.Unwind: handle macOS deviation from standard
Apparently the `__eh_frame` in Mach-O binaries doesn't include the
terminator entry, but in all other respects it acts like `.eh_frame`
rather than `.debug_frame`. I have no idea.
Diffstat (limited to 'lib/std/debug')
| -rw-r--r-- | lib/std/debug/Dwarf/Unwind.zig | 14 | ||||
| -rw-r--r-- | lib/std/debug/SelfInfo/DarwinModule.zig | 2 | ||||
| -rw-r--r-- | lib/std/debug/SelfInfo/ElfModule.zig | 2 |
3 files changed, 12 insertions, 6 deletions
diff --git a/lib/std/debug/Dwarf/Unwind.zig b/lib/std/debug/Dwarf/Unwind.zig index e251a9175d..90e531b349 100644 --- a/lib/std/debug/Dwarf/Unwind.zig +++ b/lib/std/debug/Dwarf/Unwind.zig @@ -475,10 +475,15 @@ pub fn prepare( addr_size_bytes: u8, endian: Endian, need_lookup: bool, + /// The `__eh_frame` section in Mach-O binaries deviates from the standard `.eh_frame` section + /// in one way which this function needs to be aware of. + is_macho: bool, ) !void { if (unwind.cie_list.len > 0 and (!need_lookup or unwind.lookup != null)) return; unwind.cie_list.clearRetainingCapacity(); + if (is_macho) assert(unwind.lookup == null or unwind.lookup.? != .eh_frame_hdr); + const section = unwind.frame_section; var r: Reader = .fixed(section.bytes); @@ -519,10 +524,11 @@ pub fn prepare( .terminator => break true, } } else false; - switch (section.id) { - .eh_frame => if (!saw_terminator) return bad(), // `.eh_frame` indicates the end of the CIE/FDE list with a sentinel entry - .debug_frame => if (saw_terminator) return bad(), // `.debug_frame` uses the section bounds and does not specify a sentinel entry - } + const expect_terminator = switch (section.id) { + .eh_frame => !is_macho, // `.eh_frame` indicates the end of the CIE/FDE list with a sentinel entry, though macOS omits this + .debug_frame => false, // `.debug_frame` uses the section bounds and does not specify a sentinel entry + }; + if (saw_terminator != expect_terminator) return bad(); std.mem.sortUnstable(SortedFdeEntry, fde_list.items, {}, struct { fn lessThan(ctx: void, a: SortedFdeEntry, b: SortedFdeEntry) bool { diff --git a/lib/std/debug/SelfInfo/DarwinModule.zig b/lib/std/debug/SelfInfo/DarwinModule.zig index caf2176f75..71e43a9a74 100644 --- a/lib/std/debug/SelfInfo/DarwinModule.zig +++ b/lib/std/debug/SelfInfo/DarwinModule.zig @@ -59,7 +59,7 @@ fn loadUnwindInfo(module: *const DarwinModule, gpa: Allocator, out: *DebugInfo) var dwarf: Dwarf.Unwind = .initSection(.eh_frame, @intFromPtr(eh_frame.ptr) - vmaddr_slide, eh_frame); errdefer dwarf.deinit(gpa); // We don't need lookups, so this call is just for scanning CIEs. - dwarf.prepare(gpa, @sizeOf(usize), native_endian, false) catch |err| switch (err) { + dwarf.prepare(gpa, @sizeOf(usize), native_endian, false, true) catch |err| switch (err) { error.ReadFailed => unreachable, // it's all fixed buffers error.InvalidDebugInfo, error.MissingDebugInfo, diff --git a/lib/std/debug/SelfInfo/ElfModule.zig b/lib/std/debug/SelfInfo/ElfModule.zig index eead810a86..7ce24e2e2a 100644 --- a/lib/std/debug/SelfInfo/ElfModule.zig +++ b/lib/std/debug/SelfInfo/ElfModule.zig @@ -228,7 +228,7 @@ pub fn getSymbolAtAddress(module: *const ElfModule, gpa: Allocator, di: *DebugIn }; } fn prepareUnwindLookup(unwind: *Dwarf.Unwind, gpa: Allocator) Error!void { - unwind.prepare(gpa, @sizeOf(usize), native_endian, true) catch |err| switch (err) { + unwind.prepare(gpa, @sizeOf(usize), native_endian, true, false) catch |err| switch (err) { error.ReadFailed => unreachable, // it's all fixed buffers error.InvalidDebugInfo, error.MissingDebugInfo, |
