authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2025-05-03 20:46:40+02:00
committergravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2025-05-03 20:46:40+02:00
log7889c08151d266f2b513e3e5f223ee6b870b13eb
tree6ebf1f36bceedc0dd90df464fe79803da8ab2bbb
parent0b9d6ad04246a3aa87ed63a699a25910020bff48

wip


5 files changed, 96 insertions(+), 14 deletions(-)

lib/compiler/test_runner.zig+2-1
......@@ -152,7 +152,8 @@ fn mainServer() !void {
152152 const index = try server.receiveBody_u32();
153153 const test_fn = builtin.test_functions[index];
154154 const entry_addr = @intFromPtr(test_fn.func);
155 try server.serveU64Message(.fuzz_start_addr, entry_addr);
155 const offset = std.c._dyld_get_image_vmaddr_slide(0);
156 try server.serveU64Message(.fuzz_start_addr, entry_addr - offset);
156157 defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1);
157158 is_fuzz_test = false;
158159 fuzzer_set_name(test_fn.name.ptr, test_fn.name.len);
lib/fuzzer.zig+10-3
......@@ -208,7 +208,12 @@ const Fuzzer = struct {
208208 };
209209 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&header));
210210 f.seen_pcs.appendNTimesAssumeCapacity(0, n_bitset_elems * @sizeOf(usize));
211 f.seen_pcs.appendSliceAssumeCapacity(std.mem.sliceAsBytes(pcs));
211
212 const offset = std.c._dyld_get_image_vmaddr_slide(0);
213 for (pcs) |pc| {
214 const value = pc - offset;
215 f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&value));
216 }
212217 }
213218 }
214219
......@@ -310,19 +315,21 @@ const Fuzzer = struct {
310315 f.input.clearRetainingCapacity();
311316 const old_input = f.corpus.items[corpus_index].bytes;
312317 f.input.ensureTotalCapacity(old_input.len + 1) catch @panic("mmap file resize failed");
313 switch (mutation) {
318 mut: switch (mutation) {
314319 .remove_byte => {
320 if (old_input.len == 0) continue :mut .add_byte;
315321 const omitted_index = rng.uintLessThanBiased(usize, old_input.len);
316322 f.input.appendSliceAssumeCapacity(old_input[0..omitted_index]);
317323 f.input.appendSliceAssumeCapacity(old_input[omitted_index + 1 ..]);
318324 },
319325 .modify_byte => {
326 if (old_input.len == 0) continue :mut .add_byte;
320327 const modified_index = rng.uintLessThanBiased(usize, old_input.len);
321328 f.input.appendSliceAssumeCapacity(old_input);
322329 f.input.items[modified_index] = rng.int(u8);
323330 },
324331 .add_byte => {
325 const modified_index = rng.uintLessThanBiased(usize, old_input.len);
332 const modified_index = if (old_input.len == 0) 0 else rng.uintLessThanBiased(usize, old_input.len);
326333 f.input.appendSliceAssumeCapacity(old_input[0..modified_index]);
327334 f.input.appendAssumeCapacity(rng.int(u8));
328335 f.input.appendSliceAssumeCapacity(old_input[modified_index..]);
lib/std/debug/Info.zig+77-8
......@@ -7,6 +7,7 @@
77//! properties.
88
99const std = @import("../std.zig");
10const builtin = @import("builtin");
1011const Allocator = std.mem.Allocator;
1112const Path = std.Build.Cache.Path;
1213const Dwarf = std.debug.Dwarf;
......@@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation;
1718const Info = @This();
1819
1920/// Sorted by key, ascending.
20address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule),
21address_map: std.AutoArrayHashMapUnmanaged(u64, std.debug.SelfInfo.Module),
2122/// Externally managed, outlives this `Info` instance.
2223coverage: *Coverage,
2324
......@@ -25,19 +26,40 @@ pub const LoadError = Dwarf.ElfModule.LoadError;
2526
2627pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info {
2728 var sections: Dwarf.SectionArray = Dwarf.null_section_array;
28 var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null);
29 try elf_module.dwarf.populateRanges(gpa);
3029 var info: Info = .{
3130 .address_map = .{},
3231 .coverage = coverage,
3332 };
34 try info.address_map.put(gpa, elf_module.base_address, elf_module);
33 switch (builtin.os.tag) {
34 .linux => {
35 var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null);
36 try elf_module.dwarf.populateRanges(gpa);
37 try info.address_map.put(gpa, elf_module.base_address, elf_module);
38 },
39 .macos => {
40 const macho_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| switch (err) {
41 error.FileNotFound => return error.MissingDebugInfo,
42 else => return error.InvalidDebugInfo,
43 };
44 // readMachoDebugInfo takes ownership of the file
45 // defer elf_file.close();
46 var module = std.debug.SelfInfo.readMachODebugInfo(gpa, macho_file) catch {
47 return error.InvalidDebugInfo;
48 };
49
50 module.base_address = 0;
51 module.vmaddr_slide = 0;
52
53 try info.address_map.put(gpa, 0, module);
54 },
55 else => @compileError("TODO: implement debug info loading for the target platform"),
56 }
3557 return info;
3658}
3759
3860pub fn deinit(info: *Info, gpa: Allocator) void {
39 for (info.address_map.values()) |*elf_module| {
40 elf_module.dwarf.deinit(gpa);
61 for (info.address_map.values()) |*module| {
62 module.deinit(gpa);
4163 }
4264 info.address_map.deinit(gpa);
4365 info.* = undefined;
......@@ -57,6 +79,53 @@ pub fn resolveAddresses(
5779) ResolveAddressesError!void {
5880 assert(sorted_pc_addrs.len == output.len);
5981 if (info.address_map.entries.len != 1) @panic("TODO");
60 const elf_module = &info.address_map.values()[0];
61 return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf);
82
83 switch (builtin.os.tag) {
84 else => @compileError("unsupported"),
85 .linux => {
86 const elf_module = &info.address_map.values()[0];
87 return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf);
88 },
89 .macos => {
90 const module = &info.address_map.values()[0];
91
92 var idx: usize = 0;
93 while (idx < sorted_pc_addrs.len) : (idx += 1) {
94 const ofile = (module.getOFileInfoForAddress(gpa, sorted_pc_addrs[idx]) catch return error.InvalidDebugInfo);
95 if (ofile.o_file_info.?.di.ranges.items.len == 0) {
96 try ofile.o_file_info.?.di.populateRanges(gpa);
97 }
98 // const last = ofile.ranges.getLastOrNull() orelse return;
99 // var end_idx = idx;
100 // while (end_idx < sorted_pc_addrs.len and
101 // sorted_pc_addrs[end_idx] < last.end) end_idx += 1;
102
103 // if (end_idx == idx) {
104 // std.debug.panic("made no progress", .{});
105 // }
106 //
107
108 const stab_symbol = std.mem.sliceTo(module.strings[ofile.symbol.?.strx..], 0);
109 const offset = ofile.relocated_address - ofile.symbol.?.addr;
110 // Translate again the address, this time into an address inside the
111 // .o file
112 const relocated_address_o = ofile.o_file_info.?.addr_table.get(stab_symbol) orelse @panic("error");
113
114 try info.coverage.resolveAddressesDwarf(
115 gpa,
116 &.{relocated_address_o + offset},
117 output[idx..][0..1],
118 &ofile.o_file_info.?.di,
119 );
120
121 // std.debug.print("{x} -> {x} -> {}\n", .{
122 // sorted_pc_addrs[idx],
123 // relocated_address_o + offset,
124 // output[idx],
125 // });
126
127 // idx = end_idx;
128 }
129 },
130 }
62131}
lib/std/debug/SelfInfo.zig+1-1
......@@ -860,7 +860,7 @@ pub const WindowsModule = struct {
860860/// This takes ownership of macho_file: users of this function should not close
861861/// it themselves, even on error.
862862/// TODO it's weird to take ownership even on error, rework this code.
863fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {
863pub fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {
864864 const mapped_mem = try mapWholeFile(macho_file);
865865
866866 const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr));
src/link/MachO.zig+6-1
......@@ -416,7 +416,12 @@ pub fn flushModule(
416416 }
417417
418418 if (comp.config.any_fuzz) {
419 try positionals.append(try link.openObjectInput(diags, comp.fuzzer_lib.?.full_object_path));
419 try positionals.append(try link.openArchiveInput(
420 diags,
421 comp.fuzzer_lib.?.full_object_path,
422 true,
423 false,
424 ));
420425 }
421426
422427 if (comp.ubsan_rt_lib) |crt_file| {