mirror of
https://github.com/ziglang/zig.git
synced 2025-12-21 13:43:10 +00:00
lib/std/Build/CheckObject: dump Mach-O dyld_info_only bind, weak-bind and lazy-bind data
This commit is contained in:
parent
5bda88f9a3
commit
a2d8e03931
@ -577,9 +577,12 @@ const MachODumper = struct {
|
|||||||
const writer = output.writer();
|
const writer = output.writer();
|
||||||
|
|
||||||
var symtab: ?Symtab = null;
|
var symtab: ?Symtab = null;
|
||||||
var segments = std.ArrayList(macho.segment_command_u64);
|
var segments = std.ArrayList(macho.segment_command_64).init(gpa);
|
||||||
|
defer segments.deinit();
|
||||||
var sections = std.ArrayList(macho.section_64).init(gpa);
|
var sections = std.ArrayList(macho.section_64).init(gpa);
|
||||||
|
defer sections.deinit();
|
||||||
var imports = std.ArrayList([]const u8).init(gpa);
|
var imports = std.ArrayList([]const u8).init(gpa);
|
||||||
|
defer imports.deinit();
|
||||||
var text_seg: ?u8 = null;
|
var text_seg: ?u8 = null;
|
||||||
var dyld_info_lc: ?macho.dyld_info_command = null;
|
var dyld_info_lc: ?macho.dyld_info_command = null;
|
||||||
|
|
||||||
@ -636,10 +639,27 @@ const MachODumper = struct {
|
|||||||
try writer.writeAll(dyld_info_label ++ "\n");
|
try writer.writeAll(dyld_info_label ++ "\n");
|
||||||
if (lc.rebase_size > 0) {
|
if (lc.rebase_size > 0) {
|
||||||
const data = bytes[lc.rebase_off..][0..lc.rebase_size];
|
const data = bytes[lc.rebase_off..][0..lc.rebase_size];
|
||||||
|
try writer.writeAll("rebase info\n");
|
||||||
try dumpRebaseInfo(gpa, data, segments.items, writer);
|
try dumpRebaseInfo(gpa, data, segments.items, writer);
|
||||||
}
|
}
|
||||||
|
if (lc.bind_size > 0) {
|
||||||
|
const data = bytes[lc.bind_off..][0..lc.bind_size];
|
||||||
|
try writer.writeAll("bind info\n");
|
||||||
|
try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer);
|
||||||
|
}
|
||||||
|
if (lc.weak_bind_size > 0) {
|
||||||
|
const data = bytes[lc.weak_bind_off..][0..lc.weak_bind_size];
|
||||||
|
try writer.writeAll("weak bind info\n");
|
||||||
|
try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer);
|
||||||
|
}
|
||||||
|
if (lc.lazy_bind_size > 0) {
|
||||||
|
const data = bytes[lc.lazy_bind_off..][0..lc.lazy_bind_size];
|
||||||
|
try writer.writeAll("lazy bind info\n");
|
||||||
|
try dumpBindInfo(gpa, data, segments.items, imports.items, true, writer);
|
||||||
|
}
|
||||||
if (lc.export_size > 0) {
|
if (lc.export_size > 0) {
|
||||||
const data = bytes[lc.export_off..][0..lc.export_size];
|
const data = bytes[lc.export_off..][0..lc.export_size];
|
||||||
|
try writer.writeAll("exports\n");
|
||||||
try dumpExportsTrie(gpa, data, segments.items[text_seg.?], writer);
|
try dumpExportsTrie(gpa, data, segments.items[text_seg.?], writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1011,7 +1031,6 @@ const MachODumper = struct {
|
|||||||
defer rebases.deinit();
|
defer rebases.deinit();
|
||||||
try parseRebaseInfo(data, segments, &rebases);
|
try parseRebaseInfo(data, segments, &rebases);
|
||||||
mem.sort(u64, rebases.items, {}, std.sort.asc(u64));
|
mem.sort(u64, rebases.items, {}, std.sort.asc(u64));
|
||||||
try writer.writeAll("rebase info\n");
|
|
||||||
for (rebases.items) |addr| {
|
for (rebases.items) |addr| {
|
||||||
try writer.print("0x{x}\n", .{addr});
|
try writer.print("0x{x}\n", .{addr});
|
||||||
}
|
}
|
||||||
@ -1048,7 +1067,7 @@ const MachODumper = struct {
|
|||||||
},
|
},
|
||||||
macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB => {
|
macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB => {
|
||||||
const addend = try std.leb.readULEB128(u64, reader);
|
const addend = try std.leb.readULEB128(u64, reader);
|
||||||
const seg = segments.items[seg_id.?];
|
const seg = segments[seg_id.?];
|
||||||
const addr = seg.vmaddr + offset;
|
const addr = seg.vmaddr + offset;
|
||||||
try rebases.append(addr);
|
try rebases.append(addr);
|
||||||
offset += addend + @sizeOf(u64);
|
offset += addend + @sizeOf(u64);
|
||||||
@ -1072,7 +1091,7 @@ const MachODumper = struct {
|
|||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
const seg = segments.items[seg_id.?];
|
const seg = segments[seg_id.?];
|
||||||
const base_addr = seg.vmaddr;
|
const base_addr = seg.vmaddr;
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (count < ntimes) : (count += 1) {
|
while (count < ntimes) : (count += 1) {
|
||||||
@ -1086,6 +1105,143 @@ const MachODumper = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Binding = struct {
|
||||||
|
address: u64,
|
||||||
|
addend: i64,
|
||||||
|
ordinal: ?u16,
|
||||||
|
name: []const u8,
|
||||||
|
|
||||||
|
fn deinit(binding: *Binding, gpa: Allocator) void {
|
||||||
|
gpa.free(binding.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lessThan(ctx: void, lhs: Binding, rhs: Binding) bool {
|
||||||
|
_ = ctx;
|
||||||
|
return lhs.address < rhs.address;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn dumpBindInfo(
|
||||||
|
gpa: Allocator,
|
||||||
|
data: []const u8,
|
||||||
|
segments: []const macho.segment_command_64,
|
||||||
|
dylibs: []const []const u8,
|
||||||
|
is_lazy: bool,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
var bindings = std.ArrayList(Binding).init(gpa);
|
||||||
|
defer {
|
||||||
|
for (bindings.items) |*b| {
|
||||||
|
b.deinit(gpa);
|
||||||
|
}
|
||||||
|
bindings.deinit();
|
||||||
|
}
|
||||||
|
try parseBindInfo(gpa, data, segments, &bindings, is_lazy);
|
||||||
|
mem.sort(Binding, bindings.items, {}, Binding.lessThan);
|
||||||
|
for (bindings.items) |binding| {
|
||||||
|
try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend });
|
||||||
|
if (binding.ordinal) |ord| {
|
||||||
|
try writer.print(" ({s})", .{std.fs.path.basename(dylibs[ord - 1])});
|
||||||
|
}
|
||||||
|
try writer.print(" {s}\n", .{binding.name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseBindInfo(
|
||||||
|
gpa: Allocator,
|
||||||
|
data: []const u8,
|
||||||
|
segments: []const macho.segment_command_64,
|
||||||
|
bindings: *std.ArrayList(Binding),
|
||||||
|
lazy_ops: bool,
|
||||||
|
) !void {
|
||||||
|
var stream = std.io.fixedBufferStream(data);
|
||||||
|
var creader = std.io.countingReader(stream.reader());
|
||||||
|
const reader = creader.reader();
|
||||||
|
|
||||||
|
var seg_id: ?u8 = null;
|
||||||
|
var dylib_id: ?u16 = null;
|
||||||
|
var offset: u64 = 0;
|
||||||
|
var addend: i64 = 0;
|
||||||
|
|
||||||
|
var name_buf = std.ArrayList(u8).init(gpa);
|
||||||
|
defer name_buf.deinit();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const byte = reader.readByte() catch break;
|
||||||
|
const opc = byte & macho.BIND_OPCODE_MASK;
|
||||||
|
const imm = byte & macho.BIND_IMMEDIATE_MASK;
|
||||||
|
switch (opc) {
|
||||||
|
macho.BIND_OPCODE_DONE => {
|
||||||
|
if (!lazy_ops) break;
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_SET_TYPE_IMM => {
|
||||||
|
if (lazy_ops) break;
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => {
|
||||||
|
dylib_id = imm;
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
|
||||||
|
seg_id = imm;
|
||||||
|
offset = try std.leb.readULEB128(u64, reader);
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
|
||||||
|
name_buf.clearRetainingCapacity();
|
||||||
|
try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32));
|
||||||
|
try name_buf.append(0);
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_SET_ADDEND_SLEB => {
|
||||||
|
addend = try std.leb.readILEB128(i64, reader);
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_ADD_ADDR_ULEB => {
|
||||||
|
if (lazy_ops) break;
|
||||||
|
const x = try std.leb.readULEB128(u64, reader);
|
||||||
|
offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x)));
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_DO_BIND,
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB,
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED,
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB,
|
||||||
|
=> {
|
||||||
|
var add_addr: u64 = 0;
|
||||||
|
var count: u64 = 1;
|
||||||
|
var skip: u64 = 0;
|
||||||
|
|
||||||
|
switch (opc) {
|
||||||
|
macho.BIND_OPCODE_DO_BIND => {},
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => {
|
||||||
|
if (lazy_ops) break;
|
||||||
|
add_addr = try std.leb.readULEB128(u64, reader);
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => {
|
||||||
|
if (lazy_ops) break;
|
||||||
|
add_addr = imm * @sizeOf(u64);
|
||||||
|
},
|
||||||
|
macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => {
|
||||||
|
if (lazy_ops) break;
|
||||||
|
count = try std.leb.readULEB128(u64, reader);
|
||||||
|
skip = try std.leb.readULEB128(u64, reader);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
const seg = segments[seg_id.?];
|
||||||
|
var i: u64 = 0;
|
||||||
|
while (i < count) : (i += 1) {
|
||||||
|
const addr: u64 = @intCast(@as(i64, @intCast(seg.vmaddr + offset)));
|
||||||
|
try bindings.append(.{
|
||||||
|
.address = addr,
|
||||||
|
.addend = addend,
|
||||||
|
.ordinal = dylib_id,
|
||||||
|
.name = try gpa.dupe(u8, name_buf.items),
|
||||||
|
});
|
||||||
|
offset += skip + @sizeOf(u64) + add_addr;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dumpExportsTrie(
|
fn dumpExportsTrie(
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
data: []const u8,
|
data: []const u8,
|
||||||
@ -1101,7 +1257,6 @@ const MachODumper = struct {
|
|||||||
|
|
||||||
mem.sort(Export, exports.items, {}, Export.lessThan);
|
mem.sort(Export, exports.items, {}, Export.lessThan);
|
||||||
|
|
||||||
try writer.writeAll("exports\n");
|
|
||||||
for (exports.items) |exp| {
|
for (exports.items) |exp| {
|
||||||
switch (exp.tag) {
|
switch (exp.tag) {
|
||||||
.@"export" => {
|
.@"export" => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user