Merge pull request #20903 from ziglang/dwarf-reorg

std: dwarf namespace reorg + bonus commits
This commit is contained in:
Andrew Kelley 2024-08-01 21:25:40 -07:00 committed by GitHub
commit 2e26cf83cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 2828 additions and 2821 deletions

View File

@ -166,7 +166,7 @@ fn mainTerminal() void {
var skip_count: usize = 0;
var fail_count: usize = 0;
var fuzz_count: usize = 0;
const root_node = std.Progress.start(.{
const root_node = if (builtin.fuzz) std.Progress.Node.none else std.Progress.start(.{
.root_name = "Test",
.estimated_total_items = test_fn_list.len,
});

View File

@ -18,6 +18,8 @@ const native_arch = builtin.cpu.arch;
const native_os = builtin.os.tag;
const native_endian = native_arch.endian();
pub const Dwarf = @import("debug/Dwarf.zig");
pub const runtime_safety = switch (builtin.mode) {
.Debug, .ReleaseSafe => true,
.ReleaseFast, .ReleaseSmall => false,
@ -67,7 +69,7 @@ pub const SymbolInfo = struct {
};
const PdbOrDwarf = union(enum) {
pdb: pdb.Pdb,
dwarf: DW.DwarfInfo,
dwarf: Dwarf,
fn deinit(self: *PdbOrDwarf, allocator: mem.Allocator) void {
switch (self.*) {
@ -102,9 +104,9 @@ pub fn getStderrMutex() *std.Thread.Mutex {
}
/// TODO multithreaded awareness
var self_debug_info: ?DebugInfo = null;
var self_debug_info: ?Info = null;
pub fn getSelfDebugInfo() !*DebugInfo {
pub fn getSelfDebugInfo() !*Info {
if (self_debug_info) |*info| {
return info;
} else {
@ -346,7 +348,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
stack_trace.index = slice.len;
} else {
// TODO: This should use the DWARF unwinder if .eh_frame_hdr is available (so that full debug info parsing isn't required).
// A new path for loading DebugInfo needs to be created which will only attempt to parse in-memory sections, because
// A new path for loading Info needs to be created which will only attempt to parse in-memory sections, because
// stopping to load other debug info (ie. source line info) from disk here is not required for unwinding.
var it = StackIterator.init(first_address, null);
defer it.deinit();
@ -524,7 +526,7 @@ pub fn writeStackTrace(
stack_trace: std.builtin.StackTrace,
out_stream: anytype,
allocator: mem.Allocator,
debug_info: *DebugInfo,
debug_info: *Info,
tty_config: io.tty.Config,
) !void {
_ = allocator;
@ -561,12 +563,12 @@ pub const StackIterator = struct {
fp: usize,
ma: MemoryAccessor = MemoryAccessor.init,
// When DebugInfo and a register context is available, this iterator can unwind
// When Info and a register context is available, this iterator can unwind
// stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer),
// using DWARF and MachO unwind info.
unwind_state: if (have_ucontext) ?struct {
debug_info: *DebugInfo,
dwarf_context: DW.UnwindContext,
debug_info: *Info,
dwarf_context: Dwarf.UnwindContext,
last_error: ?UnwindError = null,
failed: bool = false,
} else void = if (have_ucontext) null else {},
@ -590,7 +592,7 @@ pub const StackIterator = struct {
};
}
pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const posix.ucontext_t) !StackIterator {
pub fn initWithContext(first_address: ?usize, debug_info: *Info, context: *const posix.ucontext_t) !StackIterator {
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
if (comptime builtin.target.isDarwin() and native_arch == .aarch64) {
@ -599,7 +601,7 @@ pub const StackIterator = struct {
var iterator = init(first_address, null);
iterator.unwind_state = .{
.debug_info = debug_info,
.dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context),
.dwarf_context = try Dwarf.UnwindContext.init(debug_info.allocator, context),
};
return iterator;
@ -783,7 +785,7 @@ pub const StackIterator = struct {
// __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding
// via DWARF before attempting to use the compact unwind info will produce incorrect results.
if (module.unwind_info) |unwind_info| {
if (DW.unwindFrameMachO(&unwind_state.dwarf_context, &it.ma, unwind_info, module.eh_frame, module.base_address)) |return_address| {
if (Dwarf.unwindFrameMachO(&unwind_state.dwarf_context, &it.ma, unwind_info, module.eh_frame, module.base_address)) |return_address| {
return return_address;
} else |err| {
if (err != error.RequiresDWARFUnwind) return err;
@ -850,7 +852,7 @@ const have_msync = switch (native_os) {
pub fn writeCurrentStackTrace(
out_stream: anytype,
debug_info: *DebugInfo,
debug_info: *Info,
tty_config: io.tty.Config,
start_addr: ?usize,
) !void {
@ -936,7 +938,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w
pub fn writeStackTraceWindows(
out_stream: anytype,
debug_info: *DebugInfo,
debug_info: *Info,
tty_config: io.tty.Config,
context: *const windows.CONTEXT,
start_addr: ?usize,
@ -1000,7 +1002,7 @@ test machoSearchSymbols {
try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
}
fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
fn printUnknownSource(debug_info: *Info, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
const module_name = debug_info.getModuleNameForAddress(address);
return printLineInfo(
out_stream,
@ -1013,14 +1015,14 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
);
}
fn printLastUnwindError(it: *StackIterator, debug_info: *DebugInfo, out_stream: anytype, tty_config: io.tty.Config) void {
fn printLastUnwindError(it: *StackIterator, debug_info: *Info, out_stream: anytype, tty_config: io.tty.Config) void {
if (!have_ucontext) return;
if (it.getLastError()) |unwind_error| {
printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {};
}
}
fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
fn printUnwindError(debug_info: *Info, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
try tty_config.setColor(out_stream, .dim);
if (err == error.MissingDebugInfo) {
@ -1031,7 +1033,7 @@ fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize,
try tty_config.setColor(out_stream, .reset);
}
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
pub fn printSourceAtAddress(debug_info: *Info, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
else => return err,
@ -1105,9 +1107,9 @@ fn printLineInfo(
pub const OpenSelfDebugInfoError = error{
MissingDebugInfo,
UnsupportedOperatingSystem,
} || @typeInfo(@typeInfo(@TypeOf(DebugInfo.init)).Fn.return_type.?).ErrorUnion.error_set;
} || @typeInfo(@typeInfo(@TypeOf(Info.init)).Fn.return_type.?).ErrorUnion.error_set;
pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugInfo {
pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!Info {
nosuspend {
if (builtin.strip_debug_info)
return error.MissingDebugInfo;
@ -1124,7 +1126,7 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI
.solaris,
.illumos,
.windows,
=> return try DebugInfo.init(allocator),
=> return try Info.init(allocator),
else => return error.UnsupportedOperatingSystem,
}
}
@ -1140,10 +1142,10 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_obj: *coff.Coff) !ModuleDebu
if (coff_obj.getSectionByName(".debug_info")) |_| {
// This coff file has embedded DWARF debug info
var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array;
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
errdefer for (sections) |section| if (section) |s| if (s.owned) allocator.free(s.data);
inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
inline for (@typeInfo(Dwarf.Section.Id).Enum.fields, 0..) |section, i| {
sections[i] = if (coff_obj.getSectionByName("." ++ section.name)) |section_header| blk: {
break :blk .{
.data = try coff_obj.getSectionDataAlloc(section_header, allocator),
@ -1153,13 +1155,13 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_obj: *coff.Coff) !ModuleDebu
} else null;
}
var dwarf = DW.DwarfInfo{
var dwarf = Dwarf{
.endian = native_endian,
.sections = sections,
.is_macho = false,
};
try DW.openDwarfDebugInfo(&dwarf, allocator);
try Dwarf.open(&dwarf, allocator);
di.dwarf = dwarf;
}
@ -1211,7 +1213,7 @@ pub fn readElfDebugInfo(
elf_filename: ?[]const u8,
build_id: ?[]const u8,
expected_crc: ?u32,
parent_sections: *DW.DwarfInfo.SectionArray,
parent_sections: *Dwarf.SectionArray,
parent_mapped_mem: ?[]align(mem.page_size) const u8,
) !ModuleDebugInfo {
nosuspend {
@ -1245,7 +1247,7 @@ pub fn readElfDebugInfo(
@ptrCast(@alignCast(&mapped_mem[shoff])),
)[0..hdr.e_shnum];
var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array;
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
// Combine section list. This takes ownership over any owned sections from the parent scope.
for (parent_sections, &sections) |*parent, *section| {
@ -1274,7 +1276,7 @@ pub fn readElfDebugInfo(
}
var section_index: ?usize = null;
inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
inline for (@typeInfo(Dwarf.Section.Id).Enum.fields, 0..) |section, i| {
if (mem.eql(u8, "." ++ section.name, name)) section_index = i;
}
if (section_index == null) continue;
@ -1308,10 +1310,10 @@ pub fn readElfDebugInfo(
}
const missing_debug_info =
sections[@intFromEnum(DW.DwarfSection.debug_info)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_abbrev)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_str)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_line)] == null;
sections[@intFromEnum(Dwarf.Section.Id.debug_info)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_abbrev)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_str)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_line)] == null;
// Attempt to load debug info from an external file
// See: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
@ -1379,13 +1381,13 @@ pub fn readElfDebugInfo(
return error.MissingDebugInfo;
}
var di = DW.DwarfInfo{
var di = Dwarf{
.endian = endian,
.sections = sections,
.is_macho = false,
};
try DW.openDwarfDebugInfo(&di, allocator);
try Dwarf.open(&di, allocator);
return ModuleDebugInfo{
.base_address = undefined,
@ -1759,13 +1761,13 @@ pub const WindowsModuleInfo = struct {
} = null,
};
pub const DebugInfo = struct {
pub const Info = struct {
allocator: mem.Allocator,
address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
modules: if (native_os == .windows) std.ArrayListUnmanaged(WindowsModuleInfo) else void,
pub fn init(allocator: mem.Allocator) !DebugInfo {
var debug_info = DebugInfo{
pub fn init(allocator: mem.Allocator) !Info {
var debug_info = Info{
.allocator = allocator,
.address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator),
.modules = if (native_os == .windows) .{} else {},
@ -1808,7 +1810,7 @@ pub const DebugInfo = struct {
return debug_info;
}
pub fn deinit(self: *DebugInfo) void {
pub fn deinit(self: *Info) void {
var it = self.address_map.iterator();
while (it.next()) |entry| {
const mdi = entry.value_ptr.*;
@ -1825,7 +1827,7 @@ pub const DebugInfo = struct {
}
}
pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
pub fn getModuleForAddress(self: *Info, address: usize) !*ModuleDebugInfo {
if (comptime builtin.target.isDarwin()) {
return self.lookupModuleDyld(address);
} else if (native_os == .windows) {
@ -1842,7 +1844,7 @@ pub const DebugInfo = struct {
// Returns the module name for a given address.
// This can be called when getModuleForAddress fails, so implementations should provide
// a path that doesn't rely on any side-effects of a prior successful module lookup.
pub fn getModuleNameForAddress(self: *DebugInfo, address: usize) ?[]const u8 {
pub fn getModuleNameForAddress(self: *Info, address: usize) ?[]const u8 {
if (comptime builtin.target.isDarwin()) {
return self.lookupModuleNameDyld(address);
} else if (native_os == .windows) {
@ -1856,7 +1858,7 @@ pub const DebugInfo = struct {
}
}
fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
fn lookupModuleDyld(self: *Info, address: usize) !*ModuleDebugInfo {
const image_count = std.c._dyld_image_count();
var i: u32 = 0;
@ -1922,7 +1924,7 @@ pub const DebugInfo = struct {
return error.MissingDebugInfo;
}
fn lookupModuleNameDyld(self: *DebugInfo, address: usize) ?[]const u8 {
fn lookupModuleNameDyld(self: *Info, address: usize) ?[]const u8 {
_ = self;
const image_count = std.c._dyld_image_count();
@ -1960,7 +1962,7 @@ pub const DebugInfo = struct {
return null;
}
fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
fn lookupModuleWin32(self: *Info, address: usize) !*ModuleDebugInfo {
for (self.modules.items) |*module| {
if (address >= module.base_address and address < module.base_address + module.size) {
if (self.address_map.get(module.base_address)) |obj_di| {
@ -2050,7 +2052,7 @@ pub const DebugInfo = struct {
return error.MissingDebugInfo;
}
fn lookupModuleNameWin32(self: *DebugInfo, address: usize) ?[]const u8 {
fn lookupModuleNameWin32(self: *Info, address: usize) ?[]const u8 {
for (self.modules.items) |module| {
if (address >= module.base_address and address < module.base_address + module.size) {
return module.name;
@ -2059,7 +2061,7 @@ pub const DebugInfo = struct {
return null;
}
fn lookupModuleNameDl(self: *DebugInfo, address: usize) ?[]const u8 {
fn lookupModuleNameDl(self: *Info, address: usize) ?[]const u8 {
_ = self;
var ctx: struct {
@ -2097,7 +2099,7 @@ pub const DebugInfo = struct {
return null;
}
fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
fn lookupModuleDl(self: *Info, address: usize) !*ModuleDebugInfo {
var ctx: struct {
// Input
address: usize,
@ -2168,13 +2170,13 @@ pub const DebugInfo = struct {
const obj_di = try self.allocator.create(ModuleDebugInfo);
errdefer self.allocator.destroy(obj_di);
var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array;
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
if (ctx.gnu_eh_frame) |eh_frame_hdr| {
// This is a special case - pointer offsets inside .eh_frame_hdr
// are encoded relative to its base address, so we must use the
// version that is already memory mapped, and not the one that
// will be mapped separately from the ELF file.
sections[@intFromEnum(DW.DwarfSection.eh_frame_hdr)] = .{
sections[@intFromEnum(Dwarf.Section.Id.eh_frame_hdr)] = .{
.data = eh_frame_hdr,
.owned = false,
};
@ -2191,13 +2193,13 @@ pub const DebugInfo = struct {
return obj_di;
}
fn lookupModuleHaiku(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
fn lookupModuleHaiku(self: *Info, address: usize) !*ModuleDebugInfo {
_ = self;
_ = address;
@panic("TODO implement lookup module for Haiku");
}
fn lookupModuleWasm(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
fn lookupModuleWasm(self: *Info, address: usize) !*ModuleDebugInfo {
_ = self;
_ = address;
@panic("TODO implement lookup module for Wasm");
@ -2219,7 +2221,7 @@ pub const ModuleDebugInfo = switch (native_os) {
const OFileTable = std.StringHashMap(OFileInfo);
const OFileInfo = struct {
di: DW.DwarfInfo,
di: Dwarf,
addr_table: std.StringHashMap(u64),
};
@ -2278,8 +2280,8 @@ pub const ModuleDebugInfo = switch (native_os) {
addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
}
var sections: DW.DwarfInfo.SectionArray = DW.DwarfInfo.null_section_array;
if (self.eh_frame) |eh_frame| sections[@intFromEnum(DW.DwarfSection.eh_frame)] = .{
var sections: Dwarf.SectionArray = Dwarf.null_section_array;
if (self.eh_frame) |eh_frame| sections[@intFromEnum(Dwarf.Section.Id.eh_frame)] = .{
.data = eh_frame,
.owned = false,
};
@ -2288,7 +2290,7 @@ pub const ModuleDebugInfo = switch (native_os) {
if (!std.mem.eql(u8, "__DWARF", sect.segName())) continue;
var section_index: ?usize = null;
inline for (@typeInfo(DW.DwarfSection).Enum.fields, 0..) |section, i| {
inline for (@typeInfo(Dwarf.Section.Id).Enum.fields, 0..) |section, i| {
if (mem.eql(u8, "__" ++ section.name, sect.sectName())) section_index = i;
}
if (section_index == null) continue;
@ -2302,19 +2304,19 @@ pub const ModuleDebugInfo = switch (native_os) {
}
const missing_debug_info =
sections[@intFromEnum(DW.DwarfSection.debug_info)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_abbrev)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_str)] == null or
sections[@intFromEnum(DW.DwarfSection.debug_line)] == null;
sections[@intFromEnum(Dwarf.Section.Id.debug_info)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_abbrev)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_str)] == null or
sections[@intFromEnum(Dwarf.Section.Id.debug_line)] == null;
if (missing_debug_info) return error.MissingDebugInfo;
var di = DW.DwarfInfo{
var di = Dwarf{
.endian = .little,
.sections = sections,
.is_macho = true,
};
try DW.openDwarfDebugInfo(&di, allocator);
try Dwarf.open(&di, allocator);
const info = OFileInfo{
.di = di,
.addr_table = addr_table,
@ -2411,14 +2413,14 @@ pub const ModuleDebugInfo = switch (native_os) {
}
}
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const DW.DwarfInfo {
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const Dwarf {
return if ((try self.getOFileInfoForAddress(allocator, address)).o_file_info) |o_file_info| &o_file_info.di else null;
}
},
.uefi, .windows => struct {
base_address: usize,
pdb: ?pdb.Pdb = null,
dwarf: ?DW.DwarfInfo = null,
dwarf: ?Dwarf = null,
coff_image_base: u64,
/// Only used if pdb is non-null
@ -2488,7 +2490,7 @@ pub const ModuleDebugInfo = switch (native_os) {
return SymbolInfo{};
}
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const DW.DwarfInfo {
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const Dwarf {
_ = allocator;
_ = address;
@ -2500,7 +2502,7 @@ pub const ModuleDebugInfo = switch (native_os) {
},
.linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris, .illumos => struct {
base_address: usize,
dwarf: DW.DwarfInfo,
dwarf: Dwarf,
mapped_memory: []align(mem.page_size) const u8,
external_mapped_memory: ?[]align(mem.page_size) const u8,
@ -2516,7 +2518,7 @@ pub const ModuleDebugInfo = switch (native_os) {
return getSymbolFromDwarf(allocator, relocated_address, &self.dwarf);
}
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const DW.DwarfInfo {
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const Dwarf {
_ = allocator;
_ = address;
return &self.dwarf;
@ -2535,17 +2537,17 @@ pub const ModuleDebugInfo = switch (native_os) {
return SymbolInfo{};
}
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const DW.DwarfInfo {
pub fn getDwarfInfoForAddress(self: *@This(), allocator: mem.Allocator, address: usize) !?*const Dwarf {
_ = self;
_ = allocator;
_ = address;
return null;
}
},
else => DW.DwarfInfo,
else => Dwarf,
};
fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo) !SymbolInfo {
fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *Dwarf) !SymbolInfo {
if (nosuspend di.findCompileUnit(address)) |compile_unit| {
return SymbolInfo{
.symbol_name = nosuspend di.getSymbolName(address) orelse "???",

2709
lib/std/debug/Dwarf.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
const builtin = @import("builtin");
const std = @import("../std.zig");
const std = @import("../../std.zig");
const mem = std.mem;
const native_os = builtin.os.tag;
const posix = std.posix;
@ -392,7 +392,7 @@ pub fn regBytes(
/// Returns the ABI-defined default value this register has in the unwinding table
/// before running any of the CIE instructions. The DWARF spec defines these as having
/// the .undefined rule by default, but allows ABI authors to override that.
pub fn getRegDefaultValue(reg_number: u8, context: *std.dwarf.UnwindContext, out: []u8) !void {
pub fn getRegDefaultValue(reg_number: u8, context: *std.debug.Dwarf.UnwindContext, out: []u8) !void {
switch (builtin.cpu.arch) {
.aarch64 => {
// Callee-saved registers are initialized as if they had the .same_value rule

View File

@ -1,14 +1,14 @@
const builtin = @import("builtin");
const std = @import("../std.zig");
const std = @import("../../std.zig");
const mem = std.mem;
const debug = std.debug;
const leb = std.leb;
const dwarf = std.dwarf;
const abi = dwarf.abi;
const expressions = dwarf.expressions;
const DW = std.dwarf;
const abi = std.debug.Dwarf.abi;
const assert = std.debug.assert;
const native_endian = builtin.cpu.arch.endian();
/// TODO merge with std.dwarf.CFA
const Opcode = enum(u8) {
advance_loc = 0x1 << 6,
offset = 0x2 << 6,
@ -363,8 +363,8 @@ pub const VirtualMachine = struct {
/// Resolves the register rule and places the result into `out` (see dwarf.abi.regBytes)
pub fn resolveValue(
self: Column,
context: *dwarf.UnwindContext,
expression_context: dwarf.expressions.ExpressionContext,
context: *std.debug.Dwarf.UnwindContext,
expression_context: std.debug.Dwarf.expression.Context,
ma: *debug.StackIterator.MemoryAccessor,
out: []u8,
) !void {
@ -483,8 +483,8 @@ pub const VirtualMachine = struct {
self: *VirtualMachine,
allocator: std.mem.Allocator,
pc: u64,
cie: dwarf.CommonInformationEntry,
fde: dwarf.FrameDescriptionEntry,
cie: std.debug.Dwarf.CommonInformationEntry,
fde: std.debug.Dwarf.FrameDescriptionEntry,
addr_size_bytes: u8,
endian: std.builtin.Endian,
) !Row {
@ -502,7 +502,7 @@ pub const VirtualMachine = struct {
for (&streams, 0..) |stream, i| {
while (stream.pos < stream.buffer.len) {
const instruction = try dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);
const instruction = try std.debug.Dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);
prev_row = try self.step(allocator, cie, i == 0, instruction);
if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
}
@ -515,8 +515,8 @@ pub const VirtualMachine = struct {
self: *VirtualMachine,
allocator: std.mem.Allocator,
pc: u64,
cie: dwarf.CommonInformationEntry,
fde: dwarf.FrameDescriptionEntry,
cie: std.debug.Dwarf.CommonInformationEntry,
fde: std.debug.Dwarf.FrameDescriptionEntry,
) !Row {
return self.runTo(allocator, pc, cie, fde, @sizeOf(usize), builtin.target.cpu.arch.endian());
}
@ -538,7 +538,7 @@ pub const VirtualMachine = struct {
pub fn step(
self: *VirtualMachine,
allocator: std.mem.Allocator,
cie: dwarf.CommonInformationEntry,
cie: std.debug.Dwarf.CommonInformationEntry,
is_initial: bool,
instruction: Instruction,
) !Row {

View File

@ -1,9 +1,8 @@
const std = @import("std");
const builtin = @import("builtin");
const OP = @import("OP.zig");
const leb = std.leb;
const dwarf = std.dwarf;
const abi = dwarf.abi;
const OP = std.dwarf.OP;
const abi = std.debug.Dwarf.abi;
const mem = std.mem;
const assert = std.debug.assert;
const native_endian = builtin.cpu.arch.endian();
@ -11,46 +10,37 @@ const native_endian = builtin.cpu.arch.endian();
/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.
/// Callers should specify all the fields relevant to their context. If a field is required
/// by the expression and it isn't in the context, error.IncompleteExpressionContext is returned.
pub const ExpressionContext = struct {
pub const Context = struct {
/// The dwarf format of the section this expression is in
format: dwarf.Format = .@"32",
format: std.dwarf.Format = .@"32",
/// If specified, any addresses will pass through before being accessed
memory_accessor: ?*std.debug.StackIterator.MemoryAccessor = null,
/// The compilation unit this expression relates to, if any
compile_unit: ?*const dwarf.CompileUnit = null,
compile_unit: ?*const std.debug.Dwarf.CompileUnit = null,
/// When evaluating a user-presented expression, this is the address of the object being evaluated
object_address: ?*const anyopaque = null,
/// .debug_addr section
debug_addr: ?[]const u8 = null,
/// Thread context
thread_context: ?*std.debug.ThreadContext = null,
reg_context: ?abi.RegisterContext = null,
/// Call frame address, if in a CFI context
cfa: ?usize = null,
/// This expression is a sub-expression from an OP.entry_value instruction
entry_value_context: bool = false,
};
pub const ExpressionOptions = struct {
pub const Options = struct {
/// The address size of the target architecture
addr_size: u8 = @sizeOf(usize),
/// Endianness of the target architecture
endian: std.builtin.Endian = builtin.target.cpu.arch.endian(),
/// Restrict the stack machine to a subset of opcodes used in call frame instructions
call_frame_context: bool = false,
};
// Explicitly defined to support executing sub-expressions
pub const ExpressionError = error{
pub const Error = error{
UnimplementedExpressionCall,
UnimplementedOpcode,
UnimplementedUserOpcode,
@ -75,7 +65,7 @@ pub const ExpressionError = error{
/// A stack machine that can decode and run DWARF expressions.
/// Expressions can be decoded for non-native address size and endianness,
/// but can only be executed if the current target matches the configuration.
pub fn StackMachine(comptime options: ExpressionOptions) type {
pub fn StackMachine(comptime options: Options) type {
const addr_type = switch (options.addr_size) {
2 => u16,
4 => u32,
@ -186,7 +176,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
}
}
pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8, context: ExpressionContext) !?Operand {
pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8, context: Context) !?Operand {
const reader = stream.reader();
return switch (opcode) {
OP.addr => generic(try reader.readInt(addr_type, options.endian)),
@ -297,9 +287,9 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
self: *Self,
expression: []const u8,
allocator: std.mem.Allocator,
context: ExpressionContext,
context: Context,
initial_value: ?usize,
) ExpressionError!?Value {
) Error!?Value {
if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
var stream = std.io.fixedBufferStream(expression);
while (try self.step(&stream, allocator, context)) {}
@ -312,8 +302,8 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
self: *Self,
stream: *std.io.FixedBufferStream([]const u8),
allocator: std.mem.Allocator,
context: ExpressionContext,
) ExpressionError!bool {
context: Context,
) Error!bool {
if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())
@compileError("Execution of non-native address sizes / endianness is not supported");
@ -792,7 +782,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
};
}
pub fn Builder(comptime options: ExpressionOptions) type {
pub fn Builder(comptime options: Options) type {
const addr_type = switch (options.addr_size) {
2 => u16,
4 => u32,
@ -1066,7 +1056,7 @@ const testing = std.testing;
test "DWARF expressions" {
const allocator = std.testing.allocator;
const options = ExpressionOptions{};
const options = Options{};
var stack_machine = StackMachine(options){};
defer stack_machine.deinit(allocator);
@ -1079,7 +1069,7 @@ test "DWARF expressions" {
// Literals
{
const context = ExpressionContext{};
const context = Context{};
for (0..32) |i| {
try b.writeLiteral(writer, @intCast(i));
}
@ -1125,7 +1115,7 @@ test "DWARF expressions" {
try b.writeConst(writer, i28, input[9]);
try b.writeAddr(writer, input[10]);
var mock_compile_unit: dwarf.CompileUnit = undefined;
var mock_compile_unit: std.debug.Dwarf.CompileUnit = undefined;
mock_compile_unit.addr_base = 1;
var mock_debug_addr = std.ArrayList(u8).init(allocator);
@ -1135,7 +1125,7 @@ test "DWARF expressions" {
try mock_debug_addr.writer().writeInt(usize, input[11], native_endian);
try mock_debug_addr.writer().writeInt(usize, input[12], native_endian);
const context = ExpressionContext{
const context = Context{
.compile_unit = &mock_compile_unit,
.debug_addr = mock_debug_addr.items,
};
@ -1185,7 +1175,7 @@ test "DWARF expressions" {
};
var thread_context: std.debug.ThreadContext = undefined;
std.debug.relocateContext(&thread_context);
const context = ExpressionContext{
const context = Context{
.thread_context = &thread_context,
.reg_context = reg_context,
};
@ -1228,7 +1218,7 @@ test "DWARF expressions" {
// Stack operations
{
var context = ExpressionContext{};
var context = Context{};
stack_machine.reset();
program.clearRetainingCapacity();
@ -1359,7 +1349,7 @@ test "DWARF expressions" {
// Arithmetic and Logical Operations
{
const context = ExpressionContext{};
const context = Context{};
stack_machine.reset();
program.clearRetainingCapacity();
@ -1483,7 +1473,7 @@ test "DWARF expressions" {
// Control Flow Operations
{
const context = ExpressionContext{};
const context = Context{};
const expected = .{
.{ OP.le, 1, 1, 0 },
.{ OP.ge, 1, 0, 1 },
@ -1540,7 +1530,7 @@ test "DWARF expressions" {
// Type conversions
{
const context = ExpressionContext{};
const context = Context{};
stack_machine.reset();
program.clearRetainingCapacity();
@ -1588,7 +1578,7 @@ test "DWARF expressions" {
// Special operations
{
var context = ExpressionContext{};
var context = Context{};
stack_machine.reset();
program.clearRetainingCapacity();
@ -1617,7 +1607,7 @@ test "DWARF expressions" {
};
var thread_context: std.debug.ThreadContext = undefined;
std.debug.relocateContext(&thread_context);
context = ExpressionContext{
context = Context{
.thread_context = &thread_context,
.reg_context = reg_context,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
fd: posix.fd_t,
fd: Handle,
pub const Handle = posix.fd_t;
pub const default_mode = 0o755;

View File

@ -327,7 +327,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
}
pub fn needUnwindTables(target: std.Target) bool {
return target.os.tag == .windows or target.isDarwin() or std.dwarf.abi.supportsUnwinding(target);
return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target);
}
pub fn defaultAddressSpace(

View File

@ -992,11 +992,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);
for (test_targets) |test_target| {
const is_native = test_target.target.isNative() or
(test_target.target.os_tag == builtin.os.tag and
test_target.target.cpu_arch == builtin.cpu.arch);
if (options.skip_non_native and !is_native)
if (options.skip_non_native and !test_target.target.isNative())
continue;
const resolved_target = b.resolveTargetQuery(test_target.target);