mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
wip
this is a bad commit that contains work in progress changes to make fuzzing on macos work. more specifically it contains macho-specific code for loading debug information in the webserver. it's messy because I'm still trying to understand how this stuff works. with these changes the web server loads but the wasm code panics. it's unclear if the wasm panic is due to my dwarf loading code being wrong or if we're encountering some other latent issue.
This commit is contained in:
parent
f8fe503146
commit
7a50e76eb1
@ -582,6 +582,7 @@ fn prepareTables(
|
|||||||
ws.coverage_mutex.lock();
|
ws.coverage_mutex.lock();
|
||||||
defer ws.coverage_mutex.unlock();
|
defer ws.coverage_mutex.unlock();
|
||||||
|
|
||||||
|
std.debug.print("SET {}\n", .{coverage_id});
|
||||||
const gop = try ws.coverage_files.getOrPut(gpa, coverage_id);
|
const gop = try ws.coverage_files.getOrPut(gpa, coverage_id);
|
||||||
if (gop.found_existing) {
|
if (gop.found_existing) {
|
||||||
// We are fuzzing the same executable with multiple threads.
|
// 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();
|
ws.coverage_mutex.lock();
|
||||||
defer ws.coverage_mutex.unlock();
|
defer ws.coverage_mutex.unlock();
|
||||||
|
|
||||||
|
std.debug.print("GET {}\n", .{coverage_id});
|
||||||
const coverage_map = ws.coverage_files.getPtr(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 header: *const abi.SeenPcsHeader = @ptrCast(coverage_map.mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
|
||||||
const pcs = header.pcAddrs();
|
const pcs = header.pcAddrs();
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//! properties.
|
//! properties.
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
|
const builtin = @import("builtin");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Path = std.Build.Cache.Path;
|
const Path = std.Build.Cache.Path;
|
||||||
const Dwarf = std.debug.Dwarf;
|
const Dwarf = std.debug.Dwarf;
|
||||||
@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation;
|
|||||||
const Info = @This();
|
const Info = @This();
|
||||||
|
|
||||||
/// Sorted by key, ascending.
|
/// 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.
|
/// Externally managed, outlives this `Info` instance.
|
||||||
coverage: *Coverage,
|
coverage: *Coverage,
|
||||||
|
|
||||||
@ -25,20 +26,41 @@ pub const LoadError = Dwarf.ElfModule.LoadError;
|
|||||||
|
|
||||||
pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info {
|
pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info {
|
||||||
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
|
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 = .{
|
var info: Info = .{
|
||||||
.address_map = .{},
|
.address_map = .{},
|
||||||
.coverage = coverage,
|
.coverage = coverage,
|
||||||
};
|
};
|
||||||
|
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);
|
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;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(info: *Info, gpa: Allocator) void {
|
pub fn deinit(info: *Info, gpa: Allocator) void {
|
||||||
for (info.address_map.values()) |*elf_module| {
|
// for (info.address_map.values()) |*module| {
|
||||||
elf_module.dwarf.deinit(gpa);
|
// module.dwarf.deinit(gpa);
|
||||||
}
|
// }
|
||||||
info.address_map.deinit(gpa);
|
info.address_map.deinit(gpa);
|
||||||
info.* = undefined;
|
info.* = undefined;
|
||||||
}
|
}
|
||||||
@ -57,6 +79,38 @@ pub fn resolveAddresses(
|
|||||||
) ResolveAddressesError!void {
|
) ResolveAddressesError!void {
|
||||||
assert(sorted_pc_addrs.len == output.len);
|
assert(sorted_pc_addrs.len == output.len);
|
||||||
if (info.address_map.entries.len != 1) @panic("TODO");
|
if (info.address_map.entries.len != 1) @panic("TODO");
|
||||||
|
switch (builtin.os.tag) {
|
||||||
|
else => @compileError("unsupported"),
|
||||||
|
.linux => {
|
||||||
const elf_module = &info.address_map.values()[0];
|
const elf_module = &info.address_map.values()[0];
|
||||||
return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf);
|
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;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -687,8 +687,17 @@ pub const Module = switch (native_os) {
|
|||||||
|
|
||||||
// Check if its debug infos are already in the cache
|
// Check if its debug infos are already in the cache
|
||||||
const o_file_path = mem.sliceTo(self.strings[symbol.ofile..], 0);
|
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) {
|
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.FileNotFound,
|
||||||
error.MissingDebugInfo,
|
error.MissingDebugInfo,
|
||||||
error.InvalidDebugInfo,
|
error.InvalidDebugInfo,
|
||||||
@ -699,6 +708,7 @@ pub const Module = switch (native_os) {
|
|||||||
else => return err,
|
else => return err,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std.debug.print("success\n", .{});
|
||||||
return .{
|
return .{
|
||||||
.relocated_address = relocated_address,
|
.relocated_address = relocated_address,
|
||||||
.symbol = symbol,
|
.symbol = symbol,
|
||||||
@ -846,7 +856,7 @@ pub const WindowsModule = struct {
|
|||||||
/// This takes ownership of macho_file: users of this function should not close
|
/// This takes ownership of macho_file: users of this function should not close
|
||||||
/// it themselves, even on error.
|
/// it themselves, even on error.
|
||||||
/// TODO it's weird to take ownership even on error, rework this code.
|
/// 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 mapped_mem = try mapWholeFile(macho_file);
|
||||||
|
|
||||||
const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr));
|
const hdr: *const macho.mach_header_64 = @ptrCast(@alignCast(mapped_mem.ptr));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user