authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-09 12:50:48-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-09 12:50:48-07:00
logeb17fe85a595c81da0304f4168c5dcf8181bd972
treee4cc1b923c05ea12826edb85c82919865d0950e6
parent9f46abf598a1bc27aa42a96aa6d94f3112fa210b
parentf6f1ecf0f9227bee33b963a6ff5dfc3001ad2c46
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21006 from ziglang/fuzz

fuzzing: more optimized and correct management of 8-bit PC counters

5 files changed, 114 insertions(+), 64 deletions(-)

lib/fuzzer.zig+31-19
...@@ -213,8 +213,12 @@ const Fuzzer = struct {...@@ -213,8 +213,12 @@ const Fuzzer = struct {
213 .truncate = false,213 .truncate = false,
214 });214 });
215 defer coverage_file.close();215 defer coverage_file.close();
216 const n_bitset_elems = (flagged_pcs.len + 7) / 8;216 const n_bitset_elems = (flagged_pcs.len + @bitSizeOf(usize) - 1) / @bitSizeOf(usize);
217 const bytes_len = @sizeOf(SeenPcsHeader) + flagged_pcs.len * @sizeOf(usize) + n_bitset_elems;217 comptime assert(SeenPcsHeader.trailing[0] == .pc_bits_usize);
218 comptime assert(SeenPcsHeader.trailing[1] == .pc_addr);
219 const bytes_len = @sizeOf(SeenPcsHeader) +
220 n_bitset_elems * @sizeOf(usize) +
221 flagged_pcs.len * @sizeOf(usize);
218 const existing_len = coverage_file.getEndPos() catch |err| {222 const existing_len = coverage_file.getEndPos() catch |err| {
219 fatal("unable to check len of coverage file: {s}", .{@errorName(err)});223 fatal("unable to check len of coverage file: {s}", .{@errorName(err)});
220 };224 };
...@@ -229,7 +233,7 @@ const Fuzzer = struct {...@@ -229,7 +233,7 @@ const Fuzzer = struct {
229 fatal("unable to init coverage memory map: {s}", .{@errorName(err)});233 fatal("unable to init coverage memory map: {s}", .{@errorName(err)});
230 };234 };
231 if (existing_len != 0) {235 if (existing_len != 0) {
232 const existing_pcs_bytes = f.seen_pcs.items[@sizeOf(SeenPcsHeader)..][0 .. flagged_pcs.len * @sizeOf(usize)];236 const existing_pcs_bytes = f.seen_pcs.items[@sizeOf(SeenPcsHeader) + @sizeOf(usize) * n_bitset_elems ..][0 .. flagged_pcs.len * @sizeOf(usize)];
233 const existing_pcs = std.mem.bytesAsSlice(usize, existing_pcs_bytes);237 const existing_pcs = std.mem.bytesAsSlice(usize, existing_pcs_bytes);
234 for (existing_pcs, flagged_pcs, 0..) |old, new, i| {238 for (existing_pcs, flagged_pcs, 0..) |old, new, i| {
235 if (old != new.addr) {239 if (old != new.addr) {
...@@ -246,10 +250,10 @@ const Fuzzer = struct {...@@ -246,10 +250,10 @@ const Fuzzer = struct {
246 .lowest_stack = std.math.maxInt(usize),250 .lowest_stack = std.math.maxInt(usize),
247 };251 };
248 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&header));252 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&header));
253 f.seen_pcs.appendNTimesAssumeCapacity(0, n_bitset_elems * @sizeOf(usize));
249 for (flagged_pcs) |flagged_pc| {254 for (flagged_pcs) |flagged_pc| {
250 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&flagged_pc.addr));255 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&flagged_pc.addr));
251 }256 }
252 f.seen_pcs.appendNTimesAssumeCapacity(0, n_bitset_elems);
253 }257 }
254 }258 }
255259
...@@ -299,22 +303,30 @@ const Fuzzer = struct {...@@ -299,22 +303,30 @@ const Fuzzer = struct {
299 .score = analysis.score,303 .score = analysis.score,
300 };304 };
301305
302 // Track code coverage from all runs.
303 {306 {
304 const seen_pcs = f.seen_pcs.items[@sizeOf(SeenPcsHeader) + f.flagged_pcs.len * @sizeOf(usize) ..];307 // Track code coverage from all runs.
305 for (seen_pcs, 0..) |*elem, i| {308 comptime assert(SeenPcsHeader.trailing[0] == .pc_bits_usize);
306 const byte_i = i * 8;309 const header_end_ptr: [*]volatile usize = @ptrCast(f.seen_pcs.items[@sizeOf(SeenPcsHeader)..]);
307 const mask: u8 =310 const remainder = f.flagged_pcs.len % @bitSizeOf(usize);
308 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 0] != 0)) << 0) |311 const aligned_len = f.flagged_pcs.len - remainder;
309 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 1] != 0)) << 1) |312 const seen_pcs = header_end_ptr[0..aligned_len];
310 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 2] != 0)) << 2) |313 const pc_counters = std.mem.bytesAsSlice([@bitSizeOf(usize)]u8, f.pc_counters[0..aligned_len]);
311 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 3] != 0)) << 3) |314 const V = @Vector(@bitSizeOf(usize), u8);
312 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 4] != 0)) << 4) |315 const zero_v: V = @splat(0);
313 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 5] != 0)) << 5) |316
314 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 6] != 0)) << 6) |317 for (header_end_ptr[0..pc_counters.len], pc_counters) |*elem, *array| {
315 (@as(u8, @intFromBool(f.pc_counters.ptr[byte_i + 7] != 0)) << 7);318 const v: V = array.*;
316319 const mask: usize = @bitCast(v != zero_v);
317 _ = @atomicRmw(u8, elem, .Or, mask, .monotonic);320 _ = @atomicRmw(usize, elem, .Or, mask, .monotonic);
321 }
322 if (remainder > 0) {
323 const i = pc_counters.len;
324 const elem = &seen_pcs[i];
325 var mask: usize = 0;
326 for (f.pc_counters[i * @bitSizeOf(usize) ..][0..remainder], 0..) |byte, bit_index| {
327 mask |= @as(usize, @intFromBool(byte != 0)) << @intCast(bit_index);
328 }
329 _ = @atomicRmw(usize, elem, .Or, mask, .monotonic);
318 }330 }
319 }331 }
320332
lib/fuzzer/wasm/main.zig+20-16
...@@ -125,12 +125,12 @@ export fn coveredSourceLocations() usize {...@@ -125,12 +125,12 @@ export fn coveredSourceLocations() usize {
125}125}
126126
127export fn totalRuns() u64 {127export fn totalRuns() u64 {
128 const header: *abi.CoverageUpdateHeader = @ptrCast(recent_coverage_update.items[0..@sizeOf(abi.CoverageUpdateHeader)]);128 const header: *abi.CoverageUpdateHeader = @alignCast(@ptrCast(recent_coverage_update.items[0..@sizeOf(abi.CoverageUpdateHeader)]));
129 return header.n_runs;129 return header.n_runs;
130}130}
131131
132export fn uniqueRuns() u64 {132export fn uniqueRuns() u64 {
133 const header: *abi.CoverageUpdateHeader = @ptrCast(recent_coverage_update.items[0..@sizeOf(abi.CoverageUpdateHeader)]);133 const header: *abi.CoverageUpdateHeader = @alignCast(@ptrCast(recent_coverage_update.items[0..@sizeOf(abi.CoverageUpdateHeader)]));
134 return header.unique_runs;134 return header.unique_runs;
135}135}
136136
...@@ -335,7 +335,7 @@ fn computeSourceAnnotations(...@@ -335,7 +335,7 @@ fn computeSourceAnnotations(
335 if (next_loc_index >= locs.items.len) return;335 if (next_loc_index >= locs.items.len) return;
336 const next_sli = locs.items[next_loc_index];336 const next_sli = locs.items[next_loc_index];
337 const next_sl = next_sli.ptr();337 const next_sl = next_sli.ptr();
338 if (next_sl.line > line or (next_sl.line == line and next_sl.column > column)) break;338 if (next_sl.line > line or (next_sl.line == line and next_sl.column >= column)) break;
339 try annotations.append(gpa, .{339 try annotations.append(gpa, .{
340 .file_byte_offset = offset,340 .file_byte_offset = offset,
341 .dom_id = @intFromEnum(next_sli),341 .dom_id = @intFromEnum(next_sli),
...@@ -349,7 +349,7 @@ var coverage = Coverage.init;...@@ -349,7 +349,7 @@ var coverage = Coverage.init;
349/// Index of type `SourceLocationIndex`.349/// Index of type `SourceLocationIndex`.
350var coverage_source_locations: std.ArrayListUnmanaged(Coverage.SourceLocation) = .{};350var coverage_source_locations: std.ArrayListUnmanaged(Coverage.SourceLocation) = .{};
351/// Contains the most recent coverage update message, unmodified.351/// Contains the most recent coverage update message, unmodified.
352var recent_coverage_update: std.ArrayListUnmanaged(u8) = .{};352var recent_coverage_update: std.ArrayListAlignedUnmanaged(u8, @alignOf(u64)) = .{};
353353
354fn updateCoverage(354fn updateCoverage(
355 directories: []const Coverage.String,355 directories: []const Coverage.String,
...@@ -406,19 +406,23 @@ export fn sourceLocationFileCoveredList(sli_file: SourceLocationIndex) Slice(Sou...@@ -406,19 +406,23 @@ export fn sourceLocationFileCoveredList(sli_file: SourceLocationIndex) Slice(Sou
406 };406 };
407 const want_file = sli_file.ptr().file;407 const want_file = sli_file.ptr().file;
408 global.result.clearRetainingCapacity();408 global.result.clearRetainingCapacity();
409 const covered_bits = recent_coverage_update.items[@sizeOf(abi.CoverageUpdateHeader)..];409
410 // This code assumes 64-bit elements, which is incorrect if the executable
411 // being fuzzed is not a 64-bit CPU. It also assumes little-endian which
412 // can also be incorrect.
413 comptime assert(abi.CoverageUpdateHeader.trailing[0] == .pc_bits_usize);
414 const n_bitset_elems = (coverage_source_locations.items.len + @bitSizeOf(u64) - 1) / @bitSizeOf(u64);
415 const covered_bits = std.mem.bytesAsSlice(
416 u64,
417 recent_coverage_update.items[@sizeOf(abi.CoverageUpdateHeader)..][0 .. n_bitset_elems * @sizeOf(u64)],
418 );
410 var sli: u32 = 0;419 var sli: u32 = 0;
411 for (covered_bits) |byte| {420 for (covered_bits) |elem| {
412 global.result.ensureUnusedCapacity(gpa, 8) catch @panic("OOM");421 global.result.ensureUnusedCapacity(gpa, 64) catch @panic("OOM");
413 if ((byte & 0b0000_0001) != 0) global.add(sli + 0, want_file);422 for (0..@bitSizeOf(u64)) |i| {
414 if ((byte & 0b0000_0010) != 0) global.add(sli + 1, want_file);423 if ((elem & (@as(u64, 1) << @intCast(i))) != 0) global.add(sli, want_file);
415 if ((byte & 0b0000_0100) != 0) global.add(sli + 2, want_file);424 sli += 1;
416 if ((byte & 0b0000_1000) != 0) global.add(sli + 3, want_file);425 }
417 if ((byte & 0b0001_0000) != 0) global.add(sli + 4, want_file);
418 if ((byte & 0b0010_0000) != 0) global.add(sli + 5, want_file);
419 if ((byte & 0b0100_0000) != 0) global.add(sli + 6, want_file);
420 if ((byte & 0b1000_0000) != 0) global.add(sli + 7, want_file);
421 sli += 8;
422 }426 }
423 return Slice(SourceLocationIndex).init(global.result.items);427 return Slice(SourceLocationIndex).init(global.result.items);
424}428}
lib/std/Build/Fuzz/WebServer.zig+6-7
...@@ -7,6 +7,7 @@ const Step = std.Build.Step;...@@ -7,6 +7,7 @@ const Step = std.Build.Step;
7const Coverage = std.debug.Coverage;7const Coverage = std.debug.Coverage;
8const abi = std.Build.Fuzz.abi;8const abi = std.Build.Fuzz.abi;
9const log = std.log;9const log = std.log;
10const assert = std.debug.assert;
1011
11const WebServer = @This();12const WebServer = @This();
1213
...@@ -383,7 +384,7 @@ fn sendCoverageContext(...@@ -383,7 +384,7 @@ fn sendCoverageContext(
383 // TODO: make each events URL correspond to one coverage map384 // TODO: make each events URL correspond to one coverage map
384 const coverage_map = &coverage_maps[0];385 const coverage_map = &coverage_maps[0];
385 const cov_header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);386 const cov_header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
386 const seen_pcs = coverage_map.mapped_memory[@sizeOf(abi.SeenPcsHeader) + coverage_map.source_locations.len * @sizeOf(usize) ..];387 const seen_pcs = cov_header.seenBits();
387 const n_runs = @atomicLoad(usize, &cov_header.n_runs, .monotonic);388 const n_runs = @atomicLoad(usize, &cov_header.n_runs, .monotonic);
388 const unique_runs = @atomicLoad(usize, &cov_header.unique_runs, .monotonic);389 const unique_runs = @atomicLoad(usize, &cov_header.unique_runs, .monotonic);
389 const lowest_stack = @atomicLoad(usize, &cov_header.lowest_stack, .monotonic);390 const lowest_stack = @atomicLoad(usize, &cov_header.lowest_stack, .monotonic);
...@@ -415,7 +416,7 @@ fn sendCoverageContext(...@@ -415,7 +416,7 @@ fn sendCoverageContext(
415 };416 };
416 const iovecs: [2]std.posix.iovec_const = .{417 const iovecs: [2]std.posix.iovec_const = .{
417 makeIov(std.mem.asBytes(&header)),418 makeIov(std.mem.asBytes(&header)),
418 makeIov(seen_pcs),419 makeIov(std.mem.sliceAsBytes(seen_pcs)),
419 };420 };
420 try web_socket.writeMessagev(&iovecs, .binary);421 try web_socket.writeMessagev(&iovecs, .binary);
421422
...@@ -630,8 +631,7 @@ fn prepareTables(...@@ -630,8 +631,7 @@ fn prepareTables(
630 gop.value_ptr.mapped_memory = mapped_memory;631 gop.value_ptr.mapped_memory = mapped_memory;
631632
632 const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);633 const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
633 const pcs_bytes = mapped_memory[@sizeOf(abi.SeenPcsHeader)..][0 .. header.pcs_len * @sizeOf(usize)];634 const pcs = header.pcAddrs();
634 const pcs = std.mem.bytesAsSlice(usize, pcs_bytes);
635 const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len);635 const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len);
636 errdefer gpa.free(source_locations);636 errdefer gpa.free(source_locations);
637 debug_info.resolveAddresses(gpa, pcs, source_locations) catch |err| {637 debug_info.resolveAddresses(gpa, pcs, source_locations) catch |err| {
...@@ -648,9 +648,8 @@ fn addEntryPoint(ws: *WebServer, coverage_id: u64, addr: u64) error{ AlreadyRepo...@@ -648,9 +648,8 @@ fn addEntryPoint(ws: *WebServer, coverage_id: u64, addr: u64) error{ AlreadyRepo
648 defer ws.coverage_mutex.unlock();648 defer ws.coverage_mutex.unlock();
649649
650 const coverage_map = ws.coverage_files.getPtr(coverage_id).?;650 const coverage_map = ws.coverage_files.getPtr(coverage_id).?;
651 const ptr = coverage_map.mapped_memory;651 const header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
652 const pcs_bytes = ptr[@sizeOf(abi.SeenPcsHeader)..][0 .. coverage_map.source_locations.len * @sizeOf(usize)];652 const pcs = header.pcAddrs();
653 const pcs: []const usize = @alignCast(std.mem.bytesAsSlice(usize, pcs_bytes));
654 const index = std.sort.upperBound(usize, pcs, addr, struct {653 const index = std.sort.upperBound(usize, pcs, addr, struct {
655 fn order(context: usize, item: usize) std.math.Order {654 fn order(context: usize, item: usize) std.math.Order {
656 return std.math.order(item, context);655 return std.math.order(item, context);
lib/std/Build/Fuzz/abi.zig+42-6
...@@ -7,13 +7,40 @@...@@ -7,13 +7,40 @@
7/// make the ints be the size of the target used with libfuzzer.7/// make the ints be the size of the target used with libfuzzer.
8///8///
9/// Trailing:9/// Trailing:
10/// * pc_addr: usize for each pcs_len
11/// * 1 bit per pc_addr, usize elements10/// * 1 bit per pc_addr, usize elements
11/// * pc_addr: usize for each pcs_len
12pub const SeenPcsHeader = extern struct {12pub const SeenPcsHeader = extern struct {
13 n_runs: usize,13 n_runs: usize,
14 unique_runs: usize,14 unique_runs: usize,
15 pcs_len: usize,15 pcs_len: usize,
16 lowest_stack: usize,16 lowest_stack: usize,
17
18 /// Used for comptime assertions. Provides a mechanism for strategically
19 /// causing compile errors.
20 pub const trailing = .{
21 .pc_bits_usize,
22 .pc_addr,
23 };
24
25 pub fn headerEnd(header: *const SeenPcsHeader) []const usize {
26 const ptr: [*]align(@alignOf(usize)) const u8 = @ptrCast(header);
27 const header_end_ptr: [*]const usize = @ptrCast(ptr + @sizeOf(SeenPcsHeader));
28 const pcs_len = header.pcs_len;
29 return header_end_ptr[0 .. pcs_len + seenElemsLen(pcs_len)];
30 }
31
32 pub fn seenBits(header: *const SeenPcsHeader) []const usize {
33 return header.headerEnd()[0..seenElemsLen(header.pcs_len)];
34 }
35
36 pub fn seenElemsLen(pcs_len: usize) usize {
37 return (pcs_len + @bitSizeOf(usize) - 1) / @bitSizeOf(usize);
38 }
39
40 pub fn pcAddrs(header: *const SeenPcsHeader) []const usize {
41 const pcs_len = header.pcs_len;
42 return header.headerEnd()[seenElemsLen(pcs_len)..][0..pcs_len];
43 }
17};44};
1845
19pub const ToClientTag = enum(u8) {46pub const ToClientTag = enum(u8) {
...@@ -47,12 +74,21 @@ pub const SourceIndexHeader = extern struct {...@@ -47,12 +74,21 @@ pub const SourceIndexHeader = extern struct {
47/// changes.74/// changes.
48///75///
49/// Trailing:76/// Trailing:
50/// * one bit per source_locations_len, contained in u8 elements77/// * one bit per source_locations_len, contained in u64 elements
51pub const CoverageUpdateHeader = extern struct {78pub const CoverageUpdateHeader = extern struct {
52 tag: ToClientTag = .coverage_update,79 flags: Flags = .{},
53 n_runs: u64 align(1),80 n_runs: u64,
54 unique_runs: u64 align(1),81 unique_runs: u64,
55 lowest_stack: u64 align(1),82 lowest_stack: u64,
83
84 pub const Flags = packed struct(u64) {
85 tag: ToClientTag = .coverage_update,
86 _: u56 = 0,
87 };
88
89 pub const trailing = .{
90 .pc_bits_usize,
91 };
56};92};
5793
58/// Sent to the fuzzer web client when the set of entry points is updated.94/// Sent to the fuzzer web client when the set of entry points is updated.
tools/dump-cov.zig+15-16
...@@ -5,6 +5,7 @@ const std = @import("std");...@@ -5,6 +5,7 @@ const std = @import("std");
5const fatal = std.process.fatal;5const fatal = std.process.fatal;
6const Path = std.Build.Cache.Path;6const Path = std.Build.Cache.Path;
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const SeenPcsHeader = std.Build.Fuzz.abi.SeenPcsHeader;
89
9pub fn main() !void {10pub fn main() !void {
10 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};11 var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
...@@ -36,24 +37,29 @@ pub fn main() !void {...@@ -36,24 +37,29 @@ pub fn main() !void {
36 };37 };
37 defer debug_info.deinit(gpa);38 defer debug_info.deinit(gpa);
3839
39 const cov_bytes = cov_path.root_dir.handle.readFileAlloc(arena, cov_path.sub_path, 1 << 30) catch |err| {40 const cov_bytes = cov_path.root_dir.handle.readFileAllocOptions(
41 arena,
42 cov_path.sub_path,
43 1 << 30,
44 null,
45 @alignOf(SeenPcsHeader),
46 null,
47 ) catch |err| {
40 fatal("failed to load coverage file {}: {s}", .{ cov_path, @errorName(err) });48 fatal("failed to load coverage file {}: {s}", .{ cov_path, @errorName(err) });
41 };49 };
4250
43 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());51 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
44 const stdout = bw.writer();52 const stdout = bw.writer();
4553
46 const header: *align(1) SeenPcsHeader = @ptrCast(cov_bytes);54 const header: *SeenPcsHeader = @ptrCast(cov_bytes);
47 try stdout.print("{any}\n", .{header.*});55 try stdout.print("{any}\n", .{header.*});
48 //const n_bitset_elems = (header.pcs_len + 7) / 8;56 const pcs = header.pcAddrs();
49 const pcs_bytes = cov_bytes[@sizeOf(SeenPcsHeader)..][0 .. header.pcs_len * @sizeOf(usize)];57 for (0.., pcs[0 .. pcs.len - 1], pcs[1..]) |i, a, b| {
50 const pcs = try arena.alloc(usize, header.pcs_len);58 if (a > b) std.log.err("{d}: 0x{x} > 0x{x}", .{ i, a, b });
51 for (0..pcs_bytes.len / @sizeOf(usize), pcs) |i, *pc| {
52 pc.* = std.mem.readInt(usize, pcs_bytes[i * @sizeOf(usize) ..][0..@sizeOf(usize)], .little);
53 }59 }
54 assert(std.sort.isSorted(usize, pcs, {}, std.sort.asc(usize)));60 assert(std.sort.isSorted(usize, pcs, {}, std.sort.asc(usize)));
5561
56 const seen_pcs = cov_bytes[@sizeOf(SeenPcsHeader) + pcs.len * @sizeOf(usize) ..];62 const seen_pcs = header.seenBits();
5763
58 const source_locations = try arena.alloc(std.debug.Coverage.SourceLocation, pcs.len);64 const source_locations = try arena.alloc(std.debug.Coverage.SourceLocation, pcs.len);
59 try debug_info.resolveAddresses(gpa, pcs, source_locations);65 try debug_info.resolveAddresses(gpa, pcs, source_locations);
...@@ -62,7 +68,7 @@ pub fn main() !void {...@@ -62,7 +68,7 @@ pub fn main() !void {
62 const file = debug_info.coverage.fileAt(sl.file);68 const file = debug_info.coverage.fileAt(sl.file);
63 const dir_name = debug_info.coverage.directories.keys()[file.directory_index];69 const dir_name = debug_info.coverage.directories.keys()[file.directory_index];
64 const dir_name_slice = debug_info.coverage.stringAt(dir_name);70 const dir_name_slice = debug_info.coverage.stringAt(dir_name);
65 const hit: u1 = @truncate(seen_pcs[i / 8] >> @intCast(i % 8));71 const hit: u1 = @truncate(seen_pcs[i / @bitSizeOf(usize)] >> @intCast(i % @bitSizeOf(usize)));
66 try stdout.print("{c}{x}: {s}/{s}:{d}:{d}\n", .{72 try stdout.print("{c}{x}: {s}/{s}:{d}:{d}\n", .{
67 "-+"[hit], pc, dir_name_slice, debug_info.coverage.stringAt(file.basename), sl.line, sl.column,73 "-+"[hit], pc, dir_name_slice, debug_info.coverage.stringAt(file.basename), sl.line, sl.column,
68 });74 });
...@@ -70,10 +76,3 @@ pub fn main() !void {...@@ -70,10 +76,3 @@ pub fn main() !void {
7076
71 try bw.flush();77 try bw.flush();
72}78}
73
74const SeenPcsHeader = extern struct {
75 n_runs: usize,
76 deduplicated_runs: usize,
77 pcs_len: usize,
78 lowest_stack: usize,
79};