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