| ... | ... | @@ -100,8 +100,6 @@ const Module = switch (native_os) { |
| 100 | 100 | text_base: usize, |
| 101 | 101 | load_offset: usize, |
| 102 | 102 | name: []const u8, |
| 103 | | unwind_info: ?[]const u8, |
| 104 | | eh_frame: ?[]const u8, |
| 105 | 103 | fn key(m: *const Module) usize { |
| 106 | 104 | return m.text_base; |
| 107 | 105 | } |
| ... | ... | @@ -120,11 +118,11 @@ const Module = switch (native_os) { |
| 120 | 118 | .ncmds = header.ncmds, |
| 121 | 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 | 122 | if (load_cmd.cmd() != .SEGMENT_64) continue; |
| 125 | 123 | const segment_cmd = load_cmd.cast(macho.segment_command_64).?; |
| 126 | 124 | if (!mem.eql(u8, segment_cmd.segName(), "__TEXT")) continue; |
| 127 | | break .{ segment_cmd, load_cmd.getSections() }; |
| 125 | break segment_cmd; |
| 128 | 126 | } else continue; |
| 129 | 127 | |
| 130 | 128 | const seg_start = load_offset + text_segment_cmd.vmaddr; |
| ... | ... | @@ -132,26 +130,12 @@ const Module = switch (native_os) { |
| 132 | 130 | const seg_end = seg_start + text_segment_cmd.vmsize; |
| 133 | 131 | if (address < seg_start or address >= seg_end) continue; |
| 134 | 132 | |
| 135 | | // We've found the matching __TEXT segment. This is the image we need, but we must look |
| 136 | | // for unwind info in it before returning. |
| 137 | | |
| 138 | | var result: Module = .{ |
| 133 | // We've found the matching __TEXT segment. This is the image we need. |
| 134 | return .{ |
| 139 | 135 | .text_base = text_base, |
| 140 | 136 | .load_offset = load_offset, |
| 141 | 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 | 140 | return error.MissingDebugInfo; |
| 157 | 141 | } |
| ... | ... | @@ -270,11 +254,35 @@ const Module = switch (native_os) { |
| 270 | 254 | }; |
| 271 | 255 | } |
| 272 | 256 | fn loadUnwindInfo(module: *const Module, gpa: Allocator, di: *Module.DebugInfo) !void { |
| 273 | | if (di.unwind != null) return; |
| 274 | 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 | 283 | di.unwind = .{ |
| 276 | | .unwind_info = module.unwind_info, |
| 277 | | .eh_frame = module.eh_frame, |
| 284 | .unwind_info = unwind_info, |
| 285 | .eh_frame = eh_frame, |
| 278 | 286 | }; |
| 279 | 287 | } |
| 280 | 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 | 370 | const DebugInfo = struct { |
| 363 | 371 | unwind: ?struct { |
| 364 | 372 | // 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 | 373 | unwind_info: ?[]const u8, |
| 367 | 374 | eh_frame: ?[]const u8, |
| 368 | 375 | }, |
| ... | ... | @@ -517,7 +524,7 @@ const Module = switch (native_os) { |
| 517 | 524 | }; |
| 518 | 525 | }; |
| 519 | 526 | fn key(m: Module) usize { |
| 520 | | return m.load_offset; // MLUGG TODO: is this technically valid? idk |
| 527 | return m.load_offset; |
| 521 | 528 | } |
| 522 | 529 | fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !Module { |
| 523 | 530 | _ = cache; |