| ... | ... | @@ -577,9 +577,10 @@ const MachODumper = struct { |
| 577 | 577 | const writer = output.writer(); |
| 578 | 578 | |
| 579 | 579 | var symtab: ?Symtab = null; |
| 580 | var segments = std.ArrayList(macho.segment_command_u64); |
| 580 | 581 | var sections = std.ArrayList(macho.section_64).init(gpa); |
| 581 | 582 | var imports = std.ArrayList([]const u8).init(gpa); |
| 582 | | var text_seg: ?macho.segment_command_64 = null; |
| 583 | var text_seg: ?u8 = null; |
| 583 | 584 | var dyld_info_lc: ?macho.dyld_info_command = null; |
| 584 | 585 | |
| 585 | 586 | try dumpHeader(hdr, writer); |
| ... | ... | @@ -597,8 +598,10 @@ const MachODumper = struct { |
| 597 | 598 | for (cmd.getSections()) |sect| { |
| 598 | 599 | sections.appendAssumeCapacity(sect); |
| 599 | 600 | } |
| 601 | const seg_id: u8 = @intCast(segments.items.len); |
| 602 | try segments.append(seg); |
| 600 | 603 | if (mem.eql(u8, seg.segName(), "__TEXT")) { |
| 601 | | text_seg = seg; |
| 604 | text_seg = seg_id; |
| 602 | 605 | } |
| 603 | 606 | }, |
| 604 | 607 | .SYMTAB => { |
| ... | ... | @@ -631,9 +634,13 @@ const MachODumper = struct { |
| 631 | 634 | |
| 632 | 635 | if (dyld_info_lc) |lc| { |
| 633 | 636 | try writer.writeAll(dyld_info_label ++ "\n"); |
| 637 | if (lc.rebase_size > 0) { |
| 638 | const data = bytes[lc.rebase_off..][0..lc.rebase_size]; |
| 639 | try dumpRebaseInfo(gpa, data, segments.items, writer); |
| 640 | } |
| 634 | 641 | if (lc.export_size > 0) { |
| 635 | 642 | const data = bytes[lc.export_off..][0..lc.export_size]; |
| 636 | | try dumpExportsTrie(gpa, data, text_seg.?, writer); |
| 643 | try dumpExportsTrie(gpa, data, segments.items[text_seg.?], writer); |
| 637 | 644 | } |
| 638 | 645 | } |
| 639 | 646 | |
| ... | ... | @@ -994,6 +1001,91 @@ const MachODumper = struct { |
| 994 | 1001 | } |
| 995 | 1002 | } |
| 996 | 1003 | |
| 1004 | fn dumpRebaseInfo( |
| 1005 | gpa: Allocator, |
| 1006 | data: []const u8, |
| 1007 | segments: []const macho.segment_command_64, |
| 1008 | writer: anytype, |
| 1009 | ) !void { |
| 1010 | var rebases = std.ArrayList(u64).init(gpa); |
| 1011 | defer rebases.deinit(); |
| 1012 | try parseRebaseInfo(data, segments, &rebases); |
| 1013 | mem.sort(u64, rebases.items, {}, std.sort.asc(u64)); |
| 1014 | try writer.writeAll("rebase info\n"); |
| 1015 | for (rebases.items) |addr| { |
| 1016 | try writer.print("0x{x}\n", .{addr}); |
| 1017 | } |
| 1018 | } |
| 1019 | |
| 1020 | fn parseRebaseInfo( |
| 1021 | data: []const u8, |
| 1022 | segments: []const macho.segment_command_64, |
| 1023 | rebases: *std.ArrayList(u64), |
| 1024 | ) !void { |
| 1025 | var stream = std.io.fixedBufferStream(data); |
| 1026 | var creader = std.io.countingReader(stream.reader()); |
| 1027 | const reader = creader.reader(); |
| 1028 | |
| 1029 | var seg_id: ?u8 = null; |
| 1030 | var offset: u64 = 0; |
| 1031 | while (true) { |
| 1032 | const byte = reader.readByte() catch break; |
| 1033 | const opc = byte & macho.REBASE_OPCODE_MASK; |
| 1034 | const imm = byte & macho.REBASE_IMMEDIATE_MASK; |
| 1035 | switch (opc) { |
| 1036 | macho.REBASE_OPCODE_DONE => break, |
| 1037 | macho.REBASE_OPCODE_SET_TYPE_IMM => {}, |
| 1038 | macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { |
| 1039 | seg_id = imm; |
| 1040 | offset = try std.leb.readULEB128(u64, reader); |
| 1041 | }, |
| 1042 | macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED => { |
| 1043 | offset += imm * @sizeOf(u64); |
| 1044 | }, |
| 1045 | macho.REBASE_OPCODE_ADD_ADDR_ULEB => { |
| 1046 | const addend = try std.leb.readULEB128(u64, reader); |
| 1047 | offset += addend; |
| 1048 | }, |
| 1049 | macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB => { |
| 1050 | const addend = try std.leb.readULEB128(u64, reader); |
| 1051 | const seg = segments.items[seg_id.?]; |
| 1052 | const addr = seg.vmaddr + offset; |
| 1053 | try rebases.append(addr); |
| 1054 | offset += addend + @sizeOf(u64); |
| 1055 | }, |
| 1056 | macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES, |
| 1057 | macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES, |
| 1058 | macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB, |
| 1059 | => { |
| 1060 | var ntimes: u64 = 1; |
| 1061 | var skip: u64 = 0; |
| 1062 | switch (opc) { |
| 1063 | macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES => { |
| 1064 | ntimes = imm; |
| 1065 | }, |
| 1066 | macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES => { |
| 1067 | ntimes = try std.leb.readULEB128(u64, reader); |
| 1068 | }, |
| 1069 | macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB => { |
| 1070 | ntimes = try std.leb.readULEB128(u64, reader); |
| 1071 | skip = try std.leb.readULEB128(u64, reader); |
| 1072 | }, |
| 1073 | else => unreachable, |
| 1074 | } |
| 1075 | const seg = segments.items[seg_id.?]; |
| 1076 | const base_addr = seg.vmaddr; |
| 1077 | var count: usize = 0; |
| 1078 | while (count < ntimes) : (count += 1) { |
| 1079 | const addr = base_addr + offset; |
| 1080 | try rebases.append(addr); |
| 1081 | offset += skip + @sizeOf(u64); |
| 1082 | } |
| 1083 | }, |
| 1084 | else => break, |
| 1085 | } |
| 1086 | } |
| 1087 | } |
| 1088 | |
| 997 | 1089 | fn dumpExportsTrie( |
| 998 | 1090 | gpa: Allocator, |
| 999 | 1091 | data: []const u8, |