mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 03:04:52 +01:00
- delete std.Thread.Futex - delete std.Thread.Mutex - delete std.Thread.Semaphore - delete std.Thread.Condition - delete std.Thread.RwLock - delete std.once std.Thread.Mutex.Recursive remains... for now. it will be replaced with a special purpose mechanism used only by panic logic. std.Io.Threaded exposes mutexLock and mutexUnlock for the advanced case when you need to call them directly.
119 lines
4.2 KiB
Zig
119 lines
4.2 KiB
Zig
//! 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 Info = @This();
|
|
|
|
const std = @import("../std.zig");
|
|
const Io = std.Io;
|
|
const Allocator = std.mem.Allocator;
|
|
const Path = std.Build.Cache.Path;
|
|
const assert = std.debug.assert;
|
|
const Coverage = std.debug.Coverage;
|
|
const SourceLocation = std.debug.Coverage.SourceLocation;
|
|
const ElfFile = std.debug.ElfFile;
|
|
const MachOFile = std.debug.MachOFile;
|
|
|
|
impl: union(enum) {
|
|
elf: ElfFile,
|
|
macho: MachOFile,
|
|
},
|
|
/// Externally managed, outlives this `Info` instance.
|
|
coverage: *Coverage,
|
|
|
|
pub const LoadError = error{
|
|
MissingDebugInfo,
|
|
UnsupportedDebugInfo,
|
|
} || Io.File.OpenError || ElfFile.LoadError || MachOFile.Error || std.debug.Dwarf.ScanError;
|
|
|
|
pub fn load(
|
|
gpa: Allocator,
|
|
io: Io,
|
|
path: Path,
|
|
coverage: *Coverage,
|
|
format: std.Target.ObjectFormat,
|
|
arch: std.Target.Cpu.Arch,
|
|
) LoadError!Info {
|
|
switch (format) {
|
|
.elf => {
|
|
var file = try path.root_dir.handle.openFile(io, path.sub_path, .{});
|
|
defer file.close(io);
|
|
|
|
var elf_file: ElfFile = try .load(gpa, io, file, null, &.none);
|
|
errdefer elf_file.deinit(gpa);
|
|
|
|
if (elf_file.dwarf == null) return error.MissingDebugInfo;
|
|
try elf_file.dwarf.?.open(gpa, elf_file.endian);
|
|
try elf_file.dwarf.?.populateRanges(gpa, elf_file.endian);
|
|
|
|
return .{
|
|
.impl = .{ .elf = elf_file },
|
|
.coverage = coverage,
|
|
};
|
|
},
|
|
.macho => {
|
|
const path_str = try path.toString(gpa);
|
|
defer gpa.free(path_str);
|
|
|
|
var macho_file: MachOFile = try .load(gpa, io, path_str, arch);
|
|
errdefer macho_file.deinit(gpa);
|
|
|
|
return .{
|
|
.impl = .{ .macho = macho_file },
|
|
.coverage = coverage,
|
|
};
|
|
},
|
|
else => return error.UnsupportedDebugInfo,
|
|
}
|
|
}
|
|
|
|
pub fn deinit(info: *Info, gpa: Allocator) void {
|
|
switch (info.impl) {
|
|
.elf => |*ef| ef.deinit(gpa),
|
|
.macho => |*mf| mf.deinit(gpa),
|
|
}
|
|
info.* = undefined;
|
|
}
|
|
|
|
pub const ResolveAddressesError = Coverage.ResolveAddressesDwarfError || error{UnsupportedDebugInfo};
|
|
|
|
/// 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 {
|
|
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.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);
|
|
}
|
|
},
|
|
}
|
|
}
|