aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug/Info.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-08-04 00:16:28 -0700
committerAndrew Kelley <andrew@ziglang.org>2024-08-07 00:48:32 -0700
commit517cfb0dd1e2b5b8efc8e90ce4e5593a38fa158c (patch)
treeb630ec6fa767f2aaf6932472a8acb85ac5089cf5 /lib/std/debug/Info.zig
parent5f92a036f9a9a137e4276d0f605e4cb940eca3a7 (diff)
downloadzig-517cfb0dd1e2b5b8efc8e90ce4e5593a38fa158c.tar.gz
zig-517cfb0dd1e2b5b8efc8e90ce4e5593a38fa158c.zip
fuzzing: progress towards web UI
* libfuzzer: close file after mmap * fuzzer/main.js: connect with EventSource and debug dump the messages. currently this prints how many fuzzer runs have been attempted to console.log. * extract some `std.debug.Info` logic into `std.debug.Coverage`. Prepares for consolidation across multiple different executables which share source files, and makes it possible to send all the PC/SourceLocation mapping data with 4 memcpy'd arrays. * std.Build.Fuzz: - spawn a thread to watch the message queue and signal event subscribers. - track coverage map data - respond to /events URL with EventSource messages on a timer
Diffstat (limited to 'lib/std/debug/Info.zig')
-rw-r--r--lib/std/debug/Info.zig153
1 files changed, 10 insertions, 143 deletions
diff --git a/lib/std/debug/Info.zig b/lib/std/debug/Info.zig
index a52de6549b..ee191d2c12 100644
--- a/lib/std/debug/Info.zig
+++ b/lib/std/debug/Info.zig
@@ -12,85 +12,31 @@ const Path = std.Build.Cache.Path;
const Dwarf = std.debug.Dwarf;
const page_size = std.mem.page_size;
const assert = std.debug.assert;
-const Hash = std.hash.Wyhash;
+const Coverage = std.debug.Coverage;
+const SourceLocation = std.debug.Coverage.SourceLocation;
const Info = @This();
/// Sorted by key, ascending.
address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule),
-
-/// Provides a globally-scoped integer index for directories.
-///
-/// As opposed to, for example, a directory index that is compilation-unit
-/// scoped inside a single ELF module.
-///
-/// String memory references the memory-mapped debug information.
-///
-/// Protected by `mutex`.
-directories: std.StringArrayHashMapUnmanaged(void),
-/// Provides a globally-scoped integer index for files.
-///
-/// String memory references the memory-mapped debug information.
-///
-/// Protected by `mutex`.
-files: std.ArrayHashMapUnmanaged(File, void, File.MapContext, false),
-/// Protects `directories` and `files`.
-mutex: std.Thread.Mutex,
-
-pub const SourceLocation = struct {
- file: File.Index,
- line: u32,
- column: u32,
-
- pub const invalid: SourceLocation = .{
- .file = .invalid,
- .line = 0,
- .column = 0,
- };
-};
-
-pub const File = struct {
- directory_index: u32,
- basename: []const u8,
-
- pub const Index = enum(u32) {
- invalid = std.math.maxInt(u32),
- _,
- };
-
- pub const MapContext = struct {
- pub fn hash(ctx: MapContext, a: File) u32 {
- _ = ctx;
- return @truncate(Hash.hash(a.directory_index, a.basename));
- }
-
- pub fn eql(ctx: MapContext, a: File, b: File, b_index: usize) bool {
- _ = ctx;
- _ = b_index;
- return a.directory_index == b.directory_index and std.mem.eql(u8, a.basename, b.basename);
- }
- };
-};
+/// Externally managed, outlives this `Info` instance.
+coverage: *Coverage,
pub const LoadError = Dwarf.ElfModule.LoadError;
-pub fn load(gpa: Allocator, path: Path) LoadError!Info {
+pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info {
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null);
try elf_module.dwarf.sortCompileUnits();
var info: Info = .{
.address_map = .{},
- .directories = .{},
- .files = .{},
- .mutex = .{},
+ .coverage = coverage,
};
try info.address_map.put(gpa, elf_module.base_address, elf_module);
return info;
}
pub fn deinit(info: *Info, gpa: Allocator) void {
- info.directories.deinit(gpa);
- info.files.deinit(gpa);
for (info.address_map.values()) |*elf_module| {
elf_module.dwarf.deinit(gpa);
}
@@ -98,98 +44,19 @@ pub fn deinit(info: *Info, gpa: Allocator) void {
info.* = undefined;
}
-pub fn fileAt(info: *Info, index: File.Index) *File {
- return &info.files.keys()[@intFromEnum(index)];
-}
-
-pub const ResolveSourceLocationsError = Dwarf.ScanError;
+pub const ResolveAddressesError = Coverage.ResolveAddressesDwarfError;
/// Given an array of virtual memory addresses, sorted ascending, outputs a
/// corresponding array of source locations.
-pub fn resolveSourceLocations(
+pub fn resolveAddresses(
info: *Info,
gpa: Allocator,
sorted_pc_addrs: []const u64,
/// Asserts its length equals length of `sorted_pc_addrs`.
output: []SourceLocation,
-) ResolveSourceLocationsError!void {
+) ResolveAddressesError!void {
assert(sorted_pc_addrs.len == output.len);
if (info.address_map.entries.len != 1) @panic("TODO");
const elf_module = &info.address_map.values()[0];
- return resolveSourceLocationsDwarf(info, gpa, sorted_pc_addrs, output, &elf_module.dwarf);
-}
-
-pub fn resolveSourceLocationsDwarf(
- info: *Info,
- gpa: Allocator,
- sorted_pc_addrs: []const u64,
- /// Asserts its length equals length of `sorted_pc_addrs`.
- output: []SourceLocation,
- d: *Dwarf,
-) ResolveSourceLocationsError!void {
- assert(sorted_pc_addrs.len == output.len);
- assert(d.compile_units_sorted);
-
- var cu_i: usize = 0;
- var line_table_i: usize = 0;
- var cu: *Dwarf.CompileUnit = &d.compile_unit_list.items[0];
- var range = cu.pc_range.?;
- // Protects directories and files tables from other threads.
- info.mutex.lock();
- defer info.mutex.unlock();
- next_pc: for (sorted_pc_addrs, output) |pc, *out| {
- while (pc >= range.end) {
- cu_i += 1;
- if (cu_i >= d.compile_unit_list.items.len) {
- out.* = SourceLocation.invalid;
- continue :next_pc;
- }
- cu = &d.compile_unit_list.items[cu_i];
- line_table_i = 0;
- range = cu.pc_range orelse {
- out.* = SourceLocation.invalid;
- continue :next_pc;
- };
- }
- if (pc < range.start) {
- out.* = SourceLocation.invalid;
- continue :next_pc;
- }
- if (line_table_i == 0) {
- line_table_i = 1;
- info.mutex.unlock();
- defer info.mutex.lock();
- d.populateSrcLocCache(gpa, cu) catch |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => {
- out.* = SourceLocation.invalid;
- cu_i += 1;
- if (cu_i < d.compile_unit_list.items.len) {
- cu = &d.compile_unit_list.items[cu_i];
- line_table_i = 0;
- if (cu.pc_range) |r| range = r;
- }
- continue :next_pc;
- },
- else => |e| return e,
- };
- }
- const slc = &cu.src_loc_cache.?;
- const table_addrs = slc.line_table.keys();
- while (line_table_i < table_addrs.len and table_addrs[line_table_i] < pc) line_table_i += 1;
-
- const entry = slc.line_table.values()[line_table_i - 1];
- const corrected_file_index = entry.file - @intFromBool(slc.version < 5);
- const file_entry = slc.files[corrected_file_index];
- const dir_path = slc.directories[file_entry.dir_index].path;
- const dir_gop = try info.directories.getOrPut(gpa, dir_path);
- const file_gop = try info.files.getOrPut(gpa, .{
- .directory_index = @intCast(dir_gop.index),
- .basename = file_entry.path,
- });
- out.* = .{
- .file = @enumFromInt(file_gop.index),
- .line = entry.line,
- .column = entry.column,
- };
- }
+ return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf);
}