| author | |
| committer | |
| log | 7889c08151d266f2b513e3e5f223ee6b870b13eb |
| tree | 6ebf1f36bceedc0dd90df464fe79803da8ab2bbb |
| parent | 0b9d6ad04246a3aa87ed63a699a25910020bff48 |
5 files changed, 96 insertions(+), 14 deletions(-)
lib/compiler/test_runner.zig+2-1| ... | @@ -152,7 +152,8 @@ fn mainServer() !void { | ... | @@ -152,7 +152,8 @@ fn mainServer() !void { |
| 152 | const index = try server.receiveBody_u32(); | 152 | const index = try server.receiveBody_u32(); |
| 153 | const test_fn = builtin.test_functions[index]; | 153 | const test_fn = builtin.test_functions[index]; |
| 154 | const entry_addr = @intFromPtr(test_fn.func); | 154 | 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); | ||
| 156 | defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1); | 157 | defer if (testing.allocator_instance.deinit() == .leak) std.process.exit(1); |
| 157 | is_fuzz_test = false; | 158 | is_fuzz_test = false; |
| 158 | fuzzer_set_name(test_fn.name.ptr, test_fn.name.len); | 159 | fuzzer_set_name(test_fn.name.ptr, test_fn.name.len); |
lib/fuzzer.zig+10-3| ... | @@ -208,7 +208,12 @@ const Fuzzer = struct { | ... | @@ -208,7 +208,12 @@ const Fuzzer = struct { |
| 208 | }; | 208 | }; |
| 209 | f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&header)); | 209 | f.seen_pcs.appendSliceAssumeCapacity(std.mem.asBytes(&header)); |
| 210 | f.seen_pcs.appendNTimesAssumeCapacity(0, n_bitset_elems * @sizeOf(usize)); | 210 | 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 | } | ||
| 212 | } | 217 | } |
| 213 | } | 218 | } |
| 214 | 219 | ||
| ... | @@ -310,19 +315,21 @@ const Fuzzer = struct { | ... | @@ -310,19 +315,21 @@ const Fuzzer = struct { |
| 310 | f.input.clearRetainingCapacity(); | 315 | f.input.clearRetainingCapacity(); |
| 311 | const old_input = f.corpus.items[corpus_index].bytes; | 316 | const old_input = f.corpus.items[corpus_index].bytes; |
| 312 | f.input.ensureTotalCapacity(old_input.len + 1) catch @panic("mmap file resize failed"); | 317 | f.input.ensureTotalCapacity(old_input.len + 1) catch @panic("mmap file resize failed"); |
| 313 | switch (mutation) { | 318 | mut: switch (mutation) { |
| 314 | .remove_byte => { | 319 | .remove_byte => { |
| 320 | if (old_input.len == 0) continue :mut .add_byte; | ||
| 315 | const omitted_index = rng.uintLessThanBiased(usize, old_input.len); | 321 | const omitted_index = rng.uintLessThanBiased(usize, old_input.len); |
| 316 | f.input.appendSliceAssumeCapacity(old_input[0..omitted_index]); | 322 | f.input.appendSliceAssumeCapacity(old_input[0..omitted_index]); |
| 317 | f.input.appendSliceAssumeCapacity(old_input[omitted_index + 1 ..]); | 323 | f.input.appendSliceAssumeCapacity(old_input[omitted_index + 1 ..]); |
| 318 | }, | 324 | }, |
| 319 | .modify_byte => { | 325 | .modify_byte => { |
| 326 | if (old_input.len == 0) continue :mut .add_byte; | ||
| 320 | const modified_index = rng.uintLessThanBiased(usize, old_input.len); | 327 | const modified_index = rng.uintLessThanBiased(usize, old_input.len); |
| 321 | f.input.appendSliceAssumeCapacity(old_input); | 328 | f.input.appendSliceAssumeCapacity(old_input); |
| 322 | f.input.items[modified_index] = rng.int(u8); | 329 | f.input.items[modified_index] = rng.int(u8); |
| 323 | }, | 330 | }, |
| 324 | .add_byte => { | 331 | .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); |
| 326 | f.input.appendSliceAssumeCapacity(old_input[0..modified_index]); | 333 | f.input.appendSliceAssumeCapacity(old_input[0..modified_index]); |
| 327 | f.input.appendAssumeCapacity(rng.int(u8)); | 334 | f.input.appendAssumeCapacity(rng.int(u8)); |
| 328 | f.input.appendSliceAssumeCapacity(old_input[modified_index..]); | 335 | f.input.appendSliceAssumeCapacity(old_input[modified_index..]); |
lib/std/debug/Info.zig+77-8| ... | @@ -7,6 +7,7 @@ | ... | @@ -7,6 +7,7 @@ |
| 7 | //! properties. | 7 | //! properties. |
| 8 | 8 | ||
| 9 | const std = @import("../std.zig"); | 9 | const std = @import("../std.zig"); |
| 10 | const builtin = @import("builtin"); | ||
| 10 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| 11 | const Path = std.Build.Cache.Path; | 12 | const Path = std.Build.Cache.Path; |
| 12 | const Dwarf = std.debug.Dwarf; | 13 | const Dwarf = std.debug.Dwarf; |
| ... | @@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation; | ... | @@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation; |
| 17 | const Info = @This(); | 18 | const Info = @This(); |
| 18 | 19 | ||
| 19 | /// Sorted by key, ascending. | 20 | /// Sorted by key, ascending. |
| 20 | address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule), | 21 | address_map: std.AutoArrayHashMapUnmanaged(u64, std.debug.SelfInfo.Module), |
| 21 | /// Externally managed, outlives this `Info` instance. | 22 | /// Externally managed, outlives this `Info` instance. |
| 22 | coverage: *Coverage, | 23 | coverage: *Coverage, |
| 23 | 24 | ||
| ... | @@ -25,19 +26,40 @@ pub const LoadError = Dwarf.ElfModule.LoadError; | ... | @@ -25,19 +26,40 @@ pub const LoadError = Dwarf.ElfModule.LoadError; |
| 25 | 26 | ||
| 26 | pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info { | 27 | pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info { |
| 27 | var sections: Dwarf.SectionArray = Dwarf.null_section_array; | 28 | 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); | ||
| 30 | var info: Info = .{ | 29 | var info: Info = .{ |
| 31 | .address_map = .{}, | 30 | .address_map = .{}, |
| 32 | .coverage = coverage, | 31 | .coverage = coverage, |
| 33 | }; | 32 | }; |
| 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 | } | ||
| 35 | return info; | 57 | return info; |
| 36 | } | 58 | } |
| 37 | 59 | ||
| 38 | pub fn deinit(info: *Info, gpa: Allocator) void { | 60 | pub fn deinit(info: *Info, gpa: Allocator) void { |
| 39 | for (info.address_map.values()) |*elf_module| { | 61 | for (info.address_map.values()) |*module| { |
| 40 | elf_module.dwarf.deinit(gpa); | 62 | module.deinit(gpa); |
| 41 | } | 63 | } |
| 42 | info.address_map.deinit(gpa); | 64 | info.address_map.deinit(gpa); |
| 43 | info.* = undefined; | 65 | info.* = undefined; |
| ... | @@ -57,6 +79,53 @@ pub fn resolveAddresses( | ... | @@ -57,6 +79,53 @@ pub fn resolveAddresses( |
| 57 | ) ResolveAddressesError!void { | 79 | ) ResolveAddressesError!void { |
| 58 | assert(sorted_pc_addrs.len == output.len); | 80 | assert(sorted_pc_addrs.len == output.len); |
| 59 | if (info.address_map.entries.len != 1) @panic("TODO"); | 81 | if (info.address_map.entries.len != 1) @panic("TODO"); |
| 60 | const elf_module = &info.address_map.values()[0]; | 82 | |
| 61 | return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf); | 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 | } | ||
| 62 | } | 131 | } |
lib/std/debug/SelfInfo.zig+1-1| ... | @@ -860,7 +860,7 @@ pub const WindowsModule = struct { | ... | @@ -860,7 +860,7 @@ pub const WindowsModule = struct { |
| 860 | /// This takes ownership of macho_file: users of this function should not close | 860 | /// This takes ownership of macho_file: users of this function should not close |
| 861 | /// it themselves, even on error. | 861 | /// it themselves, even on error. |
| 862 | /// TODO it's weird to take ownership even on error, rework this code. | 862 | /// TODO it's weird to take ownership even on error, rework this code. |
| 863 | fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module { | 863 | pub fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module { |
| 864 | const mapped_mem = try mapWholeFile(macho_file); | 864 | const mapped_mem = try mapWholeFile(macho_file); |
| 865 | 865 | ||
| 866 | const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr)); | 866 | 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( | ... | @@ -416,7 +416,12 @@ pub fn flushModule( |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | if (comp.config.any_fuzz) { | 418 | 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 | )); | ||
| 420 | } | 425 | } |
| 421 | 426 | ||
| 422 | if (comp.ubsan_rt_lib) |crt_file| { | 427 | if (comp.ubsan_rt_lib) |crt_file| { |