Skip to content

Commit a3c74ac

Browse files
committed
add --debug-rt CLI arg to the compiler + bonus edits
The flag makes compiler_rt and libfuzzer be in debug mode. Also: * fuzzer: override debug logs and disable debug logs for frequently called functions * std.Build.Fuzz: fix bug of rerunning the old unit test binary * report errors from rebuilding the unit tests better * link.Elf: additionally add tsan lib and fuzzer lib to the hash
1 parent 90dfd86 commit a3c74ac

File tree

9 files changed

+116
-29
lines changed

9 files changed

+116
-29
lines changed

lib/compiler/build_runner.zig

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ pub fn main() !void {
208208
try debug_log_scopes.append(next_arg);
209209
} else if (mem.eql(u8, arg, "--debug-pkg-config")) {
210210
builder.debug_pkg_config = true;
211+
} else if (mem.eql(u8, arg, "--debug-rt")) {
212+
graph.debug_compiler_runtime_libs = true;
211213
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
212214
builder.debug_compile_errors = true;
213215
} else if (mem.eql(u8, arg, "--system")) {
@@ -1072,7 +1074,8 @@ fn workerMakeOneStep(
10721074
std.debug.lockStdErr();
10731075
defer std.debug.unlockStdErr();
10741076

1075-
printErrorMessages(b, s, run.ttyconf, run.stderr, run.prominent_compile_errors) catch {};
1077+
const gpa = b.allocator;
1078+
printErrorMessages(gpa, s, run.ttyconf, run.stderr, run.prominent_compile_errors) catch {};
10761079
}
10771080

10781081
handle_result: {
@@ -1126,14 +1129,12 @@ fn workerMakeOneStep(
11261129
}
11271130

11281131
pub fn printErrorMessages(
1129-
b: *std.Build,
1132+
gpa: Allocator,
11301133
failing_step: *Step,
11311134
ttyconf: std.io.tty.Config,
11321135
stderr: File,
11331136
prominent_compile_errors: bool,
11341137
) !void {
1135-
const gpa = b.allocator;
1136-
11371138
// Provide context for where these error messages are coming from by
11381139
// printing the corresponding Step subtree.
11391140

@@ -1313,6 +1314,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13131314
\\ --seed [integer] For shuffling dependency traversal order (default: random)
13141315
\\ --debug-log [scope] Enable debugging the compiler
13151316
\\ --debug-pkg-config Fail if unknown pkg-config flags encountered
1317+
\\ --debug-rt Debug compiler runtime libraries
13161318
\\ --verbose-link Enable compiler debug output for linking
13171319
\\ --verbose-air Enable compiler debug output for Zig AIR
13181320
\\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR

lib/fuzzer.zig

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,40 @@
11
const std = @import("std");
22
const Allocator = std.mem.Allocator;
33

4+
pub const std_options = .{
5+
.logFn = logOverride,
6+
};
7+
8+
var log_file: ?std.fs.File = null;
9+
10+
fn logOverride(
11+
comptime level: std.log.Level,
12+
comptime scope: @TypeOf(.EnumLiteral),
13+
comptime format: []const u8,
14+
args: anytype,
15+
) void {
16+
const f = if (log_file) |f| f else f: {
17+
const f = std.fs.cwd().createFile("libfuzzer.log", .{}) catch @panic("failed to open fuzzer log file");
18+
log_file = f;
19+
break :f f;
20+
};
21+
const prefix1 = comptime level.asText();
22+
const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
23+
f.writer().print(prefix1 ++ prefix2 ++ format ++ "\n", args) catch @panic("failed to write to fuzzer log");
24+
}
25+
426
export threadlocal var __sancov_lowest_stack: usize = 0;
527

628
export fn __sanitizer_cov_8bit_counters_init(start: [*]u8, stop: [*]u8) void {
729
std.log.debug("__sanitizer_cov_8bit_counters_init start={*}, stop={*}", .{ start, stop });
830
}
931

10-
export fn __sanitizer_cov_pcs_init(pcs_beg: [*]const usize, pcs_end: [*]const usize) void {
11-
std.log.debug("__sanitizer_cov_pcs_init pcs_beg={*}, pcs_end={*}", .{ pcs_beg, pcs_end });
32+
export fn __sanitizer_cov_pcs_init(pc_start: [*]const usize, pc_end: [*]const usize) void {
33+
std.log.debug("__sanitizer_cov_pcs_init pc_start={*}, pc_end={*}", .{ pc_start, pc_end });
34+
fuzzer.pc_range = .{
35+
.start = @intFromPtr(pc_start),
36+
.end = @intFromPtr(pc_start),
37+
};
1238
}
1339

1440
export fn __sanitizer_cov_trace_const_cmp1(arg1: u8, arg2: u8) void {
@@ -48,49 +74,73 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases_ptr: [*]u64) void {
4874
const len = cases_ptr[0];
4975
const val_size_in_bits = cases_ptr[1];
5076
const cases = cases_ptr[2..][0..len];
51-
std.log.debug("0x{x}: switch on value {d} ({d} bits) with {d} cases", .{
52-
pc, val, val_size_in_bits, cases.len,
53-
});
77+
_ = val;
78+
_ = pc;
79+
_ = val_size_in_bits;
80+
_ = cases;
81+
//std.log.debug("0x{x}: switch on value {d} ({d} bits) with {d} cases", .{
82+
// pc, val, val_size_in_bits, cases.len,
83+
//});
5484
}
5585

5686
export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {
5787
const pc = @returnAddress();
58-
std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });
88+
_ = callee;
89+
_ = pc;
90+
//std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });
5991
}
6092

6193
fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {
62-
std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 });
94+
_ = pc;
95+
_ = arg1;
96+
_ = arg2;
97+
//std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 });
6398
}
6499

65100
const Fuzzer = struct {
66101
gpa: Allocator,
67102
rng: std.Random.DefaultPrng,
68103
input: std.ArrayListUnmanaged(u8),
104+
pc_range: PcRange,
105+
count: usize,
69106

70107
const Slice = extern struct {
71108
ptr: [*]const u8,
72109
len: usize,
73110

74-
fn toSlice(s: Slice) []const u8 {
111+
fn toZig(s: Slice) []const u8 {
75112
return s.ptr[0..s.len];
76113
}
77114

78-
fn fromSlice(s: []const u8) Slice {
115+
fn fromZig(s: []const u8) Slice {
79116
return .{
80117
.ptr = s.ptr,
81118
.len = s.len,
82119
};
83120
}
84121
};
85122

123+
const PcRange = struct {
124+
start: usize,
125+
end: usize,
126+
};
127+
86128
fn next(f: *Fuzzer) ![]const u8 {
87129
const gpa = f.gpa;
130+
131+
// Prepare next input.
88132
const rng = fuzzer.rng.random();
89133
const len = rng.uintLessThan(usize, 64);
90134
try f.input.resize(gpa, len);
91135
rng.bytes(f.input.items);
136+
f.resetCoverage();
137+
f.count += 1;
92138
return f.input.items;
93139
}
140+
141+
fn resetCoverage(f: *Fuzzer) void {
142+
_ = f;
143+
}
94144
};
95145

96146
var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
@@ -99,10 +149,12 @@ var fuzzer: Fuzzer = .{
99149
.gpa = general_purpose_allocator.allocator(),
100150
.rng = std.Random.DefaultPrng.init(0),
101151
.input = .{},
152+
.pc_range = .{ .start = 0, .end = 0 },
153+
.count = 0,
102154
};
103155

104156
export fn fuzzer_next() Fuzzer.Slice {
105-
return Fuzzer.Slice.fromSlice(fuzzer.next() catch |err| switch (err) {
157+
return Fuzzer.Slice.fromZig(fuzzer.next() catch |err| switch (err) {
106158
error.OutOfMemory => @panic("out of memory"),
107159
});
108160
}

lib/std/Build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ pub const Graph = struct {
113113
arena: Allocator,
114114
system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .{},
115115
system_package_mode: bool = false,
116+
debug_compiler_runtime_libs: bool = false,
116117
cache: Cache,
117118
zig_exe: [:0]const u8,
118119
env_map: EnvMap,

lib/std/Build/Fuzz.zig

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,32 @@ pub fn start(
5555
}
5656

5757
fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {
58-
const compile_step = run.producer.?;
59-
const prog_node = parent_prog_node.start(compile_step.step.name, 0);
58+
const gpa = run.step.owner.allocator;
59+
const stderr = std.io.getStdErr();
60+
61+
const compile = run.producer.?;
62+
const prog_node = parent_prog_node.start(compile.step.name, 0);
6063
defer prog_node.end();
61-
if (compile_step.rebuildInFuzzMode(prog_node)) |rebuilt_bin_path| {
64+
65+
const result = compile.rebuildInFuzzMode(prog_node);
66+
67+
const show_compile_errors = compile.step.result_error_bundle.errorMessageCount() > 0;
68+
const show_error_msgs = compile.step.result_error_msgs.items.len > 0;
69+
const show_stderr = compile.step.result_stderr.len > 0;
70+
71+
if (show_error_msgs or show_compile_errors or show_stderr) {
72+
std.debug.lockStdErr();
73+
defer std.debug.unlockStdErr();
74+
build_runner.printErrorMessages(gpa, &compile.step, ttyconf, stderr, false) catch {};
75+
}
76+
77+
if (result) |rebuilt_bin_path| {
6278
run.rebuilt_executable = rebuilt_bin_path;
6379
} else |err| switch (err) {
64-
error.MakeFailed => {
65-
const b = run.step.owner;
66-
const stderr = std.io.getStdErr();
67-
std.debug.lockStdErr();
68-
defer std.debug.unlockStdErr();
69-
build_runner.printErrorMessages(b, &compile_step.step, ttyconf, stderr, false) catch {};
70-
},
80+
error.MakeFailed => {},
7181
else => {
7282
std.debug.print("step '{s}': failed to rebuild in fuzz mode: {s}\n", .{
73-
compile_step.step.name, @errorName(err),
83+
compile.step.name, @errorName(err),
7484
});
7585
},
7686
}
@@ -82,18 +92,18 @@ fn fuzzWorkerRun(
8292
ttyconf: std.io.tty.Config,
8393
parent_prog_node: std.Progress.Node,
8494
) void {
95+
const gpa = run.step.owner.allocator;
8596
const test_name = run.cached_test_metadata.?.testName(unit_test_index);
8697

8798
const prog_node = parent_prog_node.start(test_name, 0);
8899
defer prog_node.end();
89100

90101
run.rerunInFuzzMode(unit_test_index, prog_node) catch |err| switch (err) {
91102
error.MakeFailed => {
92-
const b = run.step.owner;
93103
const stderr = std.io.getStdErr();
94104
std.debug.lockStdErr();
95105
defer std.debug.unlockStdErr();
96-
build_runner.printErrorMessages(b, &run.step, ttyconf, stderr, false) catch {};
106+
build_runner.printErrorMessages(gpa, &run.step, ttyconf, stderr, false) catch {};
97107
},
98108
else => {
99109
std.debug.print("step '{s}': failed to rebuild '{s}' in fuzz mode: {s}\n", .{

lib/std/Build/Step/Compile.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,8 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
14831483
try zig_args.append("--global-cache-dir");
14841484
try zig_args.append(b.graph.global_cache_root.path orelse ".");
14851485

1486+
if (b.graph.debug_compiler_runtime_libs) try zig_args.append("--debug-rt");
1487+
14861488
try zig_args.append("--name");
14871489
try zig_args.append(compile.name);
14881490

@@ -1840,6 +1842,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
18401842
}
18411843

18421844
pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 {
1845+
const gpa = c.step.owner.allocator;
1846+
1847+
c.step.result_error_msgs.clearRetainingCapacity();
1848+
c.step.result_stderr = "";
1849+
1850+
c.step.result_error_bundle.deinit(gpa);
1851+
c.step.result_error_bundle = std.zig.ErrorBundle.empty;
1852+
18431853
const zig_args = try getZigArgs(c, true);
18441854
const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false);
18451855
return maybe_output_bin_path.?;

lib/std/Build/Step/Run.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,10 @@ pub fn rerunInFuzzMode(run: *Run, unit_test_index: u32, prog_node: std.Progress.
865865
},
866866
.artifact => |pa| {
867867
const artifact = pa.artifact;
868-
const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;
868+
const file_path = if (artifact == run.producer.?)
869+
run.rebuilt_executable.?
870+
else
871+
(artifact.installed_path orelse artifact.generated_bin.?.path.?);
869872
try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));
870873
},
871874
.output_file, .output_directory => unreachable,

src/Compilation.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2180,7 +2180,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21802180
comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);
21812181
}
21822182
},
2183-
.incremental => {},
2183+
.incremental => {
2184+
log.debug("Compilation.update for {s}, CacheMode.incremental", .{comp.root_name});
2185+
},
21842186
}
21852187

21862188
// From this point we add a preliminary set of file system inputs that

src/link/Elf.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,6 +2286,8 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22862286
}
22872287
try man.addOptionalFile(module_obj_path);
22882288
try man.addOptionalFile(compiler_rt_path);
2289+
try man.addOptionalFile(if (comp.tsan_lib) |l| l.full_object_path else null);
2290+
try man.addOptionalFile(if (comp.fuzzer_lib) |l| l.full_object_path else null);
22892291

22902292
// We can skip hashing libc and libc++ components that we are in charge of building from Zig
22912293
// installation sources because they are always a product of the compiler version + target information.

src/main.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ const usage_build_generic =
655655
\\ --debug-log [scope] Enable printing debug/info log messages for scope
656656
\\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
657657
\\ --debug-link-snapshot Enable dumping of the linker's state in JSON format
658+
\\ --debug-rt Debug compiler runtime libraries
658659
\\
659660
;
660661

@@ -912,6 +913,7 @@ fn buildOutputType(
912913
var minor_subsystem_version: ?u16 = null;
913914
var mingw_unicode_entry_point: bool = false;
914915
var enable_link_snapshots: bool = false;
916+
var debug_compiler_runtime_libs = false;
915917
var opt_incremental: ?bool = null;
916918
var install_name: ?[]const u8 = null;
917919
var hash_style: link.File.Elf.HashStyle = .both;
@@ -1367,6 +1369,8 @@ fn buildOutputType(
13671369
} else {
13681370
enable_link_snapshots = true;
13691371
}
1372+
} else if (mem.eql(u8, arg, "--debug-rt")) {
1373+
debug_compiler_runtime_libs = true;
13701374
} else if (mem.eql(u8, arg, "-fincremental")) {
13711375
dev.check(.incremental);
13721376
opt_incremental = true;
@@ -3408,6 +3412,7 @@ fn buildOutputType(
34083412
// noise when --search-prefix and --mod are combined.
34093413
.global_cc_argv = try cc_argv.toOwnedSlice(arena),
34103414
.file_system_inputs = &file_system_inputs,
3415+
.debug_compiler_runtime_libs = debug_compiler_runtime_libs,
34113416
}) catch |err| switch (err) {
34123417
error.LibCUnavailable => {
34133418
const triple_name = try target.zigTriple(arena);

0 commit comments

Comments
 (0)