Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

prepareTables

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) {
        // We are fuzzing the same executable with multiple threads.
        // 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, // populated below
        .source_locations = undefined, // populated below
        .entry_points = .empty,
        .start_timestamp = ws.now(),
        .start_n_runs = undefined, // populated below
    };
    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);

    // Unfortunately the PCs array that LLVM gives us from the 8-bit PC
    // 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();
}