Given an array of virtual memory addresses, sorted ascending, outputs a corresponding array of source locations.
pub fn resolveAddresses(
info: *Info,
gpa: Allocator,
io: Io,
/// Asserts the addresses are in ascending order.
sorted_pc_addrs: []const u64,
/// Asserts its length equals length of `sorted_pc_addrs`.
output: []SourceLocation,
) ResolveAddressesError!void
pub fn resolveAddresses(
info: *Info,
gpa: Allocator,
io: Io,
/// Asserts the addresses are in ascending order.
sorted_pc_addrs: []const u64,
/// Asserts its length equals length of `sorted_pc_addrs`.
output: []SourceLocation,
) ResolveAddressesError!void {
assert(sorted_pc_addrs.len == output.len);
switch (info.impl) {
.elf => |*ef| return info.coverage.resolveAddressesDwarf(gpa, io, ef.endian, sorted_pc_addrs, output, &ef.dwarf.?),
.macho => |*mf| {
// Resolving all of the addresses at once unfortunately isn't so easy in Mach-O binaries
// due to split debug information. For now, we'll just resolve the addreses one by one.
for (sorted_pc_addrs, output) |pc_addr, *src_loc| {
const dwarf, const dwarf_pc_addr = mf.getDwarfForAddress(gpa, io, pc_addr) catch |err| switch (err) {
error.MissingDebugInfo => {
src_loc.* = .invalid;
continue;
},
error.InvalidMachO, error.InvalidDwarf => return error.InvalidDebugInfo,
else => |e| return e,
};
if (dwarf.ranges.items.len == 0) {
dwarf.populateRanges(gpa, .little) catch |err| switch (err) {
error.EndOfStream,
error.Overflow,
error.StreamTooLong,
error.ReadFailed,
=> return error.InvalidDebugInfo,
else => |e| return e,
};
}
try info.coverage.resolveAddressesDwarf(gpa, io, .little, &.{dwarf_pc_addr}, src_loc[0..1], dwarf);
}
},
}
}