| ... | ... | @@ -2,7 +2,6 @@ const Zld = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | | const dwarf = std.dwarf; |
| 6 | 5 | const leb = std.leb; |
| 7 | 6 | const mem = std.mem; |
| 8 | 7 | const meta = std.meta; |
| ... | ... | @@ -110,70 +109,6 @@ pub const SectionMapping = struct { |
| 110 | 109 | offset: u32, |
| 111 | 110 | }; |
| 112 | 111 | |
| 113 | | const DebugInfo = struct { |
| 114 | | inner: dwarf.DwarfInfo, |
| 115 | | debug_info: []u8, |
| 116 | | debug_abbrev: []u8, |
| 117 | | debug_str: []u8, |
| 118 | | debug_line: []u8, |
| 119 | | debug_ranges: []u8, |
| 120 | | |
| 121 | | pub fn parseFromObject(allocator: *Allocator, object: Object) !?DebugInfo { |
| 122 | | var debug_info = blk: { |
| 123 | | const index = object.dwarf_debug_info_index orelse return null; |
| 124 | | break :blk try object.readSection(allocator, index); |
| 125 | | }; |
| 126 | | var debug_abbrev = blk: { |
| 127 | | const index = object.dwarf_debug_abbrev_index orelse return null; |
| 128 | | break :blk try object.readSection(allocator, index); |
| 129 | | }; |
| 130 | | var debug_str = blk: { |
| 131 | | const index = object.dwarf_debug_str_index orelse return null; |
| 132 | | break :blk try object.readSection(allocator, index); |
| 133 | | }; |
| 134 | | var debug_line = blk: { |
| 135 | | const index = object.dwarf_debug_line_index orelse return null; |
| 136 | | break :blk try object.readSection(allocator, index); |
| 137 | | }; |
| 138 | | var debug_ranges = blk: { |
| 139 | | if (object.dwarf_debug_ranges_index) |ind| { |
| 140 | | break :blk try object.readSection(allocator, ind); |
| 141 | | } |
| 142 | | break :blk try allocator.alloc(u8, 0); |
| 143 | | }; |
| 144 | | |
| 145 | | var inner: dwarf.DwarfInfo = .{ |
| 146 | | .endian = .Little, |
| 147 | | .debug_info = debug_info, |
| 148 | | .debug_abbrev = debug_abbrev, |
| 149 | | .debug_str = debug_str, |
| 150 | | .debug_line = debug_line, |
| 151 | | .debug_ranges = debug_ranges, |
| 152 | | }; |
| 153 | | try dwarf.openDwarfDebugInfo(&inner, allocator); |
| 154 | | |
| 155 | | return DebugInfo{ |
| 156 | | .inner = inner, |
| 157 | | .debug_info = debug_info, |
| 158 | | .debug_abbrev = debug_abbrev, |
| 159 | | .debug_str = debug_str, |
| 160 | | .debug_line = debug_line, |
| 161 | | .debug_ranges = debug_ranges, |
| 162 | | }; |
| 163 | | } |
| 164 | | |
| 165 | | pub fn deinit(self: *DebugInfo, allocator: *Allocator) void { |
| 166 | | allocator.free(self.debug_info); |
| 167 | | allocator.free(self.debug_abbrev); |
| 168 | | allocator.free(self.debug_str); |
| 169 | | allocator.free(self.debug_line); |
| 170 | | allocator.free(self.debug_ranges); |
| 171 | | self.inner.abbrev_table_list.deinit(); |
| 172 | | self.inner.compile_unit_list.deinit(); |
| 173 | | self.inner.func_list.deinit(); |
| 174 | | } |
| 175 | | }; |
| 176 | | |
| 177 | 112 | /// Default path to dyld |
| 178 | 113 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 179 | 114 | |
| ... | ... | @@ -2510,108 +2445,77 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2510 | 2445 | var stabs = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2511 | 2446 | defer stabs.deinit(); |
| 2512 | 2447 | |
| 2513 | | for (self.objects.items) |object, object_id| { |
| 2514 | | var debug_info = blk: { |
| 2515 | | var di = try DebugInfo.parseFromObject(self.allocator, object); |
| 2516 | | break :blk di orelse continue; |
| 2517 | | }; |
| 2518 | | defer debug_info.deinit(self.allocator); |
| 2519 | | |
| 2520 | | // We assume there is only one CU. |
| 2521 | | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { |
| 2522 | | error.MissingDebugInfo => { |
| 2523 | | // TODO audit cases with missing debug info and audit our dwarf.zig module. |
| 2524 | | log.warn("invalid or missing debug info in {s}; skipping", .{object.name}); |
| 2525 | | continue; |
| 2526 | | }, |
| 2527 | | else => |e| return e, |
| 2528 | | }; |
| 2529 | | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); |
| 2530 | | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); |
| 2531 | | |
| 2532 | | { |
| 2533 | | const tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name }); |
| 2534 | | defer self.allocator.free(tu_path); |
| 2535 | | const dirname = std.fs.path.dirname(tu_path) orelse "./"; |
| 2536 | | // Current dir |
| 2537 | | try stabs.append(.{ |
| 2538 | | .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]), |
| 2539 | | .n_type = macho.N_SO, |
| 2540 | | .n_sect = 0, |
| 2541 | | .n_desc = 0, |
| 2542 | | .n_value = 0, |
| 2543 | | }); |
| 2544 | | // Artifact name |
| 2545 | | try stabs.append(.{ |
| 2546 | | .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]), |
| 2547 | | .n_type = macho.N_SO, |
| 2548 | | .n_sect = 0, |
| 2549 | | .n_desc = 0, |
| 2550 | | .n_value = 0, |
| 2551 | | }); |
| 2552 | | // Path to object file with debug info |
| 2553 | | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 2554 | | const stat = try object.file.?.stat(); |
| 2555 | | const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); |
| 2556 | | try stabs.append(.{ |
| 2557 | | .n_strx = try self.makeString(object.name.?), |
| 2558 | | .n_type = macho.N_OSO, |
| 2559 | | .n_sect = 0, |
| 2560 | | .n_desc = 1, |
| 2561 | | .n_value = mtime, |
| 2562 | | }); |
| 2563 | | } |
| 2564 | | log.warn("analyzing debug info in '{s}'", .{object.name}); |
| 2448 | for (self.objects.items) |object| { |
| 2449 | const tu_path = object.tu_path orelse continue; |
| 2450 | const tu_mtime = object.tu_mtime orelse continue; |
| 2451 | const dirname = std.fs.path.dirname(tu_path) orelse "./"; |
| 2452 | // Current dir |
| 2453 | try stabs.append(.{ |
| 2454 | .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]), |
| 2455 | .n_type = macho.N_SO, |
| 2456 | .n_sect = 0, |
| 2457 | .n_desc = 0, |
| 2458 | .n_value = 0, |
| 2459 | }); |
| 2460 | // Artifact name |
| 2461 | try stabs.append(.{ |
| 2462 | .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]), |
| 2463 | .n_type = macho.N_SO, |
| 2464 | .n_sect = 0, |
| 2465 | .n_desc = 0, |
| 2466 | .n_value = 0, |
| 2467 | }); |
| 2468 | // Path to object file with debug info |
| 2469 | try stabs.append(.{ |
| 2470 | .n_strx = try self.makeString(object.name.?), |
| 2471 | .n_type = macho.N_OSO, |
| 2472 | .n_sect = 0, |
| 2473 | .n_desc = 1, |
| 2474 | .n_value = tu_mtime, |
| 2475 | }); |
| 2565 | 2476 | |
| 2566 | | for (object.symtab.items) |sym| { |
| 2567 | | const sym_name = object.getString(sym.inner.n_strx); |
| 2568 | | const maybe_size = blk: for (debug_info.inner.func_list.items) |func| { |
| 2569 | | if (func.pc_range) |range| { |
| 2570 | | // TODO source address needs to be preserved |
| 2571 | | if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) { |
| 2572 | | break :blk range.end - range.start; |
| 2573 | | } |
| 2574 | | } |
| 2575 | | } else null; |
| 2576 | | |
| 2577 | | if (maybe_size) |size| { |
| 2578 | | try stabs.append(.{ |
| 2579 | | .n_strx = 0, |
| 2580 | | .n_type = macho.N_BNSYM, |
| 2581 | | .n_sect = sym.inner.n_sect, |
| 2582 | | .n_desc = 0, |
| 2583 | | .n_value = sym.inner.n_value, |
| 2584 | | }); |
| 2585 | | try stabs.append(.{ |
| 2586 | | .n_strx = sym.inner.n_strx, |
| 2587 | | .n_type = macho.N_FUN, |
| 2588 | | .n_sect = sym.inner.n_sect, |
| 2589 | | .n_desc = 0, |
| 2590 | | .n_value = sym.inner.n_value, |
| 2591 | | }); |
| 2592 | | try stabs.append(.{ |
| 2593 | | .n_strx = 0, |
| 2594 | | .n_type = macho.N_FUN, |
| 2595 | | .n_sect = 0, |
| 2596 | | .n_desc = 0, |
| 2597 | | .n_value = size, |
| 2598 | | }); |
| 2599 | | try stabs.append(.{ |
| 2600 | | .n_strx = 0, |
| 2601 | | .n_type = macho.N_ENSYM, |
| 2602 | | .n_sect = sym.inner.n_sect, |
| 2603 | | .n_desc = 0, |
| 2604 | | .n_value = size, |
| 2605 | | }); |
| 2606 | | } else { |
| 2607 | | // TODO need a way to differentiate symbols: global, static, local, etc. |
| 2608 | | try stabs.append(.{ |
| 2609 | | .n_strx = sym.inner.n_strx, |
| 2610 | | .n_type = macho.N_STSYM, |
| 2611 | | .n_sect = sym.inner.n_sect, |
| 2612 | | .n_desc = 0, |
| 2613 | | .n_value = sym.inner.n_value, |
| 2614 | | }); |
| 2477 | for (object.stabs.items) |stab| { |
| 2478 | const sym = object.symtab.items[stab.symbol]; |
| 2479 | switch (stab.tag) { |
| 2480 | .function => { |
| 2481 | try stabs.append(.{ |
| 2482 | .n_strx = 0, |
| 2483 | .n_type = macho.N_BNSYM, |
| 2484 | .n_sect = sym.inner.n_sect, |
| 2485 | .n_desc = 0, |
| 2486 | .n_value = sym.inner.n_value, |
| 2487 | }); |
| 2488 | try stabs.append(.{ |
| 2489 | .n_strx = sym.inner.n_strx, |
| 2490 | .n_type = macho.N_FUN, |
| 2491 | .n_sect = sym.inner.n_sect, |
| 2492 | .n_desc = 0, |
| 2493 | .n_value = sym.inner.n_value, |
| 2494 | }); |
| 2495 | try stabs.append(.{ |
| 2496 | .n_strx = 0, |
| 2497 | .n_type = macho.N_FUN, |
| 2498 | .n_sect = 0, |
| 2499 | .n_desc = 0, |
| 2500 | .n_value = stab.size.?, |
| 2501 | }); |
| 2502 | try stabs.append(.{ |
| 2503 | .n_strx = 0, |
| 2504 | .n_type = macho.N_ENSYM, |
| 2505 | .n_sect = sym.inner.n_sect, |
| 2506 | .n_desc = 0, |
| 2507 | .n_value = stab.size.?, |
| 2508 | }); |
| 2509 | }, |
| 2510 | else => { |
| 2511 | try stabs.append(.{ |
| 2512 | .n_strx = sym.inner.n_strx, |
| 2513 | .n_type = macho.N_STSYM, |
| 2514 | .n_sect = sym.inner.n_sect, |
| 2515 | .n_desc = 0, |
| 2516 | .n_value = sym.inner.n_value, |
| 2517 | }); |
| 2518 | }, |
| 2615 | 2519 | } |
| 2616 | 2520 | } |
| 2617 | 2521 | |