| ... | ... | @@ -16,6 +16,7 @@ const trace = @import("../../tracy.zig").trace; |
| 16 | 16 | const Allocator = mem.Allocator; |
| 17 | 17 | const Atom = @import("Atom.zig"); |
| 18 | 18 | const MachO = @import("../MachO.zig"); |
| 19 | const MatchingSection = MachO.MatchingSection; |
| 19 | 20 | |
| 20 | 21 | file: fs.File, |
| 21 | 22 | name: []const u8, |
| ... | ... | @@ -421,6 +422,13 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 421 | 422 | // We only care about defined symbols, so filter every other out. |
| 422 | 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 | 432 | for (seg.sections.items) |sect, id| { |
| 425 | 433 | const sect_id = @intCast(u8, id); |
| 426 | 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 | 467 | }; |
| 460 | 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 | 481 | // a temp one, unless we already did that when working out the relocations |
| 464 | 482 | // of other atoms. |
| 465 | | const atom_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); |
| 483 | const local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| 484 | const local_sym_index = @intCast(u32, macho_file.locals.items.len); |
| 467 | 485 | try macho_file.locals.append(allocator, .{ |
| 468 | 486 | .n_strx = 0, |
| 469 | 487 | .n_type = macho.N_SECT, |
| 470 | 488 | .n_sect = @intCast(u8, macho_file.section_ordinals.getIndex(match).? + 1), |
| 471 | 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); |
| 475 | | break :blk atom_local_sym_index; |
| 492 | try self.sections_as_symbols.putNoClobber(allocator, sect_id, local_sym_index); |
| 493 | break :blk local_sym_index; |
| 476 | 494 | }; |
| 477 | | const alignment = try math.powi(u32, 2, sect.@"align"); |
| 478 | | const aligned_size = mem.alignForwardGeneric(u64, sect.size, alignment); |
| 479 | | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align"); |
| 480 | | |
| 481 | | if (code) |cc| { |
| 482 | | assert(!is_zerofill); |
| 483 | | mem.copy(u8, atom.code.items, cc); |
| 484 | | } |
| 485 | | |
| 486 | | try atom.parseRelocs(relocs, .{ |
| 487 | | .base_addr = sect.addr, |
| 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 | | } |
| 495 | const atom = try self.parseIntoAtom( |
| 496 | allocator, |
| 497 | local_sym_index, |
| 498 | sect.size, |
| 499 | sect.@"align", |
| 500 | code, |
| 501 | relocs, |
| 502 | filtered_nlists, |
| 503 | match, |
| 504 | macho_file, |
| 505 | ); |
| 541 | 506 | |
| 542 | 507 | if (!self.start_atoms.contains(match)) { |
| 543 | 508 | try self.start_atoms.putNoClobber(allocator, match, atom); |
| ... | ... | @@ -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 | 748 | fn parseSymtab(self: *Object) void { |
| 558 | 749 | const index = self.symtab_cmd_index orelse return; |
| 559 | 750 | const symtab = self.load_commands.items[index].symtab; |
| ... | ... | @@ -563,7 +754,7 @@ fn parseSymtab(self: *Object) void { |
| 563 | 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 | 758 | log.debug("parsing debug info in '{s}'", .{self.name}); |
| 568 | 759 | |
| 569 | 760 | var debug_info = blk: { |
| ... | ... | @@ -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 | 790 | const index = self.data_in_code_cmd_index orelse return; |
| 600 | 791 | const data_in_code = self.load_commands.items[index].linkedit_data; |
| 601 | 792 | const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize]; |