feature. See also
. The project being documented here (as the example) is the Zig library itself.
Fuzz.prepareTables
fn prepareTables(fuzz: *Fuzz, run_index: Configuration.Step.Index, coverage_id: u64) error
File
Code
fn prepareTables(fuzz: *Fuzz, run_index: Configuration.Step.Index, coverage_id: u64) error{ OutOfMemory, AlreadyReported, Canceled }!void {
assert(fuzz.mode == .forever);
const ws = fuzz.mode.forever.ws;
const maker = fuzz.maker;
const graph = maker.graph;
const io = graph.io;
const gpa = maker.gpa;
const conf = &maker.scanned_config.configuration;
const cache_root = graph.local_cache_root;
try fuzz.coverage_mutex.lock(io);
defer fuzz.coverage_mutex.unlock(io);
const gop = try fuzz.coverage_files.getOrPut(gpa, coverage_id);
if (gop.found_existing) {
// Perhaps the same unit test; perhaps a different one. In any
// case, since the coverage file is the same, we only have to
// notice changes to that one file in order to learn coverage for
// this particular executable.
return;
}
errdefer _ = fuzz.coverage_files.pop();
gop.value_ptr.* = .{
.coverage = std.debug.Coverage.init,
.mapped_memory = undefined,
.source_locations = undefined,
.entry_points = .empty,
.start_timestamp = ws.now(),
.start_n_runs = undefined,
};
errdefer gop.value_ptr.coverage.deinit(gpa);
const run_step = maker.stepByIndex(run_index);
const conf_run_step = run_index.ptr(conf);
const conf_run = conf_run_step.extended.cast(conf, Configuration.Step.Run).?;
const comp_index = conf_run.producer.value.?;
const conf_comp_step = comp_index.ptr(conf);
const conf_comp = conf_comp_step.extended.cast(conf, Configuration.Step.Compile).?;
const rebuilt_exe_path = run_step.extended.run.rebuilt_executable.?;
const root_module = conf_comp.root_module.get(conf);
const target = root_module.resolved_target.get(conf).?.result.get(conf);
var debug_info = std.debug.Info.load(
gpa,
io,
rebuilt_exe_path,
&gop.value_ptr.coverage,
target.flags.object_format.unwrap().?,
target.flags.cpu_arch.unwrap().?,
) catch |err| {
log.err("step {s}: failed to load debug information for {f}: {t}", .{
conf_run_step.name.slice(conf), rebuilt_exe_path, err,
});
return error.AlreadyReported;
};
defer debug_info.deinit(gpa);
const coverage_file_path: Build.Cache.Path = .{
.root_dir = cache_root,
.sub_path = "v/" ++ std.fmt.hex(coverage_id),
};
var coverage_file = coverage_file_path.root_dir.handle.openFile(io, coverage_file_path.sub_path, .{}) catch |err| {
log.err("step {s}: failed to load coverage file {f}: {t}", .{
conf_run_step.name.slice(conf), coverage_file_path, err,
});
return error.AlreadyReported;
};
defer coverage_file.close(io);
const file_size = coverage_file.length(io) catch |err| {
log.err("unable to check len of coverage file {f}: {t}", .{ coverage_file_path, err });
return error.AlreadyReported;
};
const mapped_memory = std.posix.mmap(
null,
file_size,
.{ .READ = true },
.{ .TYPE = .SHARED },
coverage_file.handle,
0,
) catch |err| {
log.err("failed to map coverage file {f}: {t}", .{ coverage_file_path, err });
return error.AlreadyReported;
};
gop.value_ptr.mapped_memory = mapped_memory;
const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
const pcs = header.pcAddrs();
const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len);
errdefer gpa.free(source_locations);
// counters feature is not sorted.
var sorted_pcs: std.MultiArrayList(struct { pc: u64, index: u32, sl: Coverage.SourceLocation }) = .empty;
defer sorted_pcs.deinit(gpa);
try sorted_pcs.resize(gpa, pcs.len);
@memcpy(sorted_pcs.items(.pc), pcs);
for (sorted_pcs.items(.index), 0..) |*v, i| v.* = @intCast(i);
sorted_pcs.sortUnstable(struct {
addrs: []const u64,
pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
return ctx.addrs[a_index] < ctx.addrs[b_index];
}
}{ .addrs = sorted_pcs.items(.pc) });
debug_info.resolveAddresses(gpa, io, sorted_pcs.items(.pc), sorted_pcs.items(.sl)) catch |err| {
log.err("failed to resolve addresses to source locations: {t}", .{err});
return error.AlreadyReported;
};
for (sorted_pcs.items(.index), sorted_pcs.items(.sl)) |i, sl| source_locations[i] = sl;
gop.value_ptr.source_locations = source_locations;
gop.value_ptr.start_n_runs = header.n_runs;
ws.notifyUpdate();
}