From 2492488501ee04e132cb552fd11a3025990ea047 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 13 Dec 2023 11:22:46 +0100 Subject: lib/std/Build/CheckObject: introduce scoped checks; implement for MachO --- lib/std/Build/Step/CheckObject.zig | 356 ++++++++++++++++++++++++------------- 1 file changed, 234 insertions(+), 122 deletions(-) (limited to 'lib/std/Build/Step/CheckObject.zig') diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index e1597d601b..7195b92635 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -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,26 @@ const Check = struct { .expected = expected, }) catch @panic("OOM"); } + + const Kind = enum { + headers, + symtab, + indirect_symtab, + dynamic_symtab, + archive_symtab, + dynamic_section, + dyld_info, + 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 +327,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 +344,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 +361,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 +379,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,7 +394,7 @@ 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); } @@ -389,7 +406,19 @@ pub fn checkInDyldInfo(self: *CheckObject) void { .macho => MachODumper.dyld_info_label, else => @panic("Unsupported target platform"), }; - self.checkStart(); + self.checkStart(.dyld_info); + 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 +430,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 +442,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 +453,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 +465,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 +486,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 +532,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 +547,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 +561,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 +576,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, } } } @@ -557,13 +587,20 @@ const MachODumper = struct { const LoadCommandIterator = macho.LoadCommandIterator; const dyld_info_label = "dyld info 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 +613,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 +623,109 @@ 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'); + switch (kind) { + .headers => { + try dumpHeader(hdr, writer); - i += 1; - } + 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'); - if (symtab) |stab| { - try dumpSymtab(sections.items, imports.items, stab, writer); - } + i += 1; + } + }, - 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); - } + .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_info => 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); + } + } else return step.fail("no dyld info found", .{}), + + else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}), } return output.toOwnedSlice(); @@ -971,7 +1035,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 +1085,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,7 +1553,8 @@ 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 { + fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { + _ = kind; const gpa = step.owner.allocator; return parseAndDumpArchive(gpa, bytes) catch |err| switch (err) { error.InvalidArchiveMagicNumber => try parseAndDumpObject(gpa, bytes), @@ -2090,7 +2201,8 @@ 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 { + _ = kind; const gpa = step.owner.allocator; var fbs = std.io.fixedBufferStream(bytes); const reader = fbs.reader(); -- cgit v1.2.3 From 92cca7fbf155602584dee294d04ee0b33135a25e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 13 Dec 2023 11:38:57 +0100 Subject: lib/std/Build/CheckObject: implement for ELF --- lib/std/Build/Step/CheckObject.zig | 67 ++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'lib/std/Build/Step/CheckObject.zig') diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 7195b92635..f837f509dd 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -1554,15 +1554,14 @@ const ElfDumper = struct { const archive_symtab_label = "archive symbol table"; fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { - _ = kind; - const gpa = step.owner.allocator; - return parseAndDumpArchive(gpa, bytes) catch |err| switch (err) { - error.InvalidArchiveMagicNumber => try parseAndDumpObject(gpa, bytes), + 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(); @@ -1623,8 +1622,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(); } @@ -1666,8 +1672,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)); @@ -1701,10 +1705,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}); } @@ -1722,7 +1726,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(); @@ -1774,12 +1779,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(); } @@ -1791,8 +1811,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"); @@ -1856,8 +1876,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); @@ -2097,8 +2116,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; -- cgit v1.2.3 From c4519d6bbae661b2e569b9b86887020a3013414e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 13 Dec 2023 11:41:51 +0100 Subject: lib/std/Build/CheckObject: implement for Wasm --- lib/std/Build/Step/CheckObject.zig | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'lib/std/Build/Step/CheckObject.zig') diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index f837f509dd..b8f7dee6cc 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -2221,7 +2221,6 @@ const WasmDumper = struct { const symtab_label = "symbols"; fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { - _ = kind; const gpa = step.owner.allocator; var fbs = std.io.fixedBufferStream(bytes); const reader = fbs.reader(); @@ -2238,15 +2237,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(); } -- cgit v1.2.3 From f26459e59429c85f89c1d5db5817e64b74b0b4ee Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 13 Dec 2023 12:06:25 +0100 Subject: lib/std/Build/CheckObject: update all tests to new API --- lib/std/Build/Step/CheckObject.zig | 2 +- test/link/elf.zig | 52 ++++++++++++++--------------- test/link/macho/dead_strip_dylibs/build.zig | 4 +-- test/link/macho/dylib/build.zig | 6 ++-- test/link/macho/entry/build.zig | 4 +-- test/link/macho/entry_in_dylib/build.zig | 6 ++-- test/link/macho/headerpad/build.zig | 8 ++--- test/link/macho/needed_framework/build.zig | 2 +- test/link/macho/needed_library/build.zig | 2 +- test/link/macho/pagezero/build.zig | 6 ++-- test/link/macho/search_strategy/build.zig | 2 +- test/link/macho/stack_size/build.zig | 2 +- test/link/macho/strict_validation/build.zig | 14 ++++---- test/link/macho/unwind_info/build.zig | 2 +- test/link/macho/weak_framework/build.zig | 2 +- test/link/macho/weak_library/build.zig | 2 +- test/link/wasm/archive/build.zig | 2 +- test/link/wasm/basic-features/build.zig | 2 +- test/link/wasm/bss/build.zig | 8 ++--- test/link/wasm/export-data/build.zig | 4 +-- test/link/wasm/export/build.zig | 6 ++-- test/link/wasm/extern-mangle/build.zig | 2 +- test/link/wasm/function-table/build.zig | 8 ++--- test/link/wasm/infer-features/build.zig | 2 +- test/link/wasm/producers/build.zig | 2 +- test/link/wasm/segments/build.zig | 8 ++--- test/link/wasm/stack_pointer/build.zig | 6 ++-- test/link/wasm/type/build.zig | 2 +- test/standalone/ios/build.zig | 2 +- 29 files changed, 85 insertions(+), 85 deletions(-) (limited to 'lib/std/Build/Step/CheckObject.zig') diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index b8f7dee6cc..b7ef490c38 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -2018,7 +2018,7 @@ const ElfDumper = struct { const symtab = switch (@"type") { .symtab => ctx.symtab, .dysymtab => ctx.dysymtab, - } orelse return; + }; try writer.writeAll(switch (@"type") { .symtab => symtab_label, diff --git a/test/link/elf.zig b/test/link/elf.zig index ba33a7eeec..4055ec9219 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -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"); diff --git a/test/link/macho/dead_strip_dylibs/build.zig b/test/link/macho/dead_strip_dylibs/build.zig index cf243b5231..52d7f2eac8 100644 --- a/test/link/macho/dead_strip_dylibs/build.zig +++ b/test/link/macho/dead_strip_dylibs/build.zig @@ -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"); diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig index b05e4f5677..beebfbdd02 100644 --- a/test/link/macho/dylib/build.zig +++ b/test/link/macho/dylib/build.zig @@ -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); diff --git a/test/link/macho/entry/build.zig b/test/link/macho/entry/build.zig index 9f493d2715..9675935a9c 100644 --- a/test/link/macho/entry/build.zig +++ b/test/link/macho/entry/build.zig @@ -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}"); diff --git a/test/link/macho/entry_in_dylib/build.zig b/test/link/macho/entry_in_dylib/build.zig index eb036abe6a..5b93541a5a 100644 --- a/test/link/macho/entry_in_dylib/build.zig +++ b/test/link/macho/entry_in_dylib/build.zig @@ -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}"); diff --git a/test/link/macho/headerpad/build.zig b/test/link/macho/headerpad/build.zig index e1aebb0a8f..3c0bb7c572 100644 --- a/test/link/macho/headerpad/build.zig +++ b/test/link/macho/headerpad/build.zig @@ -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}"); diff --git a/test/link/macho/needed_framework/build.zig b/test/link/macho/needed_framework/build.zig index f189ef7578..45c046fe0b 100644 --- a/test/link/macho/needed_framework/build.zig +++ b/test/link/macho/needed_framework/build.zig @@ -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); diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index de5d6b1ae6..cc9d2bd646 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -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); diff --git a/test/link/macho/pagezero/build.zig b/test/link/macho/pagezero/build.zig index 5a07138464..1ca7f28f11 100644 --- a/test/link/macho/pagezero/build.zig +++ b/test/link/macho/pagezero/build.zig @@ -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"); diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index b128fe71cf..b76de65b0e 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -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); diff --git a/test/link/macho/stack_size/build.zig b/test/link/macho/stack_size/build.zig index 4210d9802d..48496bd9d5 100644 --- a/test/link/macho/stack_size/build.zig +++ b/test/link/macho/stack_size/build.zig @@ -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); diff --git a/test/link/macho/strict_validation/build.zig b/test/link/macho/strict_validation/build.zig index cc2825a458..1cfaac4910 100644 --- a/test/link/macho/strict_validation/build.zig +++ b/test/link/macho/strict_validation/build.zig @@ -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}"); diff --git a/test/link/macho/unwind_info/build.zig b/test/link/macho/unwind_info/build.zig index fd0a80fb21..96c4a67568 100644 --- a/test/link/macho/unwind_info/build.zig +++ b/test/link/macho/unwind_info/build.zig @@ -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"); diff --git a/test/link/macho/weak_framework/build.zig b/test/link/macho/weak_framework/build.zig index 8a71584b25..dfb41b7457 100644 --- a/test/link/macho/weak_framework/build.zig +++ b/test/link/macho/weak_framework/build.zig @@ -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); diff --git a/test/link/macho/weak_library/build.zig b/test/link/macho/weak_library/build.zig index 14ee74a75f..7ae7c7c2d6 100644 --- a/test/link/macho/weak_library/build.zig +++ b/test/link/macho/weak_library/build.zig @@ -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"); diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig index 3da284ac8f..95aea2913e 100644 --- a/test/link/wasm/archive/build.zig +++ b/test/link/wasm/archive/build.zig @@ -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 diff --git a/test/link/wasm/basic-features/build.zig b/test/link/wasm/basic-features/build.zig index 0566fbe2c1..9cf28ea31e 100644 --- a/test/link/wasm/basic-features/build.zig +++ b/test/link/wasm/basic-features/build.zig @@ -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"); diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index faf8202cd9..c569225f8b 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -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"); diff --git a/test/link/wasm/export-data/build.zig b/test/link/wasm/export-data/build.zig index 58a8795390..f1bba98d5f 100644 --- a/test/link/wasm/export-data/build.zig +++ b/test/link/wasm/export-data/build.zig @@ -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"); diff --git a/test/link/wasm/export/build.zig b/test/link/wasm/export/build.zig index 5c0306335d..2183ccd585 100644 --- a/test/link/wasm/export/build.zig +++ b/test/link/wasm/export/build.zig @@ -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"); diff --git a/test/link/wasm/extern-mangle/build.zig b/test/link/wasm/extern-mangle/build.zig index 9f450c2dcc..d361dc140e 100644 --- a/test/link/wasm/extern-mangle/build.zig +++ b/test/link/wasm/extern-mangle/build.zig @@ -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"); diff --git a/test/link/wasm/function-table/build.zig b/test/link/wasm/function-table/build.zig index acf7043476..5a139acb3e 100644 --- a/test/link/wasm/function-table/build.zig +++ b/test/link/wasm/function-table/build.zig @@ -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"); diff --git a/test/link/wasm/infer-features/build.zig b/test/link/wasm/infer-features/build.zig index 5c7fa57447..c883063dc5 100644 --- a/test/link/wasm/infer-features/build.zig +++ b/test/link/wasm/infer-features/build.zig @@ -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"); diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig index e2bd95f450..b66521a456 100644 --- a/test/link/wasm/producers/build.zig +++ b/test/link/wasm/producers/build.zig @@ -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"); diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig index 64d25d3fae..6ab2e4a7a3 100644 --- a/test/link/wasm/segments/build.zig +++ b/test/link/wasm/segments/build.zig @@ -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"); diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig index da54c140ca..93c0f10e14 100644 --- a/test/link/wasm/stack_pointer/build.zig +++ b/test/link/wasm/stack_pointer/build.zig @@ -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"); diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig index de574e36e4..88ded91403 100644 --- a/test/link/wasm/type/build.zig +++ b/test/link/wasm/type/build.zig @@ -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 diff --git a/test/standalone/ios/build.zig b/test/standalone/ios/build.zig index cd10af21cf..1816868844 100644 --- a/test/standalone/ios/build.zig +++ b/test/standalone/ios/build.zig @@ -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); -- cgit v1.2.3 From 5d12622469db5c53fe4857dfd95be033c16b4056 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 13 Dec 2023 13:53:05 +0100 Subject: lib/std/Build/CheckObject: split dyld info into subsections for easier scoped testing --- lib/std/Build/Step/CheckObject.zig | 140 ++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 32 deletions(-) (limited to 'lib/std/Build/Step/CheckObject.zig') diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index b7ef490c38..3be9cdc83c 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -299,7 +299,11 @@ const Check = struct { dynamic_symtab, archive_symtab, dynamic_section, - dyld_info, + dyld_rebase, + dyld_bind, + dyld_weak_bind, + dyld_lazy_bind, + exports, compute_compare, }; }; @@ -398,15 +402,63 @@ pub fn checkInSymtab(self: *CheckObject) void { 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(.dyld_info); + 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); } @@ -585,7 +637,11 @@ 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"; @@ -696,34 +752,54 @@ const MachODumper = struct { try dumpIndirectSymtab(gpa, sections.items, symtab, writer); } else return step.fail("no indirect symbol table found", .{}), - .dyld_info => 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); + .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, } - 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); + }, + + .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; + } } - } else return step.fail("no dyld info found", .{}), + return step.fail("no exports data found", .{}); + }, else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}), } -- cgit v1.2.3