Cross-platform abstraction for loading debug information into an in-memory format that supports queries such as "what is the source location of this virtual memory address?"
Unlike std.debug.SelfInfo, this API does not assume the debug information
in question happens to match the host CPU architecture, OS, or other target
properties.
anyerror means the error set is known only at runtime.
In WASI, this error may occur when the file descriptor does not hold the required rights to open a new resource relative to it.
On Windows, antivirus software is enabled by default. It can be disabled, but Windows Update sometimes ignores the user's preference and re-enables it. When enabled, antivirus software on Windows intercepts file system operations and makes them significantly slower in addition to possibly failing with this error code.
On Windows, file paths cannot contain these characters: '/', '*', '?', '"', '<', '>', '|'
One of these three things:
The underlying filesystem does not support file locks
Either:
O.EXCL set to false.The file is too large to be opened. This error is unreachable for 64-bit targets, as well as when opening directories.
WASI-only; file paths must be valid UTF-8.
Windows-only; file paths provided by the user must be valid WTF-8. https://simonsapin.github.io/wtf-8/
The path refers to directory but the DIRECTORY flag was not provided.
The path exceeded max_path_bytes bytes.
On Windows, \\server or \\server\share was not found.
A new path cannot be created because the device has no room for the new file.
This error is only reachable when the CREAT flag is provided.
A component used as a directory in the path was not, in fact, a directory, or
DIRECTORY was specified and the path was not a directory.
The debug info may be valid but this implementation uses memory mapping which limits things to usize. If the target debug info is 64-bit and host is 32-bit, there may be debug info that is not supportable using this method.
The path already exists and the CREAT and EXCL flags were provided.
Insufficient kernel memory was available, or the named file is a FIFO and per-user hard limit on memory allocation for pipes has been reached.
The Operating System returned an undocumented error code.
This error is in theory not possible, but it would be better to handle this error than to invoke undefined behavior.
When this error code is observed, it usually means the Zig Standard Library needs a small patch to add the error code to the error set for the respective function.
TODO: implement this and then remove this error code
pub const LoadError = error{
InvalidDebugInfo,
MissingDebugInfo,
InvalidElfMagic,
InvalidElfVersion,
InvalidElfEndian,
/// TODO: implement this and then remove this error code
UnimplementedDwarfForeignEndian,
/// The debug info may be valid but this implementation uses memory
/// mapping which limits things to usize. If the target debug info is
/// 64-bit and host is 32-bit, there may be debug info that is not
/// supportable using this method.
Overflow,
PermissionDenied,
LockedMemoryLimitExceeded,
MemoryMappingNotSupported,
} || Allocator.Error || std.fs.File.OpenError || OpenErroranyerror means the error set is known only at runtime.
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);
return info;
}pub fn resolveAddresses( info: *Info, gpa: Allocator, sorted_pc_addrs: []const u64, output: []SourceLocation, ) ResolveAddressesError!voidGiven an array of virtual memory addresses, sorted ascending, outputs a corresponding array of source locations.
info: *Infogpa: Allocatorsorted_pc_addrs: []const u64Asserts the addresses are in ascending order.
output: []SourceLocationAsserts its length equals length of sorted_pc_addrs.
pub fn resolveAddresses(
info: *Info,
gpa: Allocator,
/// 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);
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);
}//! Cross-platform abstraction for loading debug information into an in-memory
//! format that supports queries such as "what is the source location of this
//! virtual memory address?"
//!
//! Unlike `std.debug.SelfInfo`, this API does not assume the debug information
//! in question happens to match the host CPU architecture, OS, or other target
//! properties.
const std = @import("../std.zig");
const Allocator = std.mem.Allocator;
const Path = std.Build.Cache.Path;
const Dwarf = std.debug.Dwarf;
const assert = std.debug.assert;
const Coverage = std.debug.Coverage;
const SourceLocation = std.debug.Coverage.SourceLocation;
const Info = @This();
/// Sorted by key, ascending.
address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule),
/// Externally managed, outlives this `Info` instance.
coverage: *Coverage,
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);
return info;
}
pub fn deinit(info: *Info, gpa: Allocator) void {
for (info.address_map.values()) |*elf_module| {
elf_module.dwarf.deinit(gpa);
}
info.address_map.deinit(gpa);
info.* = undefined;
}
pub const ResolveAddressesError = Coverage.ResolveAddressesDwarfError;
/// Given an array of virtual memory addresses, sorted ascending, outputs a
/// corresponding array of source locations.
pub fn resolveAddresses(
info: *Info,
gpa: Allocator,
/// 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);
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);
}