| ... | @@ -645,17 +645,17 @@ const MachODumper = struct { | ... | @@ -645,17 +645,17 @@ const MachODumper = struct { |
| 645 | if (lc.bind_size > 0) { | 645 | if (lc.bind_size > 0) { |
| 646 | const data = bytes[lc.bind_off..][0..lc.bind_size]; | 646 | const data = bytes[lc.bind_off..][0..lc.bind_size]; |
| 647 | try writer.writeAll("bind info\n"); | 647 | try writer.writeAll("bind info\n"); |
| 648 | try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer); | 648 | try dumpBindInfo(gpa, data, segments.items, imports.items, writer); |
| 649 | } | 649 | } |
| 650 | if (lc.weak_bind_size > 0) { | 650 | if (lc.weak_bind_size > 0) { |
| 651 | const data = bytes[lc.weak_bind_off..][0..lc.weak_bind_size]; | 651 | const data = bytes[lc.weak_bind_off..][0..lc.weak_bind_size]; |
| 652 | try writer.writeAll("weak bind info\n"); | 652 | try writer.writeAll("weak bind info\n"); |
| 653 | try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer); | 653 | try dumpBindInfo(gpa, data, segments.items, imports.items, writer); |
| 654 | } | 654 | } |
| 655 | if (lc.lazy_bind_size > 0) { | 655 | if (lc.lazy_bind_size > 0) { |
| 656 | const data = bytes[lc.lazy_bind_off..][0..lc.lazy_bind_size]; | 656 | const data = bytes[lc.lazy_bind_off..][0..lc.lazy_bind_size]; |
| 657 | try writer.writeAll("lazy bind info\n"); | 657 | try writer.writeAll("lazy bind info\n"); |
| 658 | try dumpBindInfo(gpa, data, segments.items, imports.items, true, writer); | 658 | try dumpBindInfo(gpa, data, segments.items, imports.items, writer); |
| 659 | } | 659 | } |
| 660 | if (lc.export_size > 0) { | 660 | if (lc.export_size > 0) { |
| 661 | const data = bytes[lc.export_off..][0..lc.export_size]; | 661 | const data = bytes[lc.export_off..][0..lc.export_size]; |
| ... | @@ -993,7 +993,7 @@ const MachODumper = struct { | ... | @@ -993,7 +993,7 @@ const MachODumper = struct { |
| 993 | if (sym.ext()) try writer.writeAll(" external"); | 993 | if (sym.ext()) try writer.writeAll(" external"); |
| 994 | try writer.print(" {s}\n", .{sym_name}); | 994 | try writer.print(" {s}\n", .{sym_name}); |
| 995 | } else if (sym.undf()) { | 995 | } else if (sym.undf()) { |
| 996 | const ordinal = @divTrunc(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER); | 996 | const ordinal = @divFloor(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER); |
| 997 | const import_name = blk: { | 997 | const import_name = blk: { |
| 998 | if (ordinal <= 0) { | 998 | if (ordinal <= 0) { |
| 999 | if (ordinal == macho.BIND_SPECIAL_DYLIB_SELF) | 999 | if (ordinal == macho.BIND_SPECIAL_DYLIB_SELF) |
| ... | @@ -1108,7 +1108,8 @@ const MachODumper = struct { | ... | @@ -1108,7 +1108,8 @@ const MachODumper = struct { |
| 1108 | const Binding = struct { | 1108 | const Binding = struct { |
| 1109 | address: u64, | 1109 | address: u64, |
| 1110 | addend: i64, | 1110 | addend: i64, |
| 1111 | ordinal: ?u16, | 1111 | ordinal: u16, |
| | 1112 | tag: Tag, |
| 1112 | name: []const u8, | 1113 | name: []const u8, |
| 1113 | | 1114 | |
| 1114 | fn deinit(binding: *Binding, gpa: Allocator) void { | 1115 | fn deinit(binding: *Binding, gpa: Allocator) void { |
| ... | @@ -1119,6 +1120,13 @@ const MachODumper = struct { | ... | @@ -1119,6 +1120,13 @@ const MachODumper = struct { |
| 1119 | _ = ctx; | 1120 | _ = ctx; |
| 1120 | return lhs.address < rhs.address; | 1121 | return lhs.address < rhs.address; |
| 1121 | } | 1122 | } |
| | 1123 | |
| | 1124 | const Tag = enum { |
| | 1125 | ord, |
| | 1126 | self, |
| | 1127 | exe, |
| | 1128 | flat, |
| | 1129 | }; |
| 1122 | }; | 1130 | }; |
| 1123 | | 1131 | |
| 1124 | fn dumpBindInfo( | 1132 | fn dumpBindInfo( |
| ... | @@ -1126,7 +1134,6 @@ const MachODumper = struct { | ... | @@ -1126,7 +1134,6 @@ const MachODumper = struct { |
| 1126 | data: []const u8, | 1134 | data: []const u8, |
| 1127 | segments: []const macho.segment_command_64, | 1135 | segments: []const macho.segment_command_64, |
| 1128 | dylibs: []const []const u8, | 1136 | dylibs: []const []const u8, |
| 1129 | is_lazy: bool, | | |
| 1130 | writer: anytype, | 1137 | writer: anytype, |
| 1131 | ) !void { | 1138 | ) !void { |
| 1132 | var bindings = std.ArrayList(Binding).init(gpa); | 1139 | var bindings = std.ArrayList(Binding).init(gpa); |
| ... | @@ -1136,14 +1143,18 @@ const MachODumper = struct { | ... | @@ -1136,14 +1143,18 @@ const MachODumper = struct { |
| 1136 | } | 1143 | } |
| 1137 | bindings.deinit(); | 1144 | bindings.deinit(); |
| 1138 | } | 1145 | } |
| 1139 | try parseBindInfo(gpa, data, segments, &bindings, is_lazy); | 1146 | try parseBindInfo(gpa, data, segments, &bindings); |
| 1140 | mem.sort(Binding, bindings.items, {}, Binding.lessThan); | 1147 | mem.sort(Binding, bindings.items, {}, Binding.lessThan); |
| 1141 | for (bindings.items) |binding| { | 1148 | for (bindings.items) |binding| { |
| 1142 | try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); | 1149 | try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); |
| 1143 | if (binding.ordinal) |ord| { | 1150 | try writer.writeAll(" ("); |
| 1144 | try writer.print(" ({s})", .{std.fs.path.basename(dylibs[ord - 1])}); | 1151 | switch (binding.tag) { |
| | 1152 | .self => try writer.writeAll("self"), |
| | 1153 | .exe => try writer.writeAll("main executable"), |
| | 1154 | .flat => try writer.writeAll("flat lookup"), |
| | 1155 | .ord => try writer.writeAll(std.fs.path.basename(dylibs[binding.ordinal - 1])), |
| 1145 | } | 1156 | } |
| 1146 | try writer.print(" {s}\n", .{binding.name}); | 1157 | try writer.print(") {s}\n", .{binding.name}); |
| 1147 | } | 1158 | } |
| 1148 | } | 1159 | } |
| 1149 | | 1160 | |
| ... | @@ -1152,14 +1163,14 @@ const MachODumper = struct { | ... | @@ -1152,14 +1163,14 @@ const MachODumper = struct { |
| 1152 | data: []const u8, | 1163 | data: []const u8, |
| 1153 | segments: []const macho.segment_command_64, | 1164 | segments: []const macho.segment_command_64, |
| 1154 | bindings: *std.ArrayList(Binding), | 1165 | bindings: *std.ArrayList(Binding), |
| 1155 | lazy_ops: bool, | | |
| 1156 | ) !void { | 1166 | ) !void { |
| 1157 | var stream = std.io.fixedBufferStream(data); | 1167 | var stream = std.io.fixedBufferStream(data); |
| 1158 | var creader = std.io.countingReader(stream.reader()); | 1168 | var creader = std.io.countingReader(stream.reader()); |
| 1159 | const reader = creader.reader(); | 1169 | const reader = creader.reader(); |
| 1160 | | 1170 | |
| 1161 | var seg_id: ?u8 = null; | 1171 | var seg_id: ?u8 = null; |
| 1162 | var dylib_id: ?u16 = null; | 1172 | var tag: Binding.Tag = .self; |
| | 1173 | var ordinal: u16 = 0; |
| 1163 | var offset: u64 = 0; | 1174 | var offset: u64 = 0; |
| 1164 | var addend: i64 = 0; | 1175 | var addend: i64 = 0; |
| 1165 | | 1176 | |
| ... | @@ -1171,14 +1182,20 @@ const MachODumper = struct { | ... | @@ -1171,14 +1182,20 @@ const MachODumper = struct { |
| 1171 | const opc = byte & macho.BIND_OPCODE_MASK; | 1182 | const opc = byte & macho.BIND_OPCODE_MASK; |
| 1172 | const imm = byte & macho.BIND_IMMEDIATE_MASK; | 1183 | const imm = byte & macho.BIND_IMMEDIATE_MASK; |
| 1173 | switch (opc) { | 1184 | switch (opc) { |
| 1174 | macho.BIND_OPCODE_DONE => { | 1185 | macho.BIND_OPCODE_DONE, |
| 1175 | if (!lazy_ops) break; | 1186 | macho.BIND_OPCODE_SET_TYPE_IMM, |
| 1176 | }, | 1187 | => {}, |
| 1177 | macho.BIND_OPCODE_SET_TYPE_IMM => { | | |
| 1178 | if (lazy_ops) break; | | |
| 1179 | }, | | |
| 1180 | macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => { | 1188 | macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => { |
| 1181 | dylib_id = imm; | 1189 | tag = .ord; |
| | 1190 | ordinal = imm; |
| | 1191 | }, |
| | 1192 | macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM => { |
| | 1193 | switch (imm) { |
| | 1194 | 0 => tag = .self, |
| | 1195 | 0xf => tag = .exe, |
| | 1196 | 0xe => tag = .flat, |
| | 1197 | else => unreachable, |
| | 1198 | } |
| 1182 | }, | 1199 | }, |
| 1183 | macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { | 1200 | macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { |
| 1184 | seg_id = imm; | 1201 | seg_id = imm; |
| ... | @@ -1193,7 +1210,6 @@ const MachODumper = struct { | ... | @@ -1193,7 +1210,6 @@ const MachODumper = struct { |
| 1193 | addend = try std.leb.readILEB128(i64, reader); | 1210 | addend = try std.leb.readILEB128(i64, reader); |
| 1194 | }, | 1211 | }, |
| 1195 | macho.BIND_OPCODE_ADD_ADDR_ULEB => { | 1212 | macho.BIND_OPCODE_ADD_ADDR_ULEB => { |
| 1196 | if (lazy_ops) break; | | |
| 1197 | const x = try std.leb.readULEB128(u64, reader); | 1213 | const x = try std.leb.readULEB128(u64, reader); |
| 1198 | offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x))); | 1214 | offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x))); |
| 1199 | }, | 1215 | }, |
| ... | @@ -1209,15 +1225,12 @@ const MachODumper = struct { | ... | @@ -1209,15 +1225,12 @@ const MachODumper = struct { |
| 1209 | switch (opc) { | 1225 | switch (opc) { |
| 1210 | macho.BIND_OPCODE_DO_BIND => {}, | 1226 | macho.BIND_OPCODE_DO_BIND => {}, |
| 1211 | macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => { | 1227 | macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => { |
| 1212 | if (lazy_ops) break; | | |
| 1213 | add_addr = try std.leb.readULEB128(u64, reader); | 1228 | add_addr = try std.leb.readULEB128(u64, reader); |
| 1214 | }, | 1229 | }, |
| 1215 | macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => { | 1230 | macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => { |
| 1216 | if (lazy_ops) break; | | |
| 1217 | add_addr = imm * @sizeOf(u64); | 1231 | add_addr = imm * @sizeOf(u64); |
| 1218 | }, | 1232 | }, |
| 1219 | macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => { | 1233 | macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => { |
| 1220 | if (lazy_ops) break; | | |
| 1221 | count = try std.leb.readULEB128(u64, reader); | 1234 | count = try std.leb.readULEB128(u64, reader); |
| 1222 | skip = try std.leb.readULEB128(u64, reader); | 1235 | skip = try std.leb.readULEB128(u64, reader); |
| 1223 | }, | 1236 | }, |
| ... | @@ -1231,7 +1244,8 @@ const MachODumper = struct { | ... | @@ -1231,7 +1244,8 @@ const MachODumper = struct { |
| 1231 | try bindings.append(.{ | 1244 | try bindings.append(.{ |
| 1232 | .address = addr, | 1245 | .address = addr, |
| 1233 | .addend = addend, | 1246 | .addend = addend, |
| 1234 | .ordinal = dylib_id, | 1247 | .tag = tag, |
| | 1248 | .ordinal = ordinal, |
| 1235 | .name = try gpa.dupe(u8, name_buf.items), | 1249 | .name = try gpa.dupe(u8, name_buf.items), |
| 1236 | }); | 1250 | }); |
| 1237 | offset += skip + @sizeOf(u64) + add_addr; | 1251 | offset += skip + @sizeOf(u64) + add_addr; |