authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-02 16:39:45+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-30 13:44:50+01:00
loge4dbfc109bb32334f8d0dde9277ddd80c9b6f126
tree37c8f79c045abd769fec803ae009343acd412bf1
parent8fdcdb8c69712ebbfbd06e0c18d373eee462fe31
signaturelock-open Commit is signed but in an unrecognized format.

dont dupe state you silly billy


1 files changed, 32 insertions(+), 25 deletions(-)

lib/std/debug/SelfInfo.zig+32-25
...@@ -100,8 +100,6 @@ const Module = switch (native_os) {...@@ -100,8 +100,6 @@ const Module = switch (native_os) {
100 text_base: usize,100 text_base: usize,
101 load_offset: usize,101 load_offset: usize,
102 name: []const u8,102 name: []const u8,
103 unwind_info: ?[]const u8,
104 eh_frame: ?[]const u8,
105 fn key(m: *const Module) usize {103 fn key(m: *const Module) usize {
106 return m.text_base;104 return m.text_base;
107 }105 }
...@@ -120,11 +118,11 @@ const Module = switch (native_os) {...@@ -120,11 +118,11 @@ const Module = switch (native_os) {
120 .ncmds = header.ncmds,118 .ncmds = header.ncmds,
121 .buffer = @as([*]u8, @ptrCast(header))[@sizeOf(macho.mach_header_64)..][0..header.sizeofcmds],119 .buffer = @as([*]u8, @ptrCast(header))[@sizeOf(macho.mach_header_64)..][0..header.sizeofcmds],
122 };120 };
123 const text_segment_cmd, const text_sections = while (it.next()) |load_cmd| {121 const text_segment_cmd = while (it.next()) |load_cmd| {
124 if (load_cmd.cmd() != .SEGMENT_64) continue;122 if (load_cmd.cmd() != .SEGMENT_64) continue;
125 const segment_cmd = load_cmd.cast(macho.segment_command_64).?;123 const segment_cmd = load_cmd.cast(macho.segment_command_64).?;
126 if (!mem.eql(u8, segment_cmd.segName(), "__TEXT")) continue;124 if (!mem.eql(u8, segment_cmd.segName(), "__TEXT")) continue;
127 break .{ segment_cmd, load_cmd.getSections() };125 break segment_cmd;
128 } else continue;126 } else continue;
129127
130 const seg_start = load_offset + text_segment_cmd.vmaddr;128 const seg_start = load_offset + text_segment_cmd.vmaddr;
...@@ -132,26 +130,12 @@ const Module = switch (native_os) {...@@ -132,26 +130,12 @@ const Module = switch (native_os) {
132 const seg_end = seg_start + text_segment_cmd.vmsize;130 const seg_end = seg_start + text_segment_cmd.vmsize;
133 if (address < seg_start or address >= seg_end) continue;131 if (address < seg_start or address >= seg_end) continue;
134132
135 // We've found the matching __TEXT segment. This is the image we need, but we must look133 // We've found the matching __TEXT segment. This is the image we need.
136 // for unwind info in it before returning.134 return .{
137
138 var result: Module = .{
139 .text_base = text_base,135 .text_base = text_base,
140 .load_offset = load_offset,136 .load_offset = load_offset,
141 .name = mem.span(std.c._dyld_get_image_name(@intCast(image_idx))),137 .name = mem.span(std.c._dyld_get_image_name(@intCast(image_idx))),
142 .unwind_info = null,
143 .eh_frame = null,
144 };138 };
145 for (text_sections) |sect| {
146 if (mem.eql(u8, sect.sectName(), "__unwind_info")) {
147 const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(load_offset + sect.addr)));
148 result.unwind_info = sect_ptr[0..@intCast(sect.size)];
149 } else if (mem.eql(u8, sect.sectName(), "__eh_frame")) {
150 const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(load_offset + sect.addr)));
151 result.eh_frame = sect_ptr[0..@intCast(sect.size)];
152 }
153 }
154 return result;
155 }139 }
156 return error.MissingDebugInfo;140 return error.MissingDebugInfo;
157 }141 }
...@@ -270,11 +254,35 @@ const Module = switch (native_os) {...@@ -270,11 +254,35 @@ const Module = switch (native_os) {
270 };254 };
271 }255 }
272 fn loadUnwindInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void {256 fn loadUnwindInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void {
273 if (di.unwind != null) return;
274 _ = gpa;257 _ = gpa;
258
259 const header: *std.macho.mach_header = @ptrFromInt(module.text_base);
260
261 var it: macho.LoadCommandIterator = .{
262 .ncmds = header.ncmds,
263 .buffer = @as([*]u8, @ptrCast(header))[@sizeOf(macho.mach_header_64)..][0..header.sizeofcmds],
264 };
265 const sections = while (it.next()) |load_cmd| {
266 if (load_cmd.cmd() != .SEGMENT_64) continue;
267 const segment_cmd = load_cmd.cast(macho.segment_command_64).?;
268 if (!mem.eql(u8, segment_cmd.segName(), "__TEXT")) continue;
269 break load_cmd.getSections();
270 } else unreachable;
271
272 var unwind_info: ?[]const u8 = null;
273 var eh_frame: ?[]const u8 = null;
274 for (sections) |sect| {
275 if (mem.eql(u8, sect.sectName(), "__unwind_info")) {
276 const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(module.load_offset + sect.addr)));
277 unwind_info = sect_ptr[0..@intCast(sect.size)];
278 } else if (mem.eql(u8, sect.sectName(), "__eh_frame")) {
279 const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(module.load_offset + sect.addr)));
280 eh_frame = sect_ptr[0..@intCast(sect.size)];
281 }
282 }
275 di.unwind = .{283 di.unwind = .{
276 .unwind_info = module.unwind_info,284 .unwind_info = unwind_info,
277 .eh_frame = module.eh_frame,285 .eh_frame = eh_frame,
278 };286 };
279 }287 }
280 fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {288 fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {
...@@ -362,7 +370,6 @@ const Module = switch (native_os) {...@@ -362,7 +370,6 @@ const Module = switch (native_os) {
362 const DebugInfo = struct {370 const DebugInfo = struct {
363 unwind: ?struct {371 unwind: ?struct {
364 // Backed by the in-memory sections mapped by the loader372 // Backed by the in-memory sections mapped by the loader
365 // MLUGG TODO: these are duplicated state. i actually reckon they should be removed from Module, and loadLocationInfo should be the one discovering them!
366 unwind_info: ?[]const u8,373 unwind_info: ?[]const u8,
367 eh_frame: ?[]const u8,374 eh_frame: ?[]const u8,
368 },375 },
...@@ -517,7 +524,7 @@ const Module = switch (native_os) {...@@ -517,7 +524,7 @@ const Module = switch (native_os) {
517 };524 };
518 };525 };
519 fn key(m: Module) usize {526 fn key(m: Module) usize {
520 return m.load_offset; // MLUGG TODO: is this technically valid? idk527 return m.load_offset;
521 }528 }
522 fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !Module {529 fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !Module {
523 _ = cache;530 _ = cache;