diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig index 87cd7a1a1d..a30b67eeae 100644 --- a/lib/std/Build/Fuzz/WebServer.zig +++ b/lib/std/Build/Fuzz/WebServer.zig @@ -582,6 +582,7 @@ fn prepareTables( ws.coverage_mutex.lock(); defer ws.coverage_mutex.unlock(); + std.debug.print("SET {}\n", .{coverage_id}); const gop = try ws.coverage_files.getOrPut(gpa, coverage_id); if (gop.found_existing) { // We are fuzzing the same executable with multiple threads. @@ -676,6 +677,7 @@ fn addEntryPoint(ws: *WebServer, coverage_id: u64, addr: u64) error{ AlreadyRepo ws.coverage_mutex.lock(); defer ws.coverage_mutex.unlock(); + std.debug.print("GET {}\n", .{coverage_id}); const coverage_map = ws.coverage_files.getPtr(coverage_id).?; const header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]); const pcs = header.pcAddrs(); diff --git a/lib/std/debug/Info.zig b/lib/std/debug/Info.zig index c809547f73..550ae27e96 100644 --- a/lib/std/debug/Info.zig +++ b/lib/std/debug/Info.zig @@ -7,6 +7,7 @@ //! properties. const std = @import("../std.zig"); +const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const Path = std.Build.Cache.Path; const Dwarf = std.debug.Dwarf; @@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation; const Info = @This(); /// Sorted by key, ascending. -address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule), +address_map: std.AutoArrayHashMapUnmanaged(u64, std.debug.SelfInfo.Module), /// Externally managed, outlives this `Info` instance. coverage: *Coverage, @@ -25,20 +26,41 @@ pub const LoadError = Dwarf.ElfModule.LoadError; 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, §ions, null); - try elf_module.dwarf.populateRanges(gpa); var info: Info = .{ .address_map = .{}, .coverage = coverage, }; - try info.address_map.put(gpa, elf_module.base_address, elf_module); + switch (builtin.os.tag) { + .linux => { + var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, §ions, null); + try elf_module.dwarf.populateRanges(gpa); + try info.address_map.put(gpa, elf_module.base_address, elf_module); + }, + .macos => { + const macho_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| switch (err) { + error.FileNotFound => return error.MissingDebugInfo, + else => return error.InvalidDebugInfo, + }; + // readMachoDebugInfo takes ownership of the file + // defer elf_file.close(); + var module = std.debug.SelfInfo.readMachODebugInfo(gpa, macho_file) catch { + return error.InvalidDebugInfo; + }; + + module.base_address = 0; + module.vmaddr_slide = 0; + + try info.address_map.put(gpa, 0, module); + }, + else => @compileError("TODO: implement debug info loading for the target platform"), + } return info; } pub fn deinit(info: *Info, gpa: Allocator) void { - for (info.address_map.values()) |*elf_module| { - elf_module.dwarf.deinit(gpa); - } + // for (info.address_map.values()) |*module| { + // module.dwarf.deinit(gpa); + // } info.address_map.deinit(gpa); info.* = undefined; } @@ -57,6 +79,38 @@ pub fn resolveAddresses( ) 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 info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf); + switch (builtin.os.tag) { + else => @compileError("unsupported"), + .linux => { + const elf_module = &info.address_map.values()[0]; + return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf); + }, + .macos => { + const module = &info.address_map.values()[0]; + + var idx: usize = 0; + while (idx < sorted_pc_addrs.len) { + const dw = (module.getDwarfInfoForAddress(gpa, sorted_pc_addrs[idx]) catch return error.InvalidDebugInfo).?; + try dw.populateRanges(gpa); + const last = dw.ranges.getLastOrNull() orelse return; + var end_idx = idx; + while (end_idx < sorted_pc_addrs.len and + sorted_pc_addrs[end_idx] < last.end) end_idx += 1; + + if (end_idx == idx) { + std.debug.print("made no progress", .{}); + return; + } + + try info.coverage.resolveAddressesDwarf( + gpa, + sorted_pc_addrs[idx..end_idx], + output[idx..end_idx], + dw, + ); + + idx = end_idx; + } + }, + } } diff --git a/lib/std/debug/SelfInfo.zig b/lib/std/debug/SelfInfo.zig index ea7ecac4ed..df0fd01642 100644 --- a/lib/std/debug/SelfInfo.zig +++ b/lib/std/debug/SelfInfo.zig @@ -687,18 +687,28 @@ pub const Module = switch (native_os) { // Check if its debug infos are already in the cache const o_file_path = mem.sliceTo(self.strings[symbol.ofile..], 0); - const o_file_info = self.ofiles.getPtr(o_file_path) orelse - (self.loadOFile(allocator, o_file_path) catch |err| switch (err) { - error.FileNotFound, - error.MissingDebugInfo, - error.InvalidDebugInfo, - => return .{ - .relocated_address = relocated_address, - .symbol = symbol, - }, - else => return err, - }); + std.debug.print("loading '{s}'\n", .{o_file_path}); + + const clean_name = if (std.mem.endsWith(u8, o_file_path, ".a.o)")) blk: { + var it = std.mem.tokenizeScalar(u8, o_file_path, '('); + break :blk std.fmt.allocPrint(allocator, "{s}.o", .{it.next().?}) catch unreachable; + } else o_file_path; + std.debug.print("clean '{s}'\n", .{clean_name}); + + const o_file_info = self.ofiles.getPtr(clean_name) orelse + (self.loadOFile(allocator, clean_name) catch |err| switch (err) { + error.FileNotFound, + error.MissingDebugInfo, + error.InvalidDebugInfo, + => return .{ + .relocated_address = relocated_address, + .symbol = symbol, + }, + else => return err, + }); + + std.debug.print("success\n", .{}); return .{ .relocated_address = relocated_address, .symbol = symbol, @@ -846,7 +856,7 @@ pub const WindowsModule = struct { /// This takes ownership of macho_file: users of this function should not close /// it themselves, even on error. /// TODO it's weird to take ownership even on error, rework this code. -fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module { +pub fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module { const mapped_mem = try mapWholeFile(macho_file); const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr));