mirror of
https://github.com/ziglang/zig.git
synced 2026-01-10 09:25:11 +00:00
Merge pull request #18271 from ziglang/check-object-scoped-checks
lib/std/Build/CheckObject: introduce scoped checks
This commit is contained in:
commit
4574dea13a
@ -246,10 +246,12 @@ const ComputeCompareExpected = struct {
|
||||
};
|
||||
|
||||
const Check = struct {
|
||||
kind: Kind,
|
||||
actions: std.ArrayList(Action),
|
||||
|
||||
fn create(allocator: Allocator) Check {
|
||||
fn create(allocator: Allocator, kind: Kind) Check {
|
||||
return .{
|
||||
.kind = kind,
|
||||
.actions = std.ArrayList(Action).init(allocator),
|
||||
};
|
||||
}
|
||||
@ -289,15 +291,30 @@ const Check = struct {
|
||||
.expected = expected,
|
||||
}) catch @panic("OOM");
|
||||
}
|
||||
|
||||
const Kind = enum {
|
||||
headers,
|
||||
symtab,
|
||||
indirect_symtab,
|
||||
dynamic_symtab,
|
||||
archive_symtab,
|
||||
dynamic_section,
|
||||
dyld_rebase,
|
||||
dyld_bind,
|
||||
dyld_weak_bind,
|
||||
dyld_lazy_bind,
|
||||
exports,
|
||||
compute_compare,
|
||||
};
|
||||
};
|
||||
|
||||
/// Creates a new empty sequence of actions.
|
||||
pub fn checkStart(self: *CheckObject) void {
|
||||
const new_check = Check.create(self.step.owner.allocator);
|
||||
fn checkStart(self: *CheckObject, kind: Check.Kind) void {
|
||||
const new_check = Check.create(self.step.owner.allocator, kind);
|
||||
self.checks.append(new_check) catch @panic("OOM");
|
||||
}
|
||||
|
||||
/// Adds an exact match phrase to the latest created Check with `CheckObject.checkStart()`.
|
||||
/// Adds an exact match phrase to the latest created Check.
|
||||
pub fn checkExact(self: *CheckObject, phrase: []const u8) void {
|
||||
self.checkExactInner(phrase, null);
|
||||
}
|
||||
@ -314,7 +331,7 @@ fn checkExactInner(self: *CheckObject, phrase: []const u8, file_source: ?std.Bui
|
||||
last.exact(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
|
||||
}
|
||||
|
||||
/// Adds a fuzzy match phrase to the latest created Check with `CheckObject.checkStart()`.
|
||||
/// Adds a fuzzy match phrase to the latest created Check.
|
||||
pub fn checkContains(self: *CheckObject, phrase: []const u8) void {
|
||||
self.checkContainsInner(phrase, null);
|
||||
}
|
||||
@ -331,8 +348,7 @@ fn checkContainsInner(self: *CheckObject, phrase: []const u8, file_source: ?std.
|
||||
last.contains(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
|
||||
}
|
||||
|
||||
/// Adds an exact match phrase with variable extractor to the latest created Check
|
||||
/// with `CheckObject.checkStart()`.
|
||||
/// Adds an exact match phrase with variable extractor to the latest created Check.
|
||||
pub fn checkExtract(self: *CheckObject, phrase: []const u8) void {
|
||||
self.checkExtractInner(phrase, null);
|
||||
}
|
||||
@ -349,7 +365,7 @@ fn checkExtractInner(self: *CheckObject, phrase: []const u8, file_source: ?std.B
|
||||
last.extract(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
|
||||
}
|
||||
|
||||
/// Adds another searched phrase to the latest created Check with `CheckObject.checkStart(...)`
|
||||
/// Adds another searched phrase to the latest created Check
|
||||
/// however ensures there is no matching phrase in the output.
|
||||
pub fn checkNotPresent(self: *CheckObject, phrase: []const u8) void {
|
||||
self.checkNotPresentInner(phrase, null);
|
||||
@ -367,6 +383,11 @@ fn checkNotPresentInner(self: *CheckObject, phrase: []const u8, file_source: ?st
|
||||
last.notPresent(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source });
|
||||
}
|
||||
|
||||
/// Creates a new check checking in the file headers (section, program headers, etc.).
|
||||
pub fn checkInHeaders(self: *CheckObject) void {
|
||||
self.checkStart(.headers);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically symbol table parsed and dumped from the object
|
||||
/// file.
|
||||
pub fn checkInSymtab(self: *CheckObject) void {
|
||||
@ -377,19 +398,79 @@ pub fn checkInSymtab(self: *CheckObject) void {
|
||||
.coff => @panic("TODO symtab for coff"),
|
||||
else => @panic("TODO other file formats"),
|
||||
};
|
||||
self.checkStart();
|
||||
self.checkStart(.symtab);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically dyld_info_only contents parsed and dumped
|
||||
/// Creates a new check checking specifically dyld rebase opcodes contents parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInDyldInfo(self: *CheckObject) void {
|
||||
pub fn checkInDyldRebase(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.dyld_info_label,
|
||||
.macho => MachODumper.dyld_rebase_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart();
|
||||
self.checkStart(.dyld_rebase);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically dyld bind opcodes contents parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInDyldBind(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.dyld_bind_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart(.dyld_bind);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically dyld weak bind opcodes contents parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInDyldWeakBind(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.dyld_weak_bind_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart(.dyld_weak_bind);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically dyld lazy bind opcodes contents parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInDyldLazyBind(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.dyld_lazy_bind_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart(.dyld_lazy_bind);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically exports info contents parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInExports(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.exports_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart(.exports);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
/// Creates a new check checking specifically indirect symbol table parsed and dumped
|
||||
/// from the object file.
|
||||
/// This check is target-dependent and applicable to MachO only.
|
||||
pub fn checkInIndirectSymtab(self: *CheckObject) void {
|
||||
const label = switch (self.obj_format) {
|
||||
.macho => MachODumper.indirect_symtab_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart(.indirect_symtab);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
@ -401,7 +482,7 @@ pub fn checkInDynamicSymtab(self: *CheckObject) void {
|
||||
.elf => ElfDumper.dynamic_symtab_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart();
|
||||
self.checkStart(.dynamic_symtab);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
@ -413,7 +494,7 @@ pub fn checkInDynamicSection(self: *CheckObject) void {
|
||||
.elf => ElfDumper.dynamic_section_label,
|
||||
else => @panic("Unsupported target platform"),
|
||||
};
|
||||
self.checkStart();
|
||||
self.checkStart(.dynamic_section);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
@ -424,7 +505,7 @@ pub fn checkInArchiveSymtab(self: *CheckObject) void {
|
||||
.elf => ElfDumper.archive_symtab_label,
|
||||
else => @panic("TODO other file formats"),
|
||||
};
|
||||
self.checkStart();
|
||||
self.checkStart(.archive_symtab);
|
||||
self.checkExact(label);
|
||||
}
|
||||
|
||||
@ -436,7 +517,7 @@ pub fn checkComputeCompare(
|
||||
program: []const u8,
|
||||
expected: ComputeCompareExpected,
|
||||
) void {
|
||||
var new_check = Check.create(self.step.owner.allocator);
|
||||
var new_check = Check.create(self.step.owner.allocator, .compute_compare);
|
||||
new_check.computeCmp(.{ .string = self.step.owner.dupe(program) }, expected);
|
||||
self.checks.append(new_check) catch @panic("OOM");
|
||||
}
|
||||
@ -457,17 +538,35 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
null,
|
||||
) catch |err| return step.fail("unable to read '{s}': {s}", .{ src_path, @errorName(err) });
|
||||
|
||||
const output = switch (self.obj_format) {
|
||||
.macho => try MachODumper.parseAndDump(step, contents),
|
||||
.elf => try ElfDumper.parseAndDump(step, contents),
|
||||
.coff => @panic("TODO coff parser"),
|
||||
.wasm => try WasmDumper.parseAndDump(step, contents),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var vars = std.StringHashMap(u64).init(gpa);
|
||||
|
||||
for (self.checks.items) |chk| {
|
||||
if (chk.kind == .compute_compare) {
|
||||
assert(chk.actions.items.len == 1);
|
||||
const act = chk.actions.items[0];
|
||||
assert(act.tag == .compute_cmp);
|
||||
const res = act.computeCmp(b, step, vars) catch |err| switch (err) {
|
||||
error.UnknownVariable => return step.fail("Unknown variable", .{}),
|
||||
else => |e| return e,
|
||||
};
|
||||
if (!res) {
|
||||
return step.fail(
|
||||
\\
|
||||
\\========= comparison failed for action: ===========
|
||||
\\{s} {}
|
||||
\\===================================================
|
||||
, .{ act.phrase.resolve(b, step), act.expected.? });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const output = switch (self.obj_format) {
|
||||
.macho => try MachODumper.parseAndDump(step, chk.kind, contents),
|
||||
.elf => try ElfDumper.parseAndDump(step, chk.kind, contents),
|
||||
.coff => return step.fail("TODO coff parser", .{}),
|
||||
.wasm => try WasmDumper.parseAndDump(step, chk.kind, contents),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var it = mem.tokenizeAny(u8, output, "\r\n");
|
||||
for (chk.actions.items) |act| {
|
||||
switch (act.tag) {
|
||||
@ -485,6 +584,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
, .{ act.phrase.resolve(b, step), output });
|
||||
}
|
||||
},
|
||||
|
||||
.contains => {
|
||||
while (it.next()) |line| {
|
||||
if (act.contains(b, step, line)) break;
|
||||
@ -499,6 +599,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
, .{ act.phrase.resolve(b, step), output });
|
||||
}
|
||||
},
|
||||
|
||||
.not_present => {
|
||||
while (it.next()) |line| {
|
||||
if (act.notPresent(b, step, line)) continue;
|
||||
@ -512,6 +613,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
, .{ act.phrase.resolve(b, step), output });
|
||||
}
|
||||
},
|
||||
|
||||
.extract => {
|
||||
while (it.next()) |line| {
|
||||
if (try act.extract(b, step, line, &vars)) break;
|
||||
@ -526,28 +628,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
, .{ act.phrase.resolve(b, step), output });
|
||||
}
|
||||
},
|
||||
.compute_cmp => {
|
||||
const res = act.computeCmp(b, step, vars) catch |err| switch (err) {
|
||||
error.UnknownVariable => {
|
||||
return step.fail(
|
||||
\\========= from parsed file: =====================
|
||||
\\{s}
|
||||
\\=================================================
|
||||
, .{output});
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
if (!res) {
|
||||
return step.fail(
|
||||
\\
|
||||
\\========= comparison failed for action: ===========
|
||||
\\{s} {}
|
||||
\\========= from parsed file: =======================
|
||||
\\{s}
|
||||
\\===================================================
|
||||
, .{ act.phrase.resolve(b, step), act.expected.?, output });
|
||||
}
|
||||
},
|
||||
|
||||
.compute_cmp => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -555,15 +637,26 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
|
||||
const MachODumper = struct {
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const dyld_info_label = "dyld info data";
|
||||
const dyld_rebase_label = "dyld rebase data";
|
||||
const dyld_bind_label = "dyld bind data";
|
||||
const dyld_weak_bind_label = "dyld weak bind data";
|
||||
const dyld_lazy_bind_label = "dyld lazy bind data";
|
||||
const exports_label = "exports data";
|
||||
const symtab_label = "symbol table";
|
||||
const indirect_symtab_label = "indirect symbol table";
|
||||
|
||||
const Symtab = struct {
|
||||
symbols: []align(1) const macho.nlist_64,
|
||||
strings: []const u8,
|
||||
symbols: []align(1) const macho.nlist_64 = &[0]macho.nlist_64{},
|
||||
strings: []const u8 = &[0]u8{},
|
||||
indirect_symbols: []align(1) const u32 = &[0]u32{},
|
||||
|
||||
fn getString(symtab: Symtab, off: u32) []const u8 {
|
||||
assert(off < symtab.strings.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(symtab.strings.ptr + off)), 0);
|
||||
}
|
||||
};
|
||||
|
||||
fn parseAndDump(step: *Step, bytes: []const u8) ![]const u8 {
|
||||
fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
|
||||
const gpa = step.owner.allocator;
|
||||
var stream = std.io.fixedBufferStream(bytes);
|
||||
const reader = stream.reader();
|
||||
@ -576,7 +669,7 @@ const MachODumper = struct {
|
||||
var output = std.ArrayList(u8).init(gpa);
|
||||
const writer = output.writer();
|
||||
|
||||
var symtab: ?Symtab = null;
|
||||
var symtab: Symtab = .{};
|
||||
var segments = std.ArrayList(macho.segment_command_64).init(gpa);
|
||||
defer segments.deinit();
|
||||
var sections = std.ArrayList(macho.section_64).init(gpa);
|
||||
@ -586,82 +679,129 @@ const MachODumper = struct {
|
||||
var text_seg: ?u8 = null;
|
||||
var dyld_info_lc: ?macho.dyld_info_command = null;
|
||||
|
||||
try dumpHeader(hdr, writer);
|
||||
{
|
||||
var it: LoadCommandIterator = .{
|
||||
.ncmds = hdr.ncmds,
|
||||
.buffer = bytes[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
|
||||
};
|
||||
var i: usize = 0;
|
||||
while (it.next()) |cmd| {
|
||||
switch (cmd.cmd()) {
|
||||
.SEGMENT_64 => {
|
||||
const seg = cmd.cast(macho.segment_command_64).?;
|
||||
try sections.ensureUnusedCapacity(seg.nsects);
|
||||
for (cmd.getSections()) |sect| {
|
||||
sections.appendAssumeCapacity(sect);
|
||||
}
|
||||
const seg_id: u8 = @intCast(segments.items.len);
|
||||
try segments.append(seg);
|
||||
if (mem.eql(u8, seg.segName(), "__TEXT")) {
|
||||
text_seg = seg_id;
|
||||
}
|
||||
},
|
||||
.SYMTAB => {
|
||||
const lc = cmd.cast(macho.symtab_command).?;
|
||||
const symbols = @as([*]align(1) const macho.nlist_64, @ptrCast(bytes.ptr + lc.symoff))[0..lc.nsyms];
|
||||
const strings = bytes[lc.stroff..][0..lc.strsize];
|
||||
symtab.symbols = symbols;
|
||||
symtab.strings = strings;
|
||||
},
|
||||
.DYSYMTAB => {
|
||||
const lc = cmd.cast(macho.dysymtab_command).?;
|
||||
const indexes = @as([*]align(1) const u32, @ptrCast(bytes.ptr + lc.indirectsymoff))[0..lc.nindirectsyms];
|
||||
symtab.indirect_symbols = indexes;
|
||||
},
|
||||
.LOAD_DYLIB,
|
||||
.LOAD_WEAK_DYLIB,
|
||||
.REEXPORT_DYLIB,
|
||||
=> {
|
||||
try imports.append(cmd.getDylibPathName());
|
||||
},
|
||||
.DYLD_INFO_ONLY => {
|
||||
dyld_info_lc = cmd.cast(macho.dyld_info_command).?;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var it: LoadCommandIterator = .{
|
||||
.ncmds = hdr.ncmds,
|
||||
.buffer = bytes[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
|
||||
};
|
||||
var i: usize = 0;
|
||||
while (it.next()) |cmd| {
|
||||
switch (cmd.cmd()) {
|
||||
.SEGMENT_64 => {
|
||||
const seg = cmd.cast(macho.segment_command_64).?;
|
||||
try sections.ensureUnusedCapacity(seg.nsects);
|
||||
for (cmd.getSections()) |sect| {
|
||||
sections.appendAssumeCapacity(sect);
|
||||
}
|
||||
const seg_id: u8 = @intCast(segments.items.len);
|
||||
try segments.append(seg);
|
||||
if (mem.eql(u8, seg.segName(), "__TEXT")) {
|
||||
text_seg = seg_id;
|
||||
}
|
||||
},
|
||||
.SYMTAB => {
|
||||
const lc = cmd.cast(macho.symtab_command).?;
|
||||
const symbols = @as([*]align(1) const macho.nlist_64, @ptrCast(bytes.ptr + lc.symoff))[0..lc.nsyms];
|
||||
const strings = bytes[lc.stroff..][0..lc.strsize];
|
||||
symtab = .{ .symbols = symbols, .strings = strings };
|
||||
},
|
||||
.LOAD_DYLIB,
|
||||
.LOAD_WEAK_DYLIB,
|
||||
.REEXPORT_DYLIB,
|
||||
=> {
|
||||
try imports.append(cmd.getDylibPathName());
|
||||
},
|
||||
.DYLD_INFO_ONLY => {
|
||||
dyld_info_lc = cmd.cast(macho.dyld_info_command).?;
|
||||
},
|
||||
else => {},
|
||||
i += 1;
|
||||
}
|
||||
|
||||
try dumpLoadCommand(cmd, i, writer);
|
||||
try writer.writeByte('\n');
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (symtab) |stab| {
|
||||
try dumpSymtab(sections.items, imports.items, stab, writer);
|
||||
}
|
||||
switch (kind) {
|
||||
.headers => {
|
||||
try dumpHeader(hdr, writer);
|
||||
|
||||
if (dyld_info_lc) |lc| {
|
||||
try writer.writeAll(dyld_info_label ++ "\n");
|
||||
if (lc.rebase_size > 0) {
|
||||
const data = bytes[lc.rebase_off..][0..lc.rebase_size];
|
||||
try writer.writeAll("rebase info\n");
|
||||
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, 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, 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, writer);
|
||||
}
|
||||
if (lc.export_size > 0) {
|
||||
const data = bytes[lc.export_off..][0..lc.export_size];
|
||||
try writer.writeAll("exports\n");
|
||||
try dumpExportsTrie(gpa, data, segments.items[text_seg.?], writer);
|
||||
}
|
||||
var it: LoadCommandIterator = .{
|
||||
.ncmds = hdr.ncmds,
|
||||
.buffer = bytes[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
|
||||
};
|
||||
var i: usize = 0;
|
||||
while (it.next()) |cmd| {
|
||||
try dumpLoadCommand(cmd, i, writer);
|
||||
try writer.writeByte('\n');
|
||||
|
||||
i += 1;
|
||||
}
|
||||
},
|
||||
|
||||
.symtab => if (symtab.symbols.len > 0) {
|
||||
try dumpSymtab(sections.items, imports.items, symtab, writer);
|
||||
} else return step.fail("no symbol table found", .{}),
|
||||
|
||||
.indirect_symtab => if (symtab.symbols.len > 0 and symtab.indirect_symbols.len > 0) {
|
||||
try dumpIndirectSymtab(gpa, sections.items, symtab, writer);
|
||||
} else return step.fail("no indirect symbol table found", .{}),
|
||||
|
||||
.dyld_rebase,
|
||||
.dyld_bind,
|
||||
.dyld_weak_bind,
|
||||
.dyld_lazy_bind,
|
||||
=> {
|
||||
if (dyld_info_lc == null) return step.fail("no dyld info found", .{});
|
||||
const lc = dyld_info_lc.?;
|
||||
|
||||
switch (kind) {
|
||||
.dyld_rebase => if (lc.rebase_size > 0) {
|
||||
const data = bytes[lc.rebase_off..][0..lc.rebase_size];
|
||||
try writer.writeAll(dyld_rebase_label ++ "\n");
|
||||
try dumpRebaseInfo(gpa, data, segments.items, writer);
|
||||
} else return step.fail("no rebase data found", .{}),
|
||||
|
||||
.dyld_bind => if (lc.bind_size > 0) {
|
||||
const data = bytes[lc.bind_off..][0..lc.bind_size];
|
||||
try writer.writeAll(dyld_bind_label ++ "\n");
|
||||
try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
|
||||
} else return step.fail("no bind data found", .{}),
|
||||
|
||||
.dyld_weak_bind => if (lc.weak_bind_size > 0) {
|
||||
const data = bytes[lc.weak_bind_off..][0..lc.weak_bind_size];
|
||||
try writer.writeAll(dyld_weak_bind_label ++ "\n");
|
||||
try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
|
||||
} else return step.fail("no weak bind data found", .{}),
|
||||
|
||||
.dyld_lazy_bind => if (lc.lazy_bind_size > 0) {
|
||||
const data = bytes[lc.lazy_bind_off..][0..lc.lazy_bind_size];
|
||||
try writer.writeAll(dyld_lazy_bind_label ++ "\n");
|
||||
try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
|
||||
} else return step.fail("no lazy bind data found", .{}),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
|
||||
.exports => blk: {
|
||||
if (dyld_info_lc) |lc| {
|
||||
if (lc.export_size > 0) {
|
||||
const data = bytes[lc.export_off..][0..lc.export_size];
|
||||
try writer.writeAll(exports_label ++ "\n");
|
||||
try dumpExportsTrie(gpa, data, segments.items[text_seg.?], writer);
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
return step.fail("no exports data found", .{});
|
||||
},
|
||||
|
||||
else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}),
|
||||
}
|
||||
|
||||
return output.toOwnedSlice();
|
||||
@ -971,7 +1111,7 @@ const MachODumper = struct {
|
||||
|
||||
for (symtab.symbols) |sym| {
|
||||
if (sym.stab()) continue;
|
||||
const sym_name = mem.sliceTo(@as([*:0]const u8, @ptrCast(symtab.strings.ptr + sym.n_strx)), 0);
|
||||
const sym_name = symtab.getString(sym.n_strx);
|
||||
if (sym.sect()) {
|
||||
const sect = sections[sym.n_sect - 1];
|
||||
try writer.print("{x} ({s},{s})", .{
|
||||
@ -1021,6 +1161,52 @@ const MachODumper = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn dumpIndirectSymtab(
|
||||
gpa: Allocator,
|
||||
sections: []const macho.section_64,
|
||||
symtab: Symtab,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
try writer.writeAll(indirect_symtab_label ++ "\n");
|
||||
|
||||
var sects = std.ArrayList(macho.section_64).init(gpa);
|
||||
defer sects.deinit();
|
||||
try sects.ensureUnusedCapacity(3);
|
||||
|
||||
for (sections) |sect| {
|
||||
if (mem.eql(u8, sect.sectName(), "__stubs")) sects.appendAssumeCapacity(sect);
|
||||
if (mem.eql(u8, sect.sectName(), "__got")) sects.appendAssumeCapacity(sect);
|
||||
if (mem.eql(u8, sect.sectName(), "__la_symbol_ptr")) sects.appendAssumeCapacity(sect);
|
||||
}
|
||||
|
||||
const sortFn = struct {
|
||||
fn sortFn(ctx: void, lhs: macho.section_64, rhs: macho.section_64) bool {
|
||||
_ = ctx;
|
||||
return lhs.reserved1 < rhs.reserved1;
|
||||
}
|
||||
}.sortFn;
|
||||
mem.sort(macho.section_64, sects.items, {}, sortFn);
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < sects.items.len) : (i += 1) {
|
||||
const sect = sects.items[i];
|
||||
const start = sect.reserved1;
|
||||
const end = if (i + 1 >= sects.items.len) symtab.indirect_symbols.len else sects.items[i + 1].reserved1;
|
||||
const entry_size = blk: {
|
||||
if (mem.eql(u8, sect.sectName(), "__stubs")) break :blk sect.reserved2;
|
||||
break :blk @sizeOf(u64);
|
||||
};
|
||||
|
||||
try writer.print("{s},{s}\n", .{ sect.segName(), sect.sectName() });
|
||||
try writer.print("nentries {d}\n", .{end - start});
|
||||
for (symtab.indirect_symbols[start..end], 0..) |index, j| {
|
||||
const sym = symtab.symbols[index];
|
||||
const addr = sect.addr + entry_size * j;
|
||||
try writer.print("0x{x} {d} {s}\n", .{ addr, index, symtab.getString(sym.n_strx) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dumpRebaseInfo(
|
||||
gpa: Allocator,
|
||||
data: []const u8,
|
||||
@ -1443,15 +1629,15 @@ const ElfDumper = struct {
|
||||
const dynamic_section_label = "dynamic section";
|
||||
const archive_symtab_label = "archive symbol table";
|
||||
|
||||
fn parseAndDump(step: *Step, bytes: []const u8) ![]const u8 {
|
||||
const gpa = step.owner.allocator;
|
||||
return parseAndDumpArchive(gpa, bytes) catch |err| switch (err) {
|
||||
error.InvalidArchiveMagicNumber => try parseAndDumpObject(gpa, bytes),
|
||||
fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
|
||||
return parseAndDumpArchive(step, kind, bytes) catch |err| switch (err) {
|
||||
error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, kind, bytes),
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
fn parseAndDumpArchive(gpa: Allocator, bytes: []const u8) ![]const u8 {
|
||||
fn parseAndDumpArchive(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
|
||||
const gpa = step.owner.allocator;
|
||||
var stream = std.io.fixedBufferStream(bytes);
|
||||
const reader = stream.reader();
|
||||
|
||||
@ -1512,8 +1698,15 @@ const ElfDumper = struct {
|
||||
var output = std.ArrayList(u8).init(gpa);
|
||||
const writer = output.writer();
|
||||
|
||||
try ctx.dumpSymtab(writer);
|
||||
try ctx.dumpObjects(writer);
|
||||
switch (kind) {
|
||||
.archive_symtab => if (ctx.symtab.items.len > 0) {
|
||||
try ctx.dumpSymtab(writer);
|
||||
} else return step.fail("no archive symbol table found", .{}),
|
||||
|
||||
else => if (ctx.objects.items.len > 0) {
|
||||
try ctx.dumpObjects(step, kind, writer);
|
||||
} else return step.fail("empty archive", .{}),
|
||||
}
|
||||
|
||||
return output.toOwnedSlice();
|
||||
}
|
||||
@ -1555,8 +1748,6 @@ const ElfDumper = struct {
|
||||
}
|
||||
|
||||
fn dumpSymtab(ctx: ArchiveContext, writer: anytype) !void {
|
||||
if (ctx.symtab.items.len == 0) return;
|
||||
|
||||
var files = std.AutoHashMap(usize, []const u8).init(ctx.gpa);
|
||||
defer files.deinit();
|
||||
try files.ensureUnusedCapacity(@intCast(ctx.objects.items.len));
|
||||
@ -1590,10 +1781,10 @@ const ElfDumper = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn dumpObjects(ctx: ArchiveContext, writer: anytype) !void {
|
||||
fn dumpObjects(ctx: ArchiveContext, step: *Step, kind: Check.Kind, writer: anytype) !void {
|
||||
for (ctx.objects.items) |object| {
|
||||
try writer.print("object {s}\n", .{object.name});
|
||||
const output = try parseAndDumpObject(ctx.gpa, ctx.data[object.off..][0..object.len]);
|
||||
const output = try parseAndDumpObject(step, kind, ctx.data[object.off..][0..object.len]);
|
||||
defer ctx.gpa.free(output);
|
||||
try writer.print("{s}\n", .{output});
|
||||
}
|
||||
@ -1611,7 +1802,8 @@ const ElfDumper = struct {
|
||||
};
|
||||
};
|
||||
|
||||
fn parseAndDumpObject(gpa: Allocator, bytes: []const u8) ![]const u8 {
|
||||
fn parseAndDumpObject(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
|
||||
const gpa = step.owner.allocator;
|
||||
var stream = std.io.fixedBufferStream(bytes);
|
||||
const reader = stream.reader();
|
||||
|
||||
@ -1663,12 +1855,27 @@ const ElfDumper = struct {
|
||||
var output = std.ArrayList(u8).init(gpa);
|
||||
const writer = output.writer();
|
||||
|
||||
try ctx.dumpHeader(writer);
|
||||
try ctx.dumpShdrs(writer);
|
||||
try ctx.dumpPhdrs(writer);
|
||||
try ctx.dumpDynamicSection(writer);
|
||||
try ctx.dumpSymtab(.symtab, writer);
|
||||
try ctx.dumpSymtab(.dysymtab, writer);
|
||||
switch (kind) {
|
||||
.headers => {
|
||||
try ctx.dumpHeader(writer);
|
||||
try ctx.dumpShdrs(writer);
|
||||
try ctx.dumpPhdrs(writer);
|
||||
},
|
||||
|
||||
.symtab => if (ctx.symtab.symbols.len > 0) {
|
||||
try ctx.dumpSymtab(.symtab, writer);
|
||||
} else return step.fail("no symbol table found", .{}),
|
||||
|
||||
.dynamic_symtab => if (ctx.dysymtab.symbols.len > 0) {
|
||||
try ctx.dumpSymtab(.dysymtab, writer);
|
||||
} else return step.fail("no dynamic symbol table found", .{}),
|
||||
|
||||
.dynamic_section => if (ctx.getSectionByName(".dynamic")) |shndx| {
|
||||
try ctx.dumpDynamicSection(shndx, writer);
|
||||
} else return step.fail("no .dynamic section found", .{}),
|
||||
|
||||
else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(kind)}),
|
||||
}
|
||||
|
||||
return output.toOwnedSlice();
|
||||
}
|
||||
@ -1680,8 +1887,8 @@ const ElfDumper = struct {
|
||||
shdrs: []align(1) const elf.Elf64_Shdr,
|
||||
phdrs: []align(1) const elf.Elf64_Phdr,
|
||||
shstrtab: []const u8,
|
||||
symtab: ?Symtab = null,
|
||||
dysymtab: ?Symtab = null,
|
||||
symtab: Symtab = .{},
|
||||
dysymtab: Symtab = .{},
|
||||
|
||||
fn dumpHeader(ctx: ObjectContext, writer: anytype) !void {
|
||||
try writer.writeAll("header\n");
|
||||
@ -1745,8 +1952,7 @@ const ElfDumper = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn dumpDynamicSection(ctx: ObjectContext, writer: anytype) !void {
|
||||
const shndx = ctx.getSectionByName(".dynamic") orelse return;
|
||||
fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void {
|
||||
const shdr = ctx.shdrs[shndx];
|
||||
const strtab = ctx.getSectionContents(shdr.sh_link);
|
||||
const data = ctx.getSectionContents(shndx);
|
||||
@ -1888,7 +2094,7 @@ const ElfDumper = struct {
|
||||
const symtab = switch (@"type") {
|
||||
.symtab => ctx.symtab,
|
||||
.dysymtab => ctx.dysymtab,
|
||||
} orelse return;
|
||||
};
|
||||
|
||||
try writer.writeAll(switch (@"type") {
|
||||
.symtab => symtab_label,
|
||||
@ -1986,8 +2192,8 @@ const ElfDumper = struct {
|
||||
};
|
||||
|
||||
const Symtab = struct {
|
||||
symbols: []align(1) const elf.Elf64_Sym,
|
||||
strings: []const u8,
|
||||
symbols: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
|
||||
strings: []const u8 = &[0]u8{},
|
||||
|
||||
fn get(st: Symtab, index: usize) ?elf.Elf64_Sym {
|
||||
if (index >= st.symbols.len) return null;
|
||||
@ -2090,7 +2296,7 @@ const ElfDumper = struct {
|
||||
const WasmDumper = struct {
|
||||
const symtab_label = "symbols";
|
||||
|
||||
fn parseAndDump(step: *Step, bytes: []const u8) ![]const u8 {
|
||||
fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
|
||||
const gpa = step.owner.allocator;
|
||||
var fbs = std.io.fixedBufferStream(bytes);
|
||||
const reader = fbs.reader();
|
||||
@ -2107,15 +2313,21 @@ const WasmDumper = struct {
|
||||
errdefer output.deinit();
|
||||
const writer = output.writer();
|
||||
|
||||
while (reader.readByte()) |current_byte| {
|
||||
const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
|
||||
return step.fail("Found invalid section id '{d}'", .{current_byte});
|
||||
};
|
||||
switch (kind) {
|
||||
.headers => {
|
||||
while (reader.readByte()) |current_byte| {
|
||||
const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
|
||||
return step.fail("Found invalid section id '{d}'", .{current_byte});
|
||||
};
|
||||
|
||||
const section_length = try std.leb.readULEB128(u32, reader);
|
||||
try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], writer);
|
||||
fbs.pos += section_length;
|
||||
} else |_| {} // reached end of stream
|
||||
const section_length = try std.leb.readULEB128(u32, reader);
|
||||
try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], writer);
|
||||
fbs.pos += section_length;
|
||||
} else |_| {} // reached end of stream
|
||||
},
|
||||
|
||||
else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(kind)}),
|
||||
}
|
||||
|
||||
return output.toOwnedSlice();
|
||||
}
|
||||
|
||||
@ -506,7 +506,7 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .copyrel");
|
||||
check.checkExact("addralign 20");
|
||||
@ -525,7 +525,7 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .copyrel");
|
||||
check.checkExact("addralign 8");
|
||||
@ -544,7 +544,7 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .copyrel");
|
||||
check.checkExact("addralign 100");
|
||||
@ -815,7 +815,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
|
||||
exe.entry = .{ .symbol_name = "foo" };
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("entry 1000");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -831,7 +831,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
|
||||
exe.entry = .{ .symbol_name = "bar" };
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("entry 2000");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -1460,13 +1460,13 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type DYN");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .dynamic");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .interp");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -1494,7 +1494,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExtract("entry {addr}");
|
||||
check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0x8000000 } });
|
||||
@ -1507,7 +1507,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
|
||||
exe.image_base = 0xffffffff8000000;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExtract("entry {addr}");
|
||||
check.checkComputeCompare("addr", .{ .op = .gte, .value = .{ .literal = 0xffffffff8000000 } });
|
||||
@ -1937,10 +1937,10 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type EXEC");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .dynamic");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -1967,10 +1967,10 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type EXEC");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .dynamic");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -2055,10 +2055,10 @@ fn testLinkingZig(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type EXEC");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .dynamic");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -2075,7 +2075,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
|
||||
exe.linkLibC();
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .eh_frame_hdr");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -2103,10 +2103,10 @@ fn testPie(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type DYN");
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .dynamic");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -2326,13 +2326,13 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
|
||||
obj2.addObject(obj1);
|
||||
|
||||
const check1 = obj1.checkObject();
|
||||
check1.checkStart();
|
||||
check1.checkInHeaders();
|
||||
check1.checkExact("section headers");
|
||||
check1.checkNotPresent(".eh_frame");
|
||||
test_step.dependOn(&check1.step);
|
||||
|
||||
const check2 = obj2.checkObject();
|
||||
check2.checkStart();
|
||||
check2.checkInHeaders();
|
||||
check2.checkExact("section headers");
|
||||
check2.checkNotPresent(".eh_frame");
|
||||
test_step.dependOn(&check2.step);
|
||||
@ -2369,7 +2369,7 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("header");
|
||||
check.checkExact("type DYN");
|
||||
// TODO fix/improve in CheckObject
|
||||
@ -2390,7 +2390,7 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
|
||||
// test_step.dependOn(&run.step);
|
||||
|
||||
// const check = exe.checkObject();
|
||||
// check.checkStart();
|
||||
// check.checkInHeaders();
|
||||
// check.checkExact("header");
|
||||
// check.checkExact("type EXEC");
|
||||
// // TODO fix/improve in CheckObject
|
||||
@ -2422,7 +2422,7 @@ fn testStrip(b: *Build, opts: Options) *Step {
|
||||
exe.linkLibC();
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkExact("name .debug_info");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -2435,7 +2435,7 @@ fn testStrip(b: *Build, opts: Options) *Step {
|
||||
exe.linkLibC();
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("section headers");
|
||||
check.checkNotPresent("name .debug_info");
|
||||
test_step.dependOn(&check.step);
|
||||
@ -3521,7 +3521,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
|
||||
exe.linkLibC();
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("program headers");
|
||||
check.checkExact("type GNU_STACK");
|
||||
check.checkExact("memsz 800000");
|
||||
|
||||
@ -19,11 +19,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
const exe = createScenario(b, optimize, "no-dead-strip");
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_DYLIB");
|
||||
check.checkContains("Cocoa");
|
||||
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_DYLIB");
|
||||
check.checkContains("libobjc");
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
dylib.linkLibC();
|
||||
|
||||
const check_dylib = dylib.checkObject();
|
||||
check_dylib.checkStart();
|
||||
check_dylib.checkInHeaders();
|
||||
check_dylib.checkExact("cmd ID_DYLIB");
|
||||
check_dylib.checkExact("name @rpath/liba.dylib");
|
||||
check_dylib.checkExact("timestamp 2");
|
||||
@ -46,14 +46,14 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.linkLibC();
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd LOAD_DYLIB");
|
||||
check_exe.checkExact("name @rpath/liba.dylib");
|
||||
check_exe.checkExact("timestamp 2");
|
||||
check_exe.checkExact("current version 10000");
|
||||
check_exe.checkExact("compatibility version 10000");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd RPATH");
|
||||
check_exe.checkExactPath("path", dylib.getOutputDirectorySource());
|
||||
test_step.dependOn(&check_exe.step);
|
||||
|
||||
@ -24,11 +24,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("segname __TEXT");
|
||||
check_exe.checkExtract("vmaddr {vmaddr}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd MAIN");
|
||||
check_exe.checkExtract("entryoff {entryoff}");
|
||||
|
||||
|
||||
@ -34,15 +34,15 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.forceUndefinedSymbol("_my_main");
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("segname __TEXT");
|
||||
check_exe.checkExtract("vmaddr {text_vmaddr}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("sectname __stubs");
|
||||
check_exe.checkExtract("addr {stubs_vmaddr}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd MAIN");
|
||||
check_exe.checkExtract("entryoff {entryoff}");
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.headerpad_max_install_names = true;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("sectname __text");
|
||||
check.checkExtract("offset {offset}");
|
||||
|
||||
@ -47,7 +47,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.headerpad_size = 0x10000;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("sectname __text");
|
||||
check.checkExtract("offset {offset}");
|
||||
check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
|
||||
@ -65,7 +65,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.headerpad_size = 0x10000;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("sectname __text");
|
||||
check.checkExtract("offset {offset}");
|
||||
check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
|
||||
@ -83,7 +83,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.headerpad_max_install_names = true;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("sectname __text");
|
||||
check.checkExtract("offset {offset}");
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.dead_strip_dylibs = true;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_DYLIB");
|
||||
check.checkContains("Cocoa");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
@ -39,7 +39,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.dead_strip_dylibs = true;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_DYLIB");
|
||||
check.checkExact("name @rpath/liba.dylib");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
@ -20,13 +20,13 @@ pub fn build(b: *std.Build) void {
|
||||
exe.pagezero_size = 0x4000;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("LC 0");
|
||||
check.checkExact("segname __PAGEZERO");
|
||||
check.checkExact("vmaddr 0");
|
||||
check.checkExact("vmsize 4000");
|
||||
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("segname __TEXT");
|
||||
check.checkExact("vmaddr 4000");
|
||||
|
||||
@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void {
|
||||
exe.pagezero_size = 0;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("LC 0");
|
||||
check.checkExact("segname __TEXT");
|
||||
check.checkExact("vmaddr 0");
|
||||
|
||||
@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
const exe = createScenario(b, optimize, target, "search_dylibs_first", .mode_first);
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_DYLIB");
|
||||
check.checkExact("name @rpath/libsearch_dylibs_first.dylib");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.stack_size = 0x100000000;
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd MAIN");
|
||||
check_exe.checkExact("stacksize 100000000");
|
||||
test_step.dependOn(&check_exe.step);
|
||||
|
||||
@ -26,13 +26,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd SEGMENT_64");
|
||||
check_exe.checkExact("segname __LINKEDIT");
|
||||
check_exe.checkExtract("fileoff {fileoff}");
|
||||
check_exe.checkExtract("filesz {filesz}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd DYLD_INFO_ONLY");
|
||||
check_exe.checkExtract("rebaseoff {rebaseoff}");
|
||||
check_exe.checkExtract("rebasesize {rebasesize}");
|
||||
@ -43,31 +43,31 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
check_exe.checkExtract("exportoff {exportoff}");
|
||||
check_exe.checkExtract("exportsize {exportsize}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd FUNCTION_STARTS");
|
||||
check_exe.checkExtract("dataoff {fstartoff}");
|
||||
check_exe.checkExtract("datasize {fstartsize}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd DATA_IN_CODE");
|
||||
check_exe.checkExtract("dataoff {diceoff}");
|
||||
check_exe.checkExtract("datasize {dicesize}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd SYMTAB");
|
||||
check_exe.checkExtract("symoff {symoff}");
|
||||
check_exe.checkExtract("nsyms {symnsyms}");
|
||||
check_exe.checkExtract("stroff {stroff}");
|
||||
check_exe.checkExtract("strsize {strsize}");
|
||||
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd DYSYMTAB");
|
||||
check_exe.checkExtract("indirectsymoff {dysymoff}");
|
||||
check_exe.checkExtract("nindirectsyms {dysymnsyms}");
|
||||
|
||||
switch (builtin.cpu.arch) {
|
||||
.aarch64 => {
|
||||
check_exe.checkStart();
|
||||
check_exe.checkInHeaders();
|
||||
check_exe.checkExact("cmd CODE_SIGNATURE");
|
||||
check_exe.checkExtract("dataoff {codesigoff}");
|
||||
check_exe.checkExtract("datasize {codesigsize}");
|
||||
|
||||
@ -32,7 +32,7 @@ fn testUnwindInfo(
|
||||
exe.link_gc_sections = dead_strip;
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("segname __TEXT");
|
||||
check.checkExact("sectname __gcc_except_tab");
|
||||
check.checkExact("sectname __unwind_info");
|
||||
|
||||
@ -23,7 +23,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.linkFrameworkWeak("Cocoa");
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_WEAK_DYLIB");
|
||||
check.checkContains("Cocoa");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
@ -37,7 +37,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.addRPath(dylib.getEmittedBinDirectory());
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd LOAD_WEAK_DYLIB");
|
||||
check.checkExact("name @rpath/liba.dylib");
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
lib.strip = false;
|
||||
|
||||
const check = lib.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("Section custom");
|
||||
check.checkExact("name __trunch"); // Ensure it was imported and resolved
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
// Verify the result contains the features explicitly set on the target for the library.
|
||||
const check = lib.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("name target_features");
|
||||
check.checkExact("features 1");
|
||||
check.checkExact("+ atomics");
|
||||
|
||||
@ -31,18 +31,18 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
|
||||
const check_lib = lib.checkObject();
|
||||
|
||||
// since we import memory, make sure it exists with the correct naming
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section import");
|
||||
check_lib.checkExact("entries 1");
|
||||
check_lib.checkExact("module env"); // default module name is "env"
|
||||
check_lib.checkExact("name memory"); // as per linker specification
|
||||
|
||||
// since we are importing memory, ensure it's not exported
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkNotPresent("Section export");
|
||||
|
||||
// validate the name of the stack pointer
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section custom");
|
||||
check_lib.checkExact("type data_segment");
|
||||
check_lib.checkExact("names 2");
|
||||
@ -77,7 +77,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
|
||||
lib.link_gc_sections = false;
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section custom");
|
||||
check_lib.checkExact("type data_segment");
|
||||
check_lib.checkExact("names 2");
|
||||
|
||||
@ -22,7 +22,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section global");
|
||||
check_lib.checkExact("entries 3");
|
||||
check_lib.checkExact("type i32"); // stack pointer so skip other fields
|
||||
@ -35,7 +35,7 @@ pub fn build(b: *std.Build) void {
|
||||
check_lib.checkComputeCompare("foo_address", .{ .op = .eq, .value = .{ .literal = 4 } });
|
||||
check_lib.checkComputeCompare("bar_address", .{ .op = .eq, .value = .{ .literal = 0 } });
|
||||
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section export");
|
||||
check_lib.checkExact("entries 3");
|
||||
check_lib.checkExact("name foo");
|
||||
|
||||
@ -46,21 +46,21 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
force_export.use_lld = false;
|
||||
|
||||
const check_no_export = no_export.checkObject();
|
||||
check_no_export.checkStart();
|
||||
check_no_export.checkInHeaders();
|
||||
check_no_export.checkExact("Section export");
|
||||
check_no_export.checkExact("entries 1");
|
||||
check_no_export.checkExact("name memory");
|
||||
check_no_export.checkExact("kind memory");
|
||||
|
||||
const check_dynamic_export = dynamic_export.checkObject();
|
||||
check_dynamic_export.checkStart();
|
||||
check_dynamic_export.checkInHeaders();
|
||||
check_dynamic_export.checkExact("Section export");
|
||||
check_dynamic_export.checkExact("entries 2");
|
||||
check_dynamic_export.checkExact("name foo");
|
||||
check_dynamic_export.checkExact("kind function");
|
||||
|
||||
const check_force_export = force_export.checkObject();
|
||||
check_force_export.checkStart();
|
||||
check_force_export.checkInHeaders();
|
||||
check_force_export.checkExact("Section export");
|
||||
check_force_export.checkExact("entries 2");
|
||||
check_force_export.checkExact("name foo");
|
||||
|
||||
@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
lib.rdynamic = true; // export `foo`
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section import");
|
||||
check_lib.checkExact("entries 2"); // a.hello & b.hello
|
||||
check_lib.checkExact("module a");
|
||||
|
||||
@ -52,7 +52,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
const check_export = export_table.checkObject();
|
||||
const check_regular = regular_table.checkObject();
|
||||
|
||||
check_import.checkStart();
|
||||
check_import.checkInHeaders();
|
||||
check_import.checkExact("Section import");
|
||||
check_import.checkExact("entries 1");
|
||||
check_import.checkExact("module env");
|
||||
@ -63,20 +63,20 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
check_import.checkNotPresent("max"); // when importing, we do not provide a max
|
||||
check_import.checkNotPresent("Section table"); // we're importing it
|
||||
|
||||
check_export.checkStart();
|
||||
check_export.checkInHeaders();
|
||||
check_export.checkExact("Section export");
|
||||
check_export.checkExact("entries 2");
|
||||
check_export.checkExact("name __indirect_function_table"); // as per linker specification
|
||||
check_export.checkExact("kind table");
|
||||
|
||||
check_regular.checkStart();
|
||||
check_regular.checkInHeaders();
|
||||
check_regular.checkExact("Section table");
|
||||
check_regular.checkExact("entries 1");
|
||||
check_regular.checkExact("type funcref");
|
||||
check_regular.checkExact("min 2"); // index starts at 1 & 1 function pointer = 2.
|
||||
check_regular.checkExact("max 2");
|
||||
|
||||
check_regular.checkStart();
|
||||
check_regular.checkInHeaders();
|
||||
check_regular.checkExact("Section element");
|
||||
check_regular.checkExact("entries 1");
|
||||
check_regular.checkExact("table index 0");
|
||||
|
||||
@ -34,7 +34,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
// Verify the result contains the features from the C Object file.
|
||||
const check = lib.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("name target_features");
|
||||
check.checkExact("features 7");
|
||||
check.checkExact("+ atomics");
|
||||
|
||||
@ -29,7 +29,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
const version_fmt = "version " ++ builtin.zig_version_string;
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("name producers");
|
||||
check_lib.checkExact("fields 2");
|
||||
check_lib.checkExact("field_name language");
|
||||
|
||||
@ -27,15 +27,15 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
b.installArtifact(lib);
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section data");
|
||||
check_lib.checkExact("entries 2"); // rodata & data, no bss because we're exporting memory
|
||||
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section custom");
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("name name"); // names custom section
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("type data_segment");
|
||||
check_lib.checkExact("names 2");
|
||||
check_lib.checkExact("index 0");
|
||||
|
||||
@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
const check_lib = lib.checkObject();
|
||||
|
||||
// ensure global exists and its initial value is equal to explitic stack size
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section global");
|
||||
check_lib.checkExact("entries 1");
|
||||
check_lib.checkExact("type i32"); // on wasm32 the stack pointer must be i32
|
||||
@ -39,13 +39,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
check_lib.checkComputeCompare("stack_pointer", .{ .op = .eq, .value = .{ .literal = lib.stack_size.? } });
|
||||
|
||||
// validate memory section starts after virtual stack
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section data");
|
||||
check_lib.checkExtract("i32.const {data_start}");
|
||||
check_lib.checkComputeCompare("data_start", .{ .op = .eq, .value = .{ .variable = "stack_pointer" } });
|
||||
|
||||
// validate the name of the stack pointer
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section custom");
|
||||
check_lib.checkExact("type global");
|
||||
check_lib.checkExact("names 1");
|
||||
|
||||
@ -26,7 +26,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
b.installArtifact(lib);
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
check_lib.checkStart();
|
||||
check_lib.checkInHeaders();
|
||||
check_lib.checkExact("Section type");
|
||||
// only 2 entries, although we have more functions.
|
||||
// This is to test functions with the same function signature
|
||||
|
||||
@ -30,7 +30,7 @@ pub fn build(b: *std.Build) void {
|
||||
exe.linkLibC();
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
check.checkInHeaders();
|
||||
check.checkExact("cmd BUILD_VERSION");
|
||||
check.checkExact("platform IOS");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user