|
//! This file is shared among Zig code running in wildly different contexts: //! * The build runner, running on the host computer //! * The build system web interface Wasm code, running in the browser //! * `libfuzzer`, compiled alongside unit tests //! //! All of these components interface to some degree via an ABI: //! * The build runner communicates with the web interface over a WebSocket connection //! * The build runner communicates with `libfuzzer` over a shared memory-mapped file |
ToClientTagAll WebSocket messages sent by the server to the client begin with a |
// Check that no WebSocket message type has implicit padding bits. This ensures we never send any // undefined bits over the wire, and also helps validate that the layout doesn't differ between, for // instance, the web server in `std.Build` and the Wasm client. comptime { const check = struct { fn check(comptime T: type) void { const std = @import("std"); std.debug.assert(@typeInfo(T) == .@"struct"); std.debug.assert(@typeInfo(T).@"struct".layout == .@"extern"); std.debug.assert(std.meta.hasUniqueRepresentation(T)); } }.check; |
ToServerTagLike |
// server->client check(Hello); check(StatusUpdate); check(StepUpdate); check(fuzz.SourceIndexHeader); check(fuzz.CoverageUpdateHeader); check(fuzz.EntryPointHeader); check(time_report.GenericResult); check(time_report.CompileResult); |
BuildStatusThe current overall status of the build runner.
Keep in sync with indices in web UI |
// client->server check(Rebuild); } |
HelloWebSocket server->client.
Sent by the server as the first message after a WebSocket connection opens to provide basic
information about the server, the build graph, etc.
Trailing:
* |
/// All WebSocket messages sent by the server to the client begin with a `ToClientTag` byte. This /// enum is non-exhaustive only to avoid Illegal Behavior when malformed messages are sent over the /// socket; unnamed tags are an error condition and should terminate the connection. /// /// Every tag has a curresponding `extern struct` representing the full message (or a header of the /// message if it is variable-length). For instance, `.hello` corresponds to `Hello`. /// /// When introducing a tag, make sure to add a corresponding `extern struct` whose first field is /// this enum, and `check` its layout in the `comptime` block above. pub const ToClientTag = enum(u8) { hello, status_update, step_update, |
FlagsAny message containing a timestamp represents it as a number of nanoseconds relative to when the build began. This field is the current timestamp, represented in that form. |
// `--fuzz` fuzz_source_index, fuzz_coverage_update, fuzz_entry_points, |
StatusUpdateThe number of steps in the build graph which are reachable from the top-level step[s] being run; in other words, the number of steps which will be executed by this build. The name of each step trails this message. |
// `--time-report` time_report_generic_result, time_report_compile_result, |
StepUpdateWhether time reporting is enabled. |
_, }; |
StatusWebSocket server->client. Indicates that the build status has changed. |
/// Like `ToClientTag`, but for messages sent by the client to the server. pub const ToServerTag = enum(u8) { rebuild, |
RebuildWebSocket server->client. Indicates a change in a step's status. |
_, }; |
fuzzKeep in sync with indices in web UI |
/// The current overall status of the build runner. /// Keep in sync with indices in web UI `main.js:updateBuildStatus`. pub const BuildStatus = enum(u8) { idle, watching, running, fuzz_init, }; |
SeenPcsHeaderABI bits specifically relating to the fuzzer interface. |
/// WebSocket server->client. /// /// Sent by the server as the first message after a WebSocket connection opens to provide basic /// information about the server, the build graph, etc. /// /// Trailing: /// * `step_name_len: u32` for each `steps_len` /// * `step_name: [step_name_len]u8` for each `step_name_len` /// * `step_status: u8` for every 4 `steps_len`; every 2 bits is a `StepUpdate.Status`, LSBs first pub const Hello = extern struct { tag: ToClientTag = .hello, |
trailinglibfuzzer uses this and its usize is the one that counts. To match the ABI, make the ints be the size of the target used with libfuzzer. Trailing: * 1 bit per pc_addr, usize elements * pc_addr: usize for each pcs_len |
status: BuildStatus, flags: Flags, |
headerEnd()Used for comptime assertions. Provides a mechanism for strategically causing compile errors. |
/// Any message containing a timestamp represents it as a number of nanoseconds relative to when /// the build began. This field is the current timestamp, represented in that form. timestamp: i64 align(4), |
seenBits()WebSocket server->client. Sent once, when fuzzing starts, to indicate the available coverage data. Trailing: * std.debug.Coverage.String for each directories_len * std.debug.Coverage.File for each files_len * std.debug.Coverage.SourceLocation for each source_locations_len * u8 for each string_bytes_len |
/// The number of steps in the build graph which are reachable from the top-level step[s] being /// run; in other words, the number of steps which will be executed by this build. The name of /// each step trails this message. steps_len: u32 align(1), |
seenElemsLen()When, according to the server, fuzzing started. |
pub const Flags = packed struct(u16) { /// Whether time reporting is enabled. time_report: bool, _: u15 = 0, }; }; /// WebSocket server->client. /// /// Indicates that the build status has changed. pub const StatusUpdate = extern struct { tag: ToClientTag = .status_update, new: BuildStatus, }; /// WebSocket server->client. /// /// Indicates a change in a step's status. pub const StepUpdate = extern struct { tag: ToClientTag = .step_update, step_idx: u32 align(1), bits: packed struct(u8) { status: Status, _: u6 = 0, }, /// Keep in sync with indices in web UI `main.js:updateStepStatus`. pub const Status = enum(u2) { pending, wip, success, failure, }; }; |
pcAddrs()WebSocket server->client. Sent whenever the set of covered source locations is updated. Trailing: * one bit per source_locations_len, contained in u64 elements |
pub const Rebuild = extern struct { tag: ToServerTag = .rebuild, }; |
SourceIndexHeaderWebSocket server->client. Sent whenever the set of entry points is updated. Trailing: * one u32 index of source_locations per locsLen() |
/// ABI bits specifically relating to the fuzzer interface. pub const fuzz = struct { /// libfuzzer uses this and its usize is the one that counts. To match the ABI, /// make the ints be the size of the target used with libfuzzer. /// /// Trailing: /// * 1 bit per pc_addr, usize elements /// * pc_addr: usize for each pcs_len pub const SeenPcsHeader = extern struct { n_runs: usize, unique_runs: usize, pcs_len: usize, |
CoverageUpdateHeaderABI bits specifically relating to the time report interface. |
/// Used for comptime assertions. Provides a mechanism for strategically /// causing compile errors. |
trailingWebSocket server->client.
Sent after a |
pub const trailing = .{ .pc_bits_usize, .pc_addr, }; |
EntryPointHeaderWebSocket server->client.
Sent after a |
pub fn headerEnd(header: *const SeenPcsHeader) []const usize { const ptr: [*]align(@alignOf(usize)) const u8 = @ptrCast(header); const header_end_ptr: [*]const usize = @ptrCast(ptr + @sizeOf(SeenPcsHeader)); const pcs_len = header.pcs_len; return header_end_ptr[0 .. pcs_len + seenElemsLen(pcs_len)]; } |
locsLen() |
pub fn seenBits(header: *const SeenPcsHeader) []const usize { return header.headerEnd()[0..seenElemsLen(header.pcs_len)]; } |
init() |
pub fn seenElemsLen(pcs_len: usize) usize { return (pcs_len + @bitSizeOf(usize) - 1) / @bitSizeOf(usize); } |
time_report |
pub fn pcAddrs(header: *const SeenPcsHeader) []const usize { const pcs_len = header.pcs_len; return header.headerEnd()[seenElemsLen(pcs_len)..][0..pcs_len]; } }; |
GenericResult |
/// WebSocket server->client. /// /// Sent once, when fuzzing starts, to indicate the available coverage data. /// /// Trailing: /// * std.debug.Coverage.String for each directories_len /// * std.debug.Coverage.File for each files_len /// * std.debug.Coverage.SourceLocation for each source_locations_len /// * u8 for each string_bytes_len pub const SourceIndexHeader = extern struct { tag: ToClientTag = .fuzz_source_index, _: [3]u8 = @splat(0), directories_len: u32, files_len: u32, source_locations_len: u32, string_bytes_len: u32, /// When, according to the server, fuzzing started. start_timestamp: i64 align(4), }; |
CompileResult |
/// WebSocket server->client. /// /// Sent whenever the set of covered source locations is updated. /// /// Trailing: /// * one bit per source_locations_len, contained in u64 elements pub const CoverageUpdateHeader = extern struct { tag: ToClientTag = .fuzz_coverage_update, _: [7]u8 = @splat(0), n_runs: u64, unique_runs: u64, |
Flags |
pub const trailing = .{ .pc_bits_usize, }; }; |
Stats |
/// WebSocket server->client. /// /// Sent whenever the set of entry points is updated. /// /// Trailing: /// * one u32 index of source_locations per locsLen() pub const EntryPointHeader = extern struct { tag: ToClientTag = .fuzz_entry_points, locs_len_raw: [3]u8, |
init: |
pub fn locsLen(hdr: EntryPointHeader) u24 { return @bitCast(hdr.locs_len_raw); } pub fn init(locs_len: u24) EntryPointHeader { return .{ .locs_len_raw = @bitCast(locs_len) }; } }; }; /// ABI bits specifically relating to the time report interface. pub const time_report = struct { /// WebSocket server->client. /// /// Sent after a `Step` finishes, providing the time taken to execute the step. pub const GenericResult = extern struct { tag: ToClientTag = .time_report_generic_result, step_idx: u32 align(1), ns_total: u64 align(1), }; /// WebSocket server->client. /// /// Sent after a `Step.Compile` finishes, providing the step's time report. /// /// Trailing: /// * `llvm_pass_timings: [llvm_pass_timings_len]u8` (ASCII-encoded) /// * for each `files_len`: /// * `name` (null-terminated UTF-8 string) /// * for each `decls_len`: /// * `name` (null-terminated UTF-8 string) /// * `file: u32` (index of file this decl is in) /// * `sema_ns: u64` (nanoseconds spent semantically analyzing this decl) /// * `codegen_ns: u64` (nanoseconds spent semantically analyzing this decl) /// * `link_ns: u64` (nanoseconds spent semantically analyzing this decl) pub const CompileResult = extern struct { tag: ToClientTag = .time_report_compile_result, step_idx: u32 align(1), flags: Flags, stats: Stats align(1), ns_total: u64 align(1), llvm_pass_timings_len: u32 align(1), files_len: u32 align(1), decls_len: u32 align(1), pub const Flags = packed struct(u8) { use_llvm: bool, _: u7 = 0, }; pub const Stats = extern struct { n_reachable_files: u32, n_imported_files: u32, n_generic_instances: u32, n_inline_calls: u32, cpu_ns_parse: u64, cpu_ns_astgen: u64, cpu_ns_sema: u64, cpu_ns_codegen: u64, cpu_ns_link: u64, real_ns_files: u64, real_ns_decls: u64, real_ns_llvm_emit: u64, real_ns_link_flush: u64, pub const init: Stats = .{ .n_reachable_files = 0, .n_imported_files = 0, .n_generic_instances = 0, .n_inline_calls = 0, .cpu_ns_parse = 0, .cpu_ns_astgen = 0, .cpu_ns_sema = 0, .cpu_ns_codegen = 0, .cpu_ns_link = 0, .real_ns_files = 0, .real_ns_decls = 0, .real_ns_llvm_emit = 0, .real_ns_link_flush = 0, }; }; }; }; |
Generated by zstd-live on 2025-08-12 12:37:55 UTC. |