authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-04-15 12:36:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-04-15 18:06:44+02:00
log1e5075f81296cccd469a0829259231cb34337a02
treeab9d2e63916b044def5314c6608f4ef69ba53b99
parentd483ba725028375cb1e290f5196daed2929e6c6c

lib/std/Build/Step/CheckObject: dump section as string


1 files changed, 93 insertions(+), 27 deletions(-)

lib/std/Build/Step/CheckObject.zig+93-27
......@@ -247,15 +247,27 @@ const ComputeCompareExpected = struct {
247247
248248const Check = struct {
249249 kind: Kind,
250 payload: Payload,
251 data: std.ArrayList(u8),
250252 actions: std.ArrayList(Action),
251253
252254 fn create(allocator: Allocator, kind: Kind) Check {
253255 return .{
254256 .kind = kind,
257 .payload = .{ .none = {} },
258 .data = std.ArrayList(u8).init(allocator),
255259 .actions = std.ArrayList(Action).init(allocator),
256260 };
257261 }
258262
263 fn dumpSection(allocator: Allocator, name: [:0]const u8) Check {
264 var check = Check.create(allocator, .dump_section);
265 const off: u32 = @intCast(check.data.items.len);
266 check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM");
267 check.payload = .{ .dump_section = off };
268 return check;
269 }
270
259271 fn extract(self: *Check, phrase: SearchPhrase) void {
260272 self.actions.append(.{
261273 .tag = .extract,
......@@ -305,6 +317,13 @@ const Check = struct {
305317 dyld_lazy_bind,
306318 exports,
307319 compute_compare,
320 dump_section,
321 };
322
323 const Payload = union {
324 none: void,
325 /// Null-delimited string in the 'data' buffer.
326 dump_section: u32,
308327 };
309328};
310329
......@@ -513,6 +532,11 @@ pub fn checkInArchiveSymtab(self: *CheckObject) void {
513532 self.checkExact(label);
514533}
515534
535pub fn dumpSection(self: *CheckObject, name: [:0]const u8) void {
536 const new_check = Check.dumpSection(self.step.owner.allocator, name);
537 self.checks.append(new_check) catch @panic("OOM");
538}
539
516540/// Creates a new standalone, singular check which allows running simple binary operations
517541/// on the extracted variables. It will then compare the reduced program with the value of
518542/// the expected variable.
......@@ -564,13 +588,44 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
564588 }
565589
566590 const output = switch (self.obj_format) {
567 .macho => try MachODumper.parseAndDump(step, chk.kind, contents),
568 .elf => try ElfDumper.parseAndDump(step, chk.kind, contents),
591 .macho => try MachODumper.parseAndDump(step, chk, contents),
592 .elf => try ElfDumper.parseAndDump(step, chk, contents),
569593 .coff => return step.fail("TODO coff parser", .{}),
570 .wasm => try WasmDumper.parseAndDump(step, chk.kind, contents),
594 .wasm => try WasmDumper.parseAndDump(step, chk, contents),
571595 else => unreachable,
572596 };
573597
598 // Depending on whether we requested dumping section verbatim or not,
599 // we either format message string with escaped codes, or not to aid debugging
600 // the failed test.
601 const fmtMessageString = struct {
602 fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(formatMessageString) {
603 return .{ .data = .{
604 .kind = kind,
605 .msg = msg,
606 } };
607 }
608
609 const Ctx = struct {
610 kind: Check.Kind,
611 msg: []const u8,
612 };
613
614 fn formatMessageString(
615 ctx: Ctx,
616 comptime unused_fmt_string: []const u8,
617 options: std.fmt.FormatOptions,
618 writer: anytype,
619 ) !void {
620 _ = unused_fmt_string;
621 _ = options;
622 switch (ctx.kind) {
623 .dump_section => try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ctx.msg)}),
624 else => try writer.writeAll(ctx.msg),
625 }
626 }
627 }.fmtMessageString;
628
574629 var it = mem.tokenizeAny(u8, output, "\r\n");
575630 for (chk.actions.items) |act| {
576631 switch (act.tag) {
......@@ -585,7 +640,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
585640 \\========= but parsed file does not contain it: =======
586641 \\{s}
587642 \\======================================================
588 , .{ act.phrase.resolve(b, step), output });
643 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
589644 }
590645 },
591646
......@@ -600,7 +655,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
600655 \\========= but parsed file does not contain it: =======
601656 \\{s}
602657 \\======================================================
603 , .{ act.phrase.resolve(b, step), output });
658 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
604659 }
605660 },
606661
......@@ -614,7 +669,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
614669 \\========= but parsed file does contain it: ========
615670 \\{s}
616671 \\===================================================
617 , .{ act.phrase.resolve(b, step), output });
672 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
618673 }
619674 },
620675
......@@ -629,7 +684,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
629684 \\========= but parsed file does not contain it: =======
630685 \\{s}
631686 \\======================================================
632 , .{ act.phrase.resolve(b, step), output });
687 , .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) });
633688 }
634689 },
635690
......@@ -660,7 +715,7 @@ const MachODumper = struct {
660715 }
661716 };
662717
663 fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
718 fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
664719 const gpa = step.owner.allocator;
665720 var stream = std.io.fixedBufferStream(bytes);
666721 const reader = stream.reader();
......@@ -731,7 +786,7 @@ const MachODumper = struct {
731786 }
732787 }
733788
734 switch (kind) {
789 switch (check.kind) {
735790 .headers => {
736791 try dumpHeader(hdr, writer);
737792
......@@ -764,7 +819,7 @@ const MachODumper = struct {
764819 if (dyld_info_lc == null) return step.fail("no dyld info found", .{});
765820 const lc = dyld_info_lc.?;
766821
767 switch (kind) {
822 switch (check.kind) {
768823 .dyld_rebase => if (lc.rebase_size > 0) {
769824 const data = bytes[lc.rebase_off..][0..lc.rebase_size];
770825 try writer.writeAll(dyld_rebase_label ++ "\n");
......@@ -805,7 +860,7 @@ const MachODumper = struct {
805860 return step.fail("no exports data found", .{});
806861 },
807862
808 else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}),
863 else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(check.kind)}),
809864 }
810865
811866 return output.toOwnedSlice();
......@@ -1633,14 +1688,14 @@ const ElfDumper = struct {
16331688 const dynamic_section_label = "dynamic section";
16341689 const archive_symtab_label = "archive symbol table";
16351690
1636 fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
1637 return parseAndDumpArchive(step, kind, bytes) catch |err| switch (err) {
1638 error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, kind, bytes),
1691 fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
1692 return parseAndDumpArchive(step, check, bytes) catch |err| switch (err) {
1693 error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, check, bytes),
16391694 else => |e| return e,
16401695 };
16411696 }
16421697
1643 fn parseAndDumpArchive(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
1698 fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
16441699 const gpa = step.owner.allocator;
16451700 var stream = std.io.fixedBufferStream(bytes);
16461701 const reader = stream.reader();
......@@ -1702,13 +1757,13 @@ const ElfDumper = struct {
17021757 var output = std.ArrayList(u8).init(gpa);
17031758 const writer = output.writer();
17041759
1705 switch (kind) {
1760 switch (check.kind) {
17061761 .archive_symtab => if (ctx.symtab.items.len > 0) {
17071762 try ctx.dumpSymtab(writer);
17081763 } else return step.fail("no archive symbol table found", .{}),
17091764
17101765 else => if (ctx.objects.items.len > 0) {
1711 try ctx.dumpObjects(step, kind, writer);
1766 try ctx.dumpObjects(step, check, writer);
17121767 } else return step.fail("empty archive", .{}),
17131768 }
17141769
......@@ -1785,10 +1840,10 @@ const ElfDumper = struct {
17851840 }
17861841 }
17871842
1788 fn dumpObjects(ctx: ArchiveContext, step: *Step, kind: Check.Kind, writer: anytype) !void {
1843 fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, writer: anytype) !void {
17891844 for (ctx.objects.items) |object| {
17901845 try writer.print("object {s}\n", .{object.name});
1791 const output = try parseAndDumpObject(step, kind, ctx.data[object.off..][0..object.len]);
1846 const output = try parseAndDumpObject(step, check, ctx.data[object.off..][0..object.len]);
17921847 defer ctx.gpa.free(output);
17931848 try writer.print("{s}\n", .{output});
17941849 }
......@@ -1806,7 +1861,7 @@ const ElfDumper = struct {
18061861 };
18071862 };
18081863
1809 fn parseAndDumpObject(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
1864 fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
18101865 const gpa = step.owner.allocator;
18111866 var stream = std.io.fixedBufferStream(bytes);
18121867 const reader = stream.reader();
......@@ -1859,7 +1914,7 @@ const ElfDumper = struct {
18591914 var output = std.ArrayList(u8).init(gpa);
18601915 const writer = output.writer();
18611916
1862 switch (kind) {
1917 switch (check.kind) {
18631918 .headers => {
18641919 try ctx.dumpHeader(writer);
18651920 try ctx.dumpShdrs(writer);
......@@ -1878,7 +1933,13 @@ const ElfDumper = struct {
18781933 try ctx.dumpDynamicSection(shndx, writer);
18791934 } else return step.fail("no .dynamic section found", .{}),
18801935
1881 else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(kind)}),
1936 .dump_section => {
1937 const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0);
1938 const shndx = ctx.getSectionByName(name) orelse return step.fail("no '{s}' section found", .{name});
1939 try ctx.dumpSection(shndx, writer);
1940 },
1941
1942 else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(check.kind)}),
18821943 }
18831944
18841945 return output.toOwnedSlice();
......@@ -2176,6 +2237,11 @@ const ElfDumper = struct {
21762237 }
21772238 }
21782239
2240 fn dumpSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void {
2241 const data = ctx.getSectionContents(shndx);
2242 try writer.print("{s}", .{data});
2243 }
2244
21792245 inline fn getSectionName(ctx: ObjectContext, shndx: usize) []const u8 {
21802246 const shdr = ctx.shdrs[shndx];
21812247 return getString(ctx.shstrtab, shdr.sh_name);
......@@ -2300,7 +2366,7 @@ const ElfDumper = struct {
23002366const WasmDumper = struct {
23012367 const symtab_label = "symbols";
23022368
2303 fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 {
2369 fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
23042370 const gpa = step.owner.allocator;
23052371 var fbs = std.io.fixedBufferStream(bytes);
23062372 const reader = fbs.reader();
......@@ -2317,7 +2383,7 @@ const WasmDumper = struct {
23172383 errdefer output.deinit();
23182384 const writer = output.writer();
23192385
2320 switch (kind) {
2386 switch (check.kind) {
23212387 .headers => {
23222388 while (reader.readByte()) |current_byte| {
23232389 const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch {
......@@ -2330,7 +2396,7 @@ const WasmDumper = struct {
23302396 } else |_| {} // reached end of stream
23312397 },
23322398
2333 else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(kind)}),
2399 else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(check.kind)}),
23342400 }
23352401
23362402 return output.toOwnedSlice();
......@@ -2364,7 +2430,7 @@ const WasmDumper = struct {
23642430 => {
23652431 const entries = try std.leb.readULEB128(u32, reader);
23662432 try writer.print("\nentries {d}\n", .{entries});
2367 try dumpSection(step, section, data[fbs.pos..], entries, writer);
2433 try parseSection(step, section, data[fbs.pos..], entries, writer);
23682434 },
23692435 .custom => {
23702436 const name_length = try std.leb.readULEB128(u32, reader);
......@@ -2393,7 +2459,7 @@ const WasmDumper = struct {
23932459 }
23942460 }
23952461
2396 fn dumpSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void {
2462 fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void {
23972463 var fbs = std.io.fixedBufferStream(data);
23982464 const reader = fbs.reader();
23992465