| ... | @@ -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; |
| 129 | | 127 | |
| 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; |
| 134 | | 132 | |
| 135 | // We've found the matching __TEXT segment. This is the image we need, but we must look | 133 | // 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 loader | 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 | 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? idk | 527 | 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; |