| ... | @@ -16,6 +16,7 @@ const trace = @import("../../tracy.zig").trace; | ... | @@ -16,6 +16,7 @@ const trace = @import("../../tracy.zig").trace; |
| 16 | const Allocator = mem.Allocator; | 16 | const Allocator = mem.Allocator; |
| 17 | const Atom = @import("Atom.zig"); | 17 | const Atom = @import("Atom.zig"); |
| 18 | const MachO = @import("../MachO.zig"); | 18 | const MachO = @import("../MachO.zig"); |
| | 19 | const MatchingSection = MachO.MatchingSection; |
| 19 | | 20 | |
| 20 | file: fs.File, | 21 | file: fs.File, |
| 21 | name: []const u8, | 22 | name: []const u8, |
| ... | @@ -421,6 +422,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -421,6 +422,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 421 | // We only care about defined symbols, so filter every other out. | 422 | // We only care about defined symbols, so filter every other out. |
| 422 | const sorted_nlists = sorted_all_nlists.items[0..iundefsym]; | 423 | const sorted_nlists = sorted_all_nlists.items[0..iundefsym]; |
| 423 | | 424 | |
| | 425 | const dead_strip = blk: { |
| | 426 | const dead_strip = macho_file.base.options.gc_sections orelse break :blk false; |
| | 427 | if (dead_strip or macho_file.base.options.optimize_mode != .Debug) |
| | 428 | break :blk self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| | 429 | break :blk false; |
| | 430 | }; |
| | 431 | |
| 424 | for (seg.sections.items) |sect, id| { | 432 | for (seg.sections.items) |sect, id| { |
| 425 | const sect_id = @intCast(u8, id); | 433 | const sect_id = @intCast(u8, id); |
| 426 | log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() }); | 434 | log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() }); |
| ... | @@ -459,85 +467,42 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -459,85 +467,42 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 459 | }; | 467 | }; |
| 460 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; | 468 | macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null; |
| 461 | | 469 | |
| 462 | // Since there is no symbol to refer to this atom, we create | 470 | if (dead_strip) blk: { |
| | 471 | if (filtered_nlists.len == 0) break :blk; // nothing to split |
| | 472 | |
| | 473 | // If the first nlist does not match the start of the section, |
| | 474 | // then we need to encapsulate the memory range [section start, first symbol) |
| | 475 | // as a temporary symbol and insert the matching Atom. |
| | 476 | const first_nlist = filtered_nlists[0].nlist; |
| | 477 | if (first_nlist.n_value > sect.addr) {} |
| | 478 | } |
| | 479 | |
| | 480 | // If there is no symbol to refer to this atom, we create |
| 463 | // a temp one, unless we already did that when working out the relocations | 481 | // a temp one, unless we already did that when working out the relocations |
| 464 | // of other atoms. | 482 | // of other atoms. |
| 465 | const atom_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { | 483 | const local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 466 | const atom_local_sym_index = @intCast(u32, macho_file.locals.items.len); | 484 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 467 | try macho_file.locals.append(allocator, .{ | 485 | try macho_file.locals.append(allocator, .{ |
| 468 | .n_strx = 0, | 486 | .n_strx = 0, |
| 469 | .n_type = macho.N_SECT, | 487 | .n_type = macho.N_SECT, |
| 470 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), | 488 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), |
| 471 | .n_desc = 0, | 489 | .n_desc = 0, |
| 472 | .n_value = 0, | 490 | .n_value = sect.addr, |
| 473 | }); | 491 | }); |
| 474 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index); | 492 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, local_sym_index); |
| 475 | break :blk atom_local_sym_index; | 493 | break :blk local_sym_index; |
| 476 | }; | 494 | }; |
| 477 | const alignment = try math.powi(u32, 2, sect.@"align"); | 495 | const atom = try self.parseIntoAtom( |
| 478 | const aligned_size = mem.alignForwardGeneric(u64, sect.size, alignment); | 496 | allocator, |
| 479 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align"); | 497 | local_sym_index, |
| 480 | | 498 | sect.size, |
| 481 | if (code) |cc| { | 499 | sect.@"align", |
| 482 | assert(!is_zerofill); | 500 | code, |
| 483 | mem.copy(u8, atom.code.items, cc); | 501 | relocs, |
| 484 | } | 502 | filtered_nlists, |
| 485 | | 503 | match, |
| 486 | try atom.parseRelocs(relocs, .{ | 504 | macho_file, |
| 487 | .base_addr = sect.addr, | 505 | ); |
| 488 | .allocator = allocator, | | |
| 489 | .object = self, | | |
| 490 | .macho_file = macho_file, | | |
| 491 | }); | | |
| 492 | | | |
| 493 | if (macho_file.has_dices) { | | |
| 494 | const dices = filterDice(self.data_in_code_entries, sect.addr, sect.addr + sect.size); | | |
| 495 | try atom.dices.ensureTotalCapacity(allocator, dices.len); | | |
| 496 | | | |
| 497 | for (dices) |dice| { | | |
| 498 | atom.dices.appendAssumeCapacity(.{ | | |
| 499 | .offset = dice.offset - (math.cast(u32, sect.addr) orelse return error.Overflow), | | |
| 500 | .length = dice.length, | | |
| 501 | .kind = dice.kind, | | |
| 502 | }); | | |
| 503 | } | | |
| 504 | } | | |
| 505 | | | |
| 506 | // Since this is atom gets a helper local temporary symbol that didn't exist | | |
| 507 | // in the object file which encompasses the entire section, we need traverse | | |
| 508 | // the filtered symbols and note which symbol is contained within so that | | |
| 509 | // we can properly allocate addresses down the line. | | |
| 510 | // While we're at it, we need to update segment,section mapping of each symbol too. | | |
| 511 | try atom.contained.ensureTotalCapacity(allocator, filtered_nlists.len); | | |
| 512 | | | |
| 513 | for (filtered_nlists) |nlist_with_index| { | | |
| 514 | const nlist = nlist_with_index.nlist; | | |
| 515 | const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable; | | |
| 516 | const local = &macho_file.locals.items[local_sym_index]; | | |
| 517 | local.n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1); | | |
| 518 | | | |
| 519 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { | | |
| 520 | // TODO there has to be a better to handle this. | | |
| 521 | for (di.inner.func_list.items) |func| { | | |
| 522 | if (func.pc_range) |range| { | | |
| 523 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { | | |
| 524 | break :blk Atom.Stab{ | | |
| 525 | .function = range.end - range.start, | | |
| 526 | }; | | |
| 527 | } | | |
| 528 | } | | |
| 529 | } | | |
| 530 | // TODO | | |
| 531 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; | | |
| 532 | break :blk .static; | | |
| 533 | } else null; | | |
| 534 | | | |
| 535 | atom.contained.appendAssumeCapacity(.{ | | |
| 536 | .local_sym_index = local_sym_index, | | |
| 537 | .offset = nlist.n_value - sect.addr, | | |
| 538 | .stab = stab, | | |
| 539 | }); | | |
| 540 | } | | |
| 541 | | 506 | |
| 542 | if (!self.start_atoms.contains(match)) { | 507 | if (!self.start_atoms.contains(match)) { |
| 543 | try self.start_atoms.putNoClobber(allocator, match, atom); | 508 | try self.start_atoms.putNoClobber(allocator, match, atom); |
| ... | @@ -554,6 +519,232 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -554,6 +519,232 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 554 | } | 519 | } |
| 555 | } | 520 | } |
| 556 | | 521 | |
| | 522 | // const Context = struct { |
| | 523 | // allocator: *Allocator, |
| | 524 | // object: *Object, |
| | 525 | // macho_file: *MachO, |
| | 526 | // match: MachO.MatchingSection, |
| | 527 | // }; |
| | 528 | |
| | 529 | // const AtomParser = struct { |
| | 530 | // section: macho.section_64, |
| | 531 | // code: []u8, |
| | 532 | // relocs: []macho.relocation_info, |
| | 533 | // nlists: []NlistWithIndex, |
| | 534 | // index: u32 = 0, |
| | 535 | |
| | 536 | // fn peek(self: AtomParser) ?NlistWithIndex { |
| | 537 | // return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null; |
| | 538 | // } |
| | 539 | |
| | 540 | // fn lessThanBySeniority(context: Context, lhs: NlistWithIndex, rhs: NlistWithIndex) bool { |
| | 541 | // if (!MachO.symbolIsExt(rhs.nlist)) { |
| | 542 | // return MachO.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx)); |
| | 543 | // } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) { |
| | 544 | // return !MachO.symbolIsExt(lhs.nlist); |
| | 545 | // } else { |
| | 546 | // return false; |
| | 547 | // } |
| | 548 | // } |
| | 549 | |
| | 550 | // pub fn next(self: *AtomParser, context: Context) !?*Atom { |
| | 551 | // if (self.index == self.nlists.len) return null; |
| | 552 | |
| | 553 | // const tracy = trace(@src()); |
| | 554 | // defer tracy.end(); |
| | 555 | |
| | 556 | // var aliases = std.ArrayList(NlistWithIndex).init(context.allocator); |
| | 557 | // defer aliases.deinit(); |
| | 558 | |
| | 559 | // const next_nlist: ?NlistWithIndex = blk: while (true) { |
| | 560 | // const curr_nlist = self.nlists[self.index]; |
| | 561 | // try aliases.append(curr_nlist); |
| | 562 | |
| | 563 | // if (self.peek()) |next_nlist| { |
| | 564 | // if (curr_nlist.nlist.n_value == next_nlist.nlist.n_value) { |
| | 565 | // self.index += 1; |
| | 566 | // continue; |
| | 567 | // } |
| | 568 | // break :blk next_nlist; |
| | 569 | // } |
| | 570 | // break :blk null; |
| | 571 | // } else null; |
| | 572 | |
| | 573 | // for (aliases.items) |*nlist_with_index| { |
| | 574 | // nlist_with_index.index = context.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable; |
| | 575 | // } |
| | 576 | |
| | 577 | // if (aliases.items.len > 1) { |
| | 578 | // // Bubble-up senior symbol as the main link to the atom. |
| | 579 | // sort.sort( |
| | 580 | // NlistWithIndex, |
| | 581 | // aliases.items, |
| | 582 | // context, |
| | 583 | // AtomParser.lessThanBySeniority, |
| | 584 | // ); |
| | 585 | // } |
| | 586 | |
| | 587 | // const senior_nlist = aliases.pop(); |
| | 588 | // const senior_sym = &context.macho_file.locals.items[senior_nlist.index]; |
| | 589 | // senior_sym.n_sect = @intCast(u8, context.macho_file.section_ordinals.getIndex(context.match).? + 1); |
| | 590 | |
| | 591 | // const start_addr = senior_nlist.nlist.n_value - self.section.addr; |
| | 592 | // const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; |
| | 593 | |
| | 594 | // const code = self.code[start_addr..end_addr]; |
| | 595 | // const size = code.len; |
| | 596 | |
| | 597 | // const max_align = self.section.@"align"; |
| | 598 | // const actual_align = if (senior_nlist.nlist.n_value > 0) |
| | 599 | // math.min(@ctz(u64, senior_nlist.nlist.n_value), max_align) |
| | 600 | // else |
| | 601 | // max_align; |
| | 602 | |
| | 603 | // const stab: ?Atom.Stab = if (context.object.debug_info) |di| blk: { |
| | 604 | // // TODO there has to be a better to handle this. |
| | 605 | // for (di.inner.func_list.items) |func| { |
| | 606 | // if (func.pc_range) |range| { |
| | 607 | // if (senior_nlist.nlist.n_value >= range.start and senior_nlist.nlist.n_value < range.end) { |
| | 608 | // break :blk Atom.Stab{ |
| | 609 | // .function = range.end - range.start, |
| | 610 | // }; |
| | 611 | // } |
| | 612 | // } |
| | 613 | // } |
| | 614 | // // TODO |
| | 615 | // // if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global; |
| | 616 | // break :blk .static; |
| | 617 | // } else null; |
| | 618 | |
| | 619 | // const atom = try context.macho_file.createEmptyAtom(senior_nlist.index, size, actual_align); |
| | 620 | // atom.stab = stab; |
| | 621 | |
| | 622 | // const is_zerofill = blk: { |
| | 623 | // const section_type = commands.sectionType(self.section); |
| | 624 | // break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| | 625 | // }; |
| | 626 | // if (!is_zerofill) { |
| | 627 | // mem.copy(u8, atom.code.items, code); |
| | 628 | // } |
| | 629 | |
| | 630 | // try atom.aliases.ensureTotalCapacity(context.allocator, aliases.items.len); |
| | 631 | // for (aliases.items) |alias| { |
| | 632 | // atom.aliases.appendAssumeCapacity(alias.index); |
| | 633 | // const sym = &context.macho_file.locals.items[alias.index]; |
| | 634 | // sym.n_sect = @intCast(u8, context.macho_file.section_ordinals.getIndex(context.match).? + 1); |
| | 635 | // } |
| | 636 | |
| | 637 | // try atom.parseRelocs(self.relocs, .{ |
| | 638 | // .base_addr = self.section.addr, |
| | 639 | // .base_offset = start_addr, |
| | 640 | // .allocator = context.allocator, |
| | 641 | // .object = context.object, |
| | 642 | // .macho_file = context.macho_file, |
| | 643 | // }); |
| | 644 | |
| | 645 | // if (context.macho_file.has_dices) { |
| | 646 | // const dices = filterDice( |
| | 647 | // context.object.data_in_code_entries.items, |
| | 648 | // senior_nlist.nlist.n_value, |
| | 649 | // senior_nlist.nlist.n_value + size, |
| | 650 | // ); |
| | 651 | // try atom.dices.ensureTotalCapacity(context.allocator, dices.len); |
| | 652 | |
| | 653 | // for (dices) |dice| { |
| | 654 | // atom.dices.appendAssumeCapacity(.{ |
| | 655 | // .offset = dice.offset - try math.cast(u32, senior_nlist.nlist.n_value), |
| | 656 | // .length = dice.length, |
| | 657 | // .kind = dice.kind, |
| | 658 | // }); |
| | 659 | // } |
| | 660 | // } |
| | 661 | |
| | 662 | // self.index += 1; |
| | 663 | |
| | 664 | // return atom; |
| | 665 | // } |
| | 666 | // }; |
| | 667 | |
| | 668 | fn parseIntoAtom( |
| | 669 | self: *Object, |
| | 670 | allocator: Allocator, |
| | 671 | local_sym_index: u32, |
| | 672 | size: u64, |
| | 673 | alignment: u32, |
| | 674 | code: ?[]const u8, |
| | 675 | relocs: []const macho.relocation_info, |
| | 676 | nlists: []const NlistWithIndex, |
| | 677 | match: MatchingSection, |
| | 678 | macho_file: *MachO, |
| | 679 | ) !*Atom { |
| | 680 | const sym = macho_file.locals.items[local_sym_index]; |
| | 681 | const align_pow_2 = try math.powi(u32, 2, alignment); |
| | 682 | const aligned_size = mem.alignForwardGeneric(u64, size, align_pow_2); |
| | 683 | const atom = try macho_file.createEmptyAtom(local_sym_index, aligned_size, alignment); |
| | 684 | |
| | 685 | if (code) |cc| { |
| | 686 | mem.copy(u8, atom.code.items, cc); |
| | 687 | } |
| | 688 | |
| | 689 | try atom.parseRelocs(relocs, .{ |
| | 690 | .base_addr = sym.n_value, |
| | 691 | .allocator = allocator, |
| | 692 | .object = self, |
| | 693 | .macho_file = macho_file, |
| | 694 | }); |
| | 695 | |
| | 696 | if (macho_file.has_dices) { |
| | 697 | const dices = filterDice(self.data_in_code_entries, sym.n_value, sym.n_value + size); |
| | 698 | try atom.dices.ensureTotalCapacity(allocator, dices.len); |
| | 699 | |
| | 700 | for (dices) |dice| { |
| | 701 | atom.dices.appendAssumeCapacity(.{ |
| | 702 | .offset = dice.offset - (math.cast(u32, sym.n_value) orelse return error.Overflow), |
| | 703 | .length = dice.length, |
| | 704 | .kind = dice.kind, |
| | 705 | }); |
| | 706 | } |
| | 707 | } |
| | 708 | |
| | 709 | // Since this is atom gets a helper local temporary symbol that didn't exist |
| | 710 | // in the object file which encompasses the entire section, we need traverse |
| | 711 | // the filtered symbols and note which symbol is contained within so that |
| | 712 | // we can properly allocate addresses down the line. |
| | 713 | // While we're at it, we need to update segment,section mapping of each symbol too. |
| | 714 | try atom.contained.ensureTotalCapacity(allocator, nlists.len); |
| | 715 | |
| | 716 | for (nlists) |nlist_with_index| { |
| | 717 | const nlist = nlist_with_index.nlist; |
| | 718 | const sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable; |
| | 719 | const this_sym = &macho_file.locals.items[sym_index]; |
| | 720 | this_sym.n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1); |
| | 721 | |
| | 722 | const stab: ?Atom.Stab = if (self.debug_info) |di| blk: { |
| | 723 | // TODO there has to be a better to handle this. |
| | 724 | for (di.inner.func_list.items) |func| { |
| | 725 | if (func.pc_range) |range| { |
| | 726 | if (nlist.n_value >= range.start and nlist.n_value < range.end) { |
| | 727 | break :blk Atom.Stab{ |
| | 728 | .function = range.end - range.start, |
| | 729 | }; |
| | 730 | } |
| | 731 | } |
| | 732 | } |
| | 733 | // TODO |
| | 734 | // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global; |
| | 735 | break :blk .static; |
| | 736 | } else null; |
| | 737 | |
| | 738 | atom.contained.appendAssumeCapacity(.{ |
| | 739 | .local_sym_index = sym_index, |
| | 740 | .offset = nlist.n_value - sym.n_value, |
| | 741 | .stab = stab, |
| | 742 | }); |
| | 743 | } |
| | 744 | |
| | 745 | return atom; |
| | 746 | } |
| | 747 | |
| 557 | fn parseSymtab(self: *Object) void { | 748 | fn parseSymtab(self: *Object) void { |
| 558 | const index = self.symtab_cmd_index orelse return; | 749 | const index = self.symtab_cmd_index orelse return; |
| 559 | const symtab = self.load_commands.items[index].symtab; | 750 | const symtab = self.load_commands.items[index].symtab; |
| ... | @@ -563,7 +754,7 @@ fn parseSymtab(self: *Object) void { | ... | @@ -563,7 +754,7 @@ fn parseSymtab(self: *Object) void { |
| 563 | self.strtab = self.contents[symtab.stroff..][0..symtab.strsize]; | 754 | self.strtab = self.contents[symtab.stroff..][0..symtab.strsize]; |
| 564 | } | 755 | } |
| 565 | | 756 | |
| 566 | pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { | 757 | fn parseDebugInfo(self: *Object, allocator: Allocator) !void { |
| 567 | log.debug("parsing debug info in '{s}'", .{self.name}); | 758 | log.debug("parsing debug info in '{s}'", .{self.name}); |
| 568 | | 759 | |
| 569 | var debug_info = blk: { | 760 | var debug_info = blk: { |
| ... | @@ -595,7 +786,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { | ... | @@ -595,7 +786,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { |
| 595 | } | 786 | } |
| 596 | } | 787 | } |
| 597 | | 788 | |
| 598 | pub fn parseDataInCode(self: *Object) void { | 789 | fn parseDataInCode(self: *Object) void { |
| 599 | const index = self.data_in_code_cmd_index orelse return; | 790 | const index = self.data_in_code_cmd_index orelse return; |
| 600 | const data_in_code = self.load_commands.items[index].linkedit_data; | 791 | const data_in_code = self.load_commands.items[index].linkedit_data; |
| 601 | const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize]; | 792 | const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize]; |