authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-28 10:23:25+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-28 10:23:25+02:00
log5834a608fc629319772b1623a31b62dd49ac6d63
treeef3b895c679671c72a2d18e6cc5750e2b4d05fb3
parent075f5bc5ffdbe0a458a733d596a1fc4a74b8e1ab

link-tests: do not save global extracted var unless a match

Improve testing MachO binaries by verbose printing of the symtab which includes segment,section names for defined symbols, and import (dylib) name for imports.

3 files changed, 87 insertions(+), 7 deletions(-)

lib/std/build/CheckObjectStep.zig+81-6
...@@ -65,6 +65,7 @@ const Action = struct {...@@ -65,6 +65,7 @@ const Action = struct {
65 fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool {65 fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool {
66 assert(act.tag == .match);66 assert(act.tag == .match);
6767
68 var candidate_var: ?struct { name: []const u8, value: u64 } = null;
68 var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " ");69 var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " ");
69 var needle_it = mem.tokenize(u8, mem.trim(u8, act.phrase, " "), " ");70 var needle_it = mem.tokenize(u8, mem.trim(u8, act.phrase, " "), " ");
7071
...@@ -92,12 +93,19 @@ const Action = struct {...@@ -92,12 +93,19 @@ const Action = struct {
92 const name = needle_tok[1..closing_brace];93 const name = needle_tok[1..closing_brace];
93 if (name.len == 0) return error.MissingBraceValue;94 if (name.len == 0) return error.MissingBraceValue;
94 const value = try std.fmt.parseInt(u64, hay_tok, 16);95 const value = try std.fmt.parseInt(u64, hay_tok, 16);
95 try global_vars.putNoClobber(name, value);96 candidate_var = .{
97 .name = name,
98 .value = value,
99 };
96 } else {100 } else {
97 if (!mem.eql(u8, hay_tok, needle_tok)) return false;101 if (!mem.eql(u8, hay_tok, needle_tok)) return false;
98 }102 }
99 }103 }
100104
105 if (candidate_var) |v| {
106 try global_vars.putNoClobber(v.name, v.value);
107 }
108
101 return true;109 return true;
102 }110 }
103111
...@@ -332,20 +340,43 @@ const MachODumper = struct {...@@ -332,20 +340,43 @@ const MachODumper = struct {
332 var output = std.ArrayList(u8).init(gpa);340 var output = std.ArrayList(u8).init(gpa);
333 const writer = output.writer();341 const writer = output.writer();
334342
335 var symtab_cmd: ?macho.symtab_command = null;343 var load_commands = std.ArrayList(macho.LoadCommand).init(gpa);
344 try load_commands.ensureTotalCapacity(hdr.ncmds);
345
346 var sections = std.ArrayList(struct { seg: u16, sect: u16 }).init(gpa);
347 var imports = std.ArrayList(u16).init(gpa);
348
349 var symtab_cmd: ?u16 = null;
336 var i: u16 = 0;350 var i: u16 = 0;
337 while (i < hdr.ncmds) : (i += 1) {351 while (i < hdr.ncmds) : (i += 1) {
338 var cmd = try macho.LoadCommand.read(gpa, reader);352 var cmd = try macho.LoadCommand.read(gpa, reader);
353 load_commands.appendAssumeCapacity(cmd);
339354
340 if (opts.dump_symtab and cmd.cmd() == .SYMTAB) {355 switch (cmd.cmd()) {
341 symtab_cmd = cmd.symtab;356 .SEGMENT_64 => {
357 const seg = cmd.segment;
358 for (seg.sections.items) |_, j| {
359 try sections.append(.{ .seg = i, .sect = @intCast(u16, j) });
360 }
361 },
362 .SYMTAB => {
363 symtab_cmd = i;
364 },
365 .LOAD_DYLIB,
366 .LOAD_WEAK_DYLIB,
367 .REEXPORT_DYLIB,
368 => {
369 try imports.append(i);
370 },
371 else => {},
342 }372 }
343373
344 try dumpLoadCommand(cmd, i, writer);374 try dumpLoadCommand(cmd, i, writer);
345 try writer.writeByte('\n');375 try writer.writeByte('\n');
346 }376 }
347377
348 if (symtab_cmd) |cmd| {378 if (opts.dump_symtab) {
379 const cmd = load_commands.items[symtab_cmd.?].symtab;
349 try writer.writeAll(symtab_label ++ "\n");380 try writer.writeAll(symtab_label ++ "\n");
350 const strtab = bytes[cmd.stroff..][0..cmd.strsize];381 const strtab = bytes[cmd.stroff..][0..cmd.strsize];
351 const raw_symtab = bytes[cmd.symoff..][0 .. cmd.nsyms * @sizeOf(macho.nlist_64)];382 const raw_symtab = bytes[cmd.symoff..][0 .. cmd.nsyms * @sizeOf(macho.nlist_64)];
...@@ -354,7 +385,51 @@ const MachODumper = struct {...@@ -354,7 +385,51 @@ const MachODumper = struct {
354 for (symtab) |sym| {385 for (symtab) |sym| {
355 if (sym.stab()) continue;386 if (sym.stab()) continue;
356 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);387 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
357 try writer.print("{s} {x}\n", .{ sym_name, sym.n_value });388 if (sym.sect()) {
389 const map = sections.items[sym.n_sect - 1];
390 const seg = load_commands.items[map.seg].segment;
391 const sect = seg.sections.items[map.sect];
392 try writer.print("{x} ({s},{s})", .{
393 sym.n_value,
394 sect.segName(),
395 sect.sectName(),
396 });
397 if (sym.ext()) {
398 try writer.writeAll(" external");
399 }
400 try writer.print(" {s}\n", .{sym_name});
401 } else if (sym.undf()) {
402 const ordinal = @divTrunc(@bitCast(i16, sym.n_desc), macho.N_SYMBOL_RESOLVER);
403 const import_name = blk: {
404 if (ordinal <= 0) {
405 if (ordinal == macho.BIND_SPECIAL_DYLIB_SELF)
406 break :blk "self import";
407 if (ordinal == macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE)
408 break :blk "main executable";
409 if (ordinal == macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP)
410 break :blk "flat lookup";
411 unreachable;
412 }
413 const import_id = imports.items[@bitCast(u16, ordinal) - 1];
414 const import = load_commands.items[import_id].dylib;
415 const full_path = mem.sliceTo(import.data, 0);
416 const basename = fs.path.basename(full_path);
417 assert(basename.len > 0);
418 const ext = mem.lastIndexOfScalar(u8, basename, '.') orelse basename.len;
419 break :blk basename[0..ext];
420 };
421 try writer.writeAll("(undefined)");
422 if (sym.weakRef()) {
423 try writer.writeAll(" weak");
424 }
425 if (sym.ext()) {
426 try writer.writeAll(" external");
427 }
428 try writer.print(" {s} (from {s})\n", .{
429 sym_name,
430 import_name,
431 });
432 } else unreachable;
358 }433 }
359 }434 }
360435
test/link/macho/entry/build.zig+1-1
...@@ -22,7 +22,7 @@ pub fn build(b: *Builder) void {...@@ -22,7 +22,7 @@ pub fn build(b: *Builder) void {
22 check_exe.checkNext("entryoff {entryoff}");22 check_exe.checkNext("entryoff {entryoff}");
2323
24 check_exe.checkInSymtab();24 check_exe.checkInSymtab();
25 check_exe.checkNext("_non_main {n_value}");25 check_exe.checkNext("{n_value} (__TEXT,__text) external _non_main");
2626
27 check_exe.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } });27 check_exe.checkComputeCompare("vmaddr entryoff +", .{ .op = .eq, .value = .{ .variable = "n_value" } });
2828
test/link/macho/weak_library/build.zig+5
...@@ -25,6 +25,11 @@ pub fn build(b: *Builder) void {...@@ -25,6 +25,11 @@ pub fn build(b: *Builder) void {
25 const check = exe.checkObject(.macho);25 const check = exe.checkObject(.macho);
26 check.checkStart("cmd LOAD_WEAK_DYLIB");26 check.checkStart("cmd LOAD_WEAK_DYLIB");
27 check.checkNext("name @rpath/liba.dylib");27 check.checkNext("name @rpath/liba.dylib");
28
29 check.checkInSymtab();
30 check.checkNext("(undefined) weak external _a (from liba)");
31 check.checkNext("(undefined) weak external _asStr (from liba)");
32
28 test_step.dependOn(&check.step);33 test_step.dependOn(&check.step);
2934
30 const run_cmd = exe.run();35 const run_cmd = exe.run();