| ... | ... | @@ -27,7 +27,6 @@ header: ?macho.mach_header_64 = null, |
| 27 | 27 | file: ?fs.File = null, |
| 28 | 28 | file_offset: ?u32 = null, |
| 29 | 29 | name: ?[]const u8 = null, |
| 30 | | mtime: ?u64 = null, |
| 31 | 30 | |
| 32 | 31 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 33 | 32 | |
| ... | ... | @@ -51,9 +50,17 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 51 | 50 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 52 | 51 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 53 | 52 | |
| 53 | // Debug info |
| 54 | debug_info: ?DebugInfo = null, |
| 55 | tu_name: ?[]const u8 = null, |
| 56 | tu_comp_dir: ?[]const u8 = null, |
| 57 | mtime: ?u64 = null, |
| 58 | |
| 54 | 59 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 55 | 60 | sections_as_symbols: std.AutoHashMapUnmanaged(u8, *Symbol) = .{}, |
| 56 | 61 | |
| 62 | text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 63 | |
| 57 | 64 | const DebugInfo = struct { |
| 58 | 65 | inner: dwarf.DwarfInfo, |
| 59 | 66 | debug_info: []u8, |
| ... | ... | @@ -160,6 +167,19 @@ pub fn deinit(self: *Object) void { |
| 160 | 167 | self.strtab.deinit(self.allocator); |
| 161 | 168 | self.symbols.deinit(self.allocator); |
| 162 | 169 | self.sections_as_symbols.deinit(self.allocator); |
| 170 | self.text_blocks.deinit(self.allocator); |
| 171 | |
| 172 | if (self.debug_info) |*db| { |
| 173 | db.deinit(self.allocator); |
| 174 | } |
| 175 | |
| 176 | if (self.tu_name) |n| { |
| 177 | self.allocator.free(n); |
| 178 | } |
| 179 | |
| 180 | if (self.tu_comp_dir) |n| { |
| 181 | self.allocator.free(n); |
| 182 | } |
| 163 | 183 | |
| 164 | 184 | if (self.name) |n| { |
| 165 | 185 | self.allocator.free(n); |
| ... | ... | @@ -203,6 +223,7 @@ pub fn parse(self: *Object) !void { |
| 203 | 223 | try self.readLoadCommands(reader); |
| 204 | 224 | try self.parseSymtab(); |
| 205 | 225 | try self.parseDataInCode(); |
| 226 | try self.parseDebugInfo(); |
| 206 | 227 | } |
| 207 | 228 | |
| 208 | 229 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { |
| ... | ... | @@ -431,11 +452,27 @@ const TextBlockParser = struct { |
| 431 | 452 | else |
| 432 | 453 | max_align; |
| 433 | 454 | |
| 455 | const stab: ?TextBlock.Stab = if (self.object.debug_info) |di| blk: { |
| 456 | // TODO there has to be a better to handle this. |
| 457 | for (di.inner.func_list.items) |func| { |
| 458 | if (func.pc_range) |range| { |
| 459 | if (senior_nlist.nlist.n_value >= range.start and senior_nlist.nlist.n_value < range.end) { |
| 460 | break :blk TextBlock.Stab{ |
| 461 | .function = range.end - range.start, |
| 462 | }; |
| 463 | } |
| 464 | } |
| 465 | } |
| 466 | if (self.zld.globals.contains(senior_sym.name)) break :blk .global; |
| 467 | break :blk .static; |
| 468 | } else null; |
| 469 | |
| 434 | 470 | const block = try self.allocator.create(TextBlock); |
| 435 | 471 | errdefer self.allocator.destroy(block); |
| 436 | 472 | |
| 437 | 473 | block.* = TextBlock.init(self.allocator); |
| 438 | 474 | block.local_sym_index = senior_nlist.index; |
| 475 | block.stab = stab; |
| 439 | 476 | block.code = try self.allocator.dupe(u8, code); |
| 440 | 477 | block.size = size; |
| 441 | 478 | block.alignment = actual_align; |
| ... | ... | @@ -531,9 +568,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 531 | 568 | |
| 532 | 569 | // Is there any padding between symbols within the section? |
| 533 | 570 | const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 571 | // TODO is it perhaps worth skip parsing subsections in Debug mode and not worry about |
| 572 | // duplicates at all? Need some benchmarks! |
| 534 | 573 | // const is_splittable = false; |
| 535 | 574 | |
| 536 | | const has_dices: bool = blk: { |
| 575 | zld.has_dices = blk: { |
| 537 | 576 | if (self.text_section_index) |index| { |
| 538 | 577 | if (index != id) break :blk false; |
| 539 | 578 | if (self.data_in_code_entries.items.len == 0) break :blk false; |
| ... | ... | @@ -541,7 +580,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 541 | 580 | } |
| 542 | 581 | break :blk false; |
| 543 | 582 | }; |
| 544 | | zld.has_dices = has_dices; |
| 583 | zld.has_stabs = zld.has_stabs or self.debug_info != null; |
| 545 | 584 | |
| 546 | 585 | next: { |
| 547 | 586 | if (is_splittable) blocks: { |
| ... | ... | @@ -625,6 +664,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 625 | 664 | } else { |
| 626 | 665 | try zld.blocks.putNoClobber(zld.allocator, match, block); |
| 627 | 666 | } |
| 667 | |
| 668 | try self.text_blocks.append(self.allocator, block); |
| 628 | 669 | } |
| 629 | 670 | |
| 630 | 671 | var parser = TextBlockParser{ |
| ... | ... | @@ -681,6 +722,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 681 | 722 | } else { |
| 682 | 723 | try zld.blocks.putNoClobber(zld.allocator, match, block); |
| 683 | 724 | } |
| 725 | |
| 726 | try self.text_blocks.append(self.allocator, block); |
| 684 | 727 | } |
| 685 | 728 | |
| 686 | 729 | break :next; |
| ... | ... | @@ -758,9 +801,25 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 758 | 801 | reg.segment_id = match.seg; |
| 759 | 802 | reg.section_id = match.sect; |
| 760 | 803 | |
| 804 | const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: { |
| 805 | // TODO there has to be a better to handle this. |
| 806 | for (di.inner.func_list.items) |func| { |
| 807 | if (func.pc_range) |range| { |
| 808 | if (reg.address >= range.start and reg.address < range.end) { |
| 809 | break :blk TextBlock.Stab{ |
| 810 | .function = range.end - range.start, |
| 811 | }; |
| 812 | } |
| 813 | } |
| 814 | } |
| 815 | if (zld.globals.contains(sym.name)) break :blk .global; |
| 816 | break :blk .static; |
| 817 | } else null; |
| 818 | |
| 761 | 819 | contained.appendAssumeCapacity(.{ |
| 762 | 820 | .local_sym_index = reg.local_sym_index, |
| 763 | 821 | .offset = nlist_with_index.nlist.n_value - sect.addr, |
| 822 | .stab = stab, |
| 764 | 823 | }); |
| 765 | 824 | } |
| 766 | 825 | |
| ... | ... | @@ -785,6 +844,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 785 | 844 | } else { |
| 786 | 845 | try zld.blocks.putNoClobber(zld.allocator, match, block); |
| 787 | 846 | } |
| 847 | |
| 848 | try self.text_blocks.append(self.allocator, block); |
| 788 | 849 | } |
| 789 | 850 | } |
| 790 | 851 | } |
| ... | ... | @@ -861,13 +922,12 @@ fn parseSymtab(self: *Object) !void { |
| 861 | 922 | } |
| 862 | 923 | |
| 863 | 924 | pub fn parseDebugInfo(self: *Object) !void { |
| 925 | log.debug("parsing debug info in '{s}'", .{self.name.?}); |
| 926 | |
| 864 | 927 | var debug_info = blk: { |
| 865 | 928 | var di = try DebugInfo.parseFromObject(self.allocator, self); |
| 866 | 929 | break :blk di orelse return; |
| 867 | 930 | }; |
| 868 | | defer debug_info.deinit(self.allocator); |
| 869 | | |
| 870 | | log.debug("parsing debug info in '{s}'", .{self.name.?}); |
| 871 | 931 | |
| 872 | 932 | // We assume there is only one CU. |
| 873 | 933 | const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) { |
| ... | ... | @@ -881,6 +941,10 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 881 | 941 | const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); |
| 882 | 942 | const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); |
| 883 | 943 | |
| 944 | self.debug_info = debug_info; |
| 945 | self.tu_name = try self.allocator.dupe(u8, name); |
| 946 | self.tu_comp_dir = try self.allocator.dupe(u8, comp_dir); |
| 947 | |
| 884 | 948 | if (self.mtime == null) { |
| 885 | 949 | self.mtime = mtime: { |
| 886 | 950 | const file = self.file orelse break :mtime 0; |
| ... | ... | @@ -888,67 +952,6 @@ pub fn parseDebugInfo(self: *Object) !void { |
| 888 | 952 | break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); |
| 889 | 953 | }; |
| 890 | 954 | } |
| 891 | | |
| 892 | | try self.stabs.ensureUnusedCapacity(self.allocator, self.symbols.items.len + 4); |
| 893 | | |
| 894 | | // Current dir |
| 895 | | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, comp_dir, .{ |
| 896 | | .kind = .so, |
| 897 | | .file = self, |
| 898 | | })); |
| 899 | | |
| 900 | | // Artifact name |
| 901 | | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, name, .{ |
| 902 | | .kind = .so, |
| 903 | | .file = self, |
| 904 | | })); |
| 905 | | |
| 906 | | // Path to object file with debug info |
| 907 | | self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, self.name.?, .{ |
| 908 | | .kind = .oso, |
| 909 | | .file = self, |
| 910 | | })); |
| 911 | | |
| 912 | | for (self.symbols.items) |sym| { |
| 913 | | if (sym.cast(Symbol.Regular)) |reg| { |
| 914 | | const size: u64 = blk: for (debug_info.inner.func_list.items) |func| { |
| 915 | | if (func.pc_range) |range| { |
| 916 | | if (reg.address >= range.start and reg.address < range.end) { |
| 917 | | break :blk range.end - range.start; |
| 918 | | } |
| 919 | | } |
| 920 | | } else 0; |
| 921 | | |
| 922 | | const stab = try Symbol.Stab.new(self.allocator, sym.name, .{ |
| 923 | | .kind = kind: { |
| 924 | | if (size > 0) break :kind .function; |
| 925 | | switch (reg.linkage) { |
| 926 | | .translation_unit => break :kind .static, |
| 927 | | else => break :kind .global, |
| 928 | | } |
| 929 | | }, |
| 930 | | .size = size, |
| 931 | | .symbol = sym, |
| 932 | | .file = self, |
| 933 | | }); |
| 934 | | self.stabs.appendAssumeCapacity(stab); |
| 935 | | } else if (sym.cast(Symbol.Tentative)) |_| { |
| 936 | | const stab = try Symbol.Stab.new(self.allocator, sym.name, .{ |
| 937 | | .kind = .global, |
| 938 | | .size = 0, |
| 939 | | .symbol = sym, |
| 940 | | .file = self, |
| 941 | | }); |
| 942 | | self.stabs.appendAssumeCapacity(stab); |
| 943 | | } |
| 944 | | } |
| 945 | | |
| 946 | | // Closing delimiter. |
| 947 | | const delim_stab = try Symbol.Stab.new(self.allocator, "", .{ |
| 948 | | .kind = .so, |
| 949 | | .file = self, |
| 950 | | }); |
| 951 | | self.stabs.appendAssumeCapacity(delim_stab); |
| 952 | 955 | } |
| 953 | 956 | |
| 954 | 957 | pub fn parseDataInCode(self: *Object) !void { |