diff --git a/lib/std/debug.zig b/lib/std/debug.zig index ebbcad627ba2..d0ec4db1d0b6 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -14,7 +14,6 @@ const native_os = builtin.os.tag; const native_endian = native_arch.endian(); const Writer = std.io.Writer; -pub const MemoryAccessor = @import("debug/MemoryAccessor.zig"); pub const FixedBufferReader = @import("debug/FixedBufferReader.zig"); pub const Dwarf = @import("debug/Dwarf.zig"); pub const Pdb = @import("debug/Pdb.zig"); @@ -501,6 +500,11 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT // 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 SelfInfo 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. + if (builtin.cpu.arch == .powerpc64) { + // https://github.com/ziglang/zig/issues/24970 + stack_trace.index = 0; + return; + } var it = StackIterator.init(first_address, null); defer it.deinit(); for (stack_trace.instruction_addresses, 0..) |*addr, i| { @@ -773,7 +777,6 @@ pub const StackIterator = struct { first_address: ?usize, // Last known value of the frame pointer register. fp: usize, - ma: MemoryAccessor = MemoryAccessor.init, // When SelfInfo and a register context is available, this iterator can unwind // stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer), @@ -795,7 +798,7 @@ pub const StackIterator = struct { ::: .{ .memory = true }); } - return StackIterator{ + return .{ .first_address = first_address, // TODO: this is a workaround for #16876 //.fp = fp orelse @frameAddress(), @@ -825,7 +828,6 @@ pub const StackIterator = struct { } pub fn deinit(it: *StackIterator) void { - it.ma.deinit(); if (have_ucontext and it.unwind_state != null) it.unwind_state.?.dwarf_context.deinit(); } @@ -896,7 +898,6 @@ pub const StackIterator = struct { unwind_state.debug_info.allocator, module.base_address, &unwind_state.dwarf_context, - &it.ma, unwind_info, module.eh_frame, )) |return_address| { @@ -915,7 +916,6 @@ pub const StackIterator = struct { di, module.base_address, &unwind_state.dwarf_context, - &it.ma, null, ); } else return error.MissingDebugInfo; @@ -951,7 +951,7 @@ pub const StackIterator = struct { // Sanity check. if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) return null; - const new_fp = math.add(usize, it.ma.load(usize, fp) orelse return null, fp_bias) catch + const new_fp = math.add(usize, @as(*usize, @ptrFromInt(fp)).*, fp_bias) catch return null; // Sanity check: the stack grows down thus all the parent frames must be @@ -959,8 +959,7 @@ pub const StackIterator = struct { // A zero frame pointer often signals this is the last frame, that case // is gracefully handled by the next call to next_internal. if (new_fp != 0 and new_fp < it.fp) return null; - const new_pc = it.ma.load(usize, math.add(usize, fp, pc_offset) catch return null) orelse - return null; + const new_pc = @as(*usize, @ptrFromInt(math.add(usize, fp, pc_offset) catch return null)).*; it.fp = new_fp; @@ -1774,7 +1773,6 @@ pub inline fn inValgrind() bool { test { _ = &Dwarf; - _ = &MemoryAccessor; _ = &FixedBufferReader; _ = &Pdb; _ = &SelfInfo; diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 01c672b3a083..519c89a039c3 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -24,7 +24,6 @@ const UT = DW.UT; const assert = std.debug.assert; const cast = std.math.cast; const maxInt = std.math.maxInt; -const MemoryAccessor = std.debug.MemoryAccessor; const Path = std.Build.Cache.Path; const FixedBufferReader = std.debug.FixedBufferReader; const ArrayList = std.ArrayList; @@ -349,29 +348,9 @@ pub const ExceptionFrameHeader = struct { }; } - fn isValidPtr( - self: ExceptionFrameHeader, - comptime T: type, - ptr: usize, - ma: *MemoryAccessor, - eh_frame_len: ?usize, - ) bool { - if (eh_frame_len) |len| { - return ptr >= self.eh_frame_ptr and ptr <= self.eh_frame_ptr + len - @sizeOf(T); - } else { - return ma.load(T, ptr) != null; - } - } - - /// Find an entry by binary searching the eh_frame_hdr section. - /// - /// Since the length of the eh_frame section (`eh_frame_len`) may not be known by the caller, - /// MemoryAccessor will be used to verify readability of the header entries. - /// If `eh_frame_len` is provided, then these checks can be skipped. pub fn findEntry( self: ExceptionFrameHeader, - ma: *MemoryAccessor, - eh_frame_len: ?usize, + eh_frame_len: usize, eh_frame_hdr_ptr: usize, pc: usize, cie: *CommonInformationEntry, @@ -421,8 +400,7 @@ pub const ExceptionFrameHeader = struct { if (fde_ptr < self.eh_frame_ptr) return bad(); - // Even if eh_frame_len is not specified, all ranges accssed are checked via MemoryAccessor - const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse maxInt(u32)]; + const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0..eh_frame_len]; const fde_offset = fde_ptr - self.eh_frame_ptr; var eh_frame_fbr: FixedBufferReader = .{ @@ -431,15 +409,13 @@ pub const ExceptionFrameHeader = struct { .endian = native_endian, }; - const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); - if (fde_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); + const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame); if (fde_entry_header.type != .fde) return bad(); // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable const cie_offset = fde_entry_header.type.fde; try eh_frame_fbr.seekTo(cie_offset); - const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); - if (cie_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); + const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame); if (cie_entry_header.type != .cie) return bad(); cie.* = try CommonInformationEntry.parse( @@ -486,15 +462,11 @@ pub const EntryHeader = struct { /// Reads a header for either an FDE or a CIE, then advances the fbr to the position after the trailing structure. /// `fbr` must be a FixedBufferReader backed by either the .eh_frame or .debug_frame sections. - pub fn read( - fbr: *FixedBufferReader, - opt_ma: ?*MemoryAccessor, - dwarf_section: Section.Id, - ) !EntryHeader { + pub fn read(fbr: *FixedBufferReader, dwarf_section: Section.Id) !EntryHeader { assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame); const length_offset = fbr.pos; - const unit_header = try readUnitHeader(fbr, opt_ma); + const unit_header = try readUnitHeader(fbr); const unit_length = cast(usize, unit_header.unit_length) orelse return bad(); if (unit_length == 0) return .{ .length_offset = length_offset, @@ -506,10 +478,7 @@ pub const EntryHeader = struct { const end_offset = start_offset + unit_length; defer fbr.pos = end_offset; - const id = try if (opt_ma) |ma| - fbr.readAddressChecked(unit_header.format, ma) - else - fbr.readAddress(unit_header.format); + const id = try fbr.readAddress(unit_header.format); const entry_bytes = fbr.buf[fbr.pos..end_offset]; const cie_id: u64 = switch (dwarf_section) { .eh_frame => CommonInformationEntry.eh_id, @@ -856,7 +825,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void { while (this_unit_offset < fbr.buf.len) { try fbr.seekTo(this_unit_offset); - const unit_header = try readUnitHeader(&fbr, null); + const unit_header = try readUnitHeader(&fbr); if (unit_header.unit_length == 0) return; const next_offset = unit_header.header_length + unit_header.unit_length; @@ -1045,7 +1014,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator) ScanError!void { while (this_unit_offset < fbr.buf.len) { try fbr.seekTo(this_unit_offset); - const unit_header = try readUnitHeader(&fbr, null); + const unit_header = try readUnitHeader(&fbr); if (unit_header.unit_length == 0) return; const next_offset = unit_header.header_length + unit_header.unit_length; @@ -1427,7 +1396,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! }; try fbr.seekTo(line_info_offset); - const unit_header = try readUnitHeader(&fbr, null); + const unit_header = try readUnitHeader(&fbr); if (unit_header.unit_length == 0) return missing(); const next_offset = unit_header.header_length + unit_header.unit_length; @@ -1815,7 +1784,7 @@ pub fn scanCieFdeInfo(di: *Dwarf, allocator: Allocator, base_address: usize) !vo if (di.section(frame_section)) |section_data| { var fbr: FixedBufferReader = .{ .buf = section_data, .endian = di.endian }; while (fbr.pos < fbr.buf.len) { - const entry_header = try EntryHeader.read(&fbr, null, frame_section); + const entry_header = try EntryHeader.read(&fbr, frame_section); switch (entry_header.type) { .cie => { const cie = try CommonInformationEntry.parse( @@ -1988,8 +1957,8 @@ const UnitHeader = struct { unit_length: u64, }; -fn readUnitHeader(fbr: *FixedBufferReader, opt_ma: ?*MemoryAccessor) ScanError!UnitHeader { - return switch (try if (opt_ma) |ma| fbr.readIntChecked(u32, ma) else fbr.readInt(u32)) { +fn readUnitHeader(fbr: *FixedBufferReader) ScanError!UnitHeader { + return switch (try fbr.readInt(u32)) { 0...0xfffffff0 - 1 => |unit_length| .{ .format = .@"32", .header_length = 4, @@ -1999,7 +1968,7 @@ fn readUnitHeader(fbr: *FixedBufferReader, opt_ma: ?*MemoryAccessor) ScanError!U 0xffffffff => .{ .format = .@"64", .header_length = 12, - .unit_length = try if (opt_ma) |ma| fbr.readIntChecked(u64, ma) else fbr.readInt(u64), + .unit_length = try fbr.readInt(u64), }, }; } diff --git a/lib/std/debug/Dwarf/expression.zig b/lib/std/debug/Dwarf/expression.zig index fcbb9391713d..c123cdb30b8c 100644 --- a/lib/std/debug/Dwarf/expression.zig +++ b/lib/std/debug/Dwarf/expression.zig @@ -15,8 +15,6 @@ const assert = std.debug.assert; pub const Context = struct { /// The dwarf format of the section this expression is in format: std.dwarf.Format = .@"32", - /// If specified, any addresses will pass through before being accessed - memory_accessor: ?*std.debug.MemoryAccessor = null, /// The compilation unit this expression relates to, if any compile_unit: ?*const std.debug.Dwarf.CompileUnit = null, /// When evaluating a user-presented expression, this is the address of the object being evaluated @@ -465,16 +463,6 @@ pub fn StackMachine(comptime options: Options) type { else => unreachable, }; - if (context.memory_accessor) |memory_accessor| { - if (!switch (size) { - 1 => memory_accessor.load(u8, addr) != null, - 2 => memory_accessor.load(u16, addr) != null, - 4 => memory_accessor.load(u32, addr) != null, - 8 => memory_accessor.load(u64, addr) != null, - else => return error.InvalidExpression, - }) return error.InvalidExpression; - } - const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) { 1 => @as(*const u8, @ptrFromInt(addr)).*, 2 => @as(*const u16, @ptrFromInt(addr)).*, diff --git a/lib/std/debug/FixedBufferReader.zig b/lib/std/debug/FixedBufferReader.zig index e4aec1a9c675..edf763892fc1 100644 --- a/lib/std/debug/FixedBufferReader.zig +++ b/lib/std/debug/FixedBufferReader.zig @@ -1,7 +1,6 @@ //! Optimized for performance in debug builds. const std = @import("../std.zig"); -const MemoryAccessor = std.debug.MemoryAccessor; const FixedBufferReader = @This(); @@ -38,17 +37,6 @@ pub fn readInt(fbr: *FixedBufferReader, comptime T: type) Error!T { return std.mem.readInt(T, fbr.buf[fbr.pos..][0..size], fbr.endian); } -pub fn readIntChecked( - fbr: *FixedBufferReader, - comptime T: type, - ma: *MemoryAccessor, -) Error!T { - if (ma.load(T, @intFromPtr(fbr.buf[fbr.pos..].ptr)) == null) - return error.InvalidBuffer; - - return fbr.readInt(T); -} - pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T { return std.leb.readUleb128(T, fbr); } @@ -64,17 +52,6 @@ pub fn readAddress(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64 }; } -pub fn readAddressChecked( - fbr: *FixedBufferReader, - format: std.dwarf.Format, - ma: *MemoryAccessor, -) Error!u64 { - return switch (format) { - .@"32" => try fbr.readIntChecked(u32, ma), - .@"64" => try fbr.readIntChecked(u64, ma), - }; -} - pub fn readBytes(fbr: *FixedBufferReader, len: usize) Error![]const u8 { if (fbr.buf.len - fbr.pos < len) return error.EndOfBuffer; defer fbr.pos += len; diff --git a/lib/std/debug/MemoryAccessor.zig b/lib/std/debug/MemoryAccessor.zig deleted file mode 100644 index 7857656554e5..000000000000 --- a/lib/std/debug/MemoryAccessor.zig +++ /dev/null @@ -1,141 +0,0 @@ -//! Reads memory from any address of the current location using OS-specific -//! syscalls, bypassing memory page protection. Useful for stack unwinding. - -const builtin = @import("builtin"); -const native_os = builtin.os.tag; - -const std = @import("../std.zig"); -const posix = std.posix; -const File = std.fs.File; -const page_size_min = std.heap.page_size_min; - -const MemoryAccessor = @This(); - -var cached_pid: posix.pid_t = -1; - -mem: switch (native_os) { - .linux => File, - else => void, -}, - -pub const init: MemoryAccessor = .{ - .mem = switch (native_os) { - .linux => .{ .handle = -1 }, - else => {}, - }, -}; - -pub fn deinit(ma: *MemoryAccessor) void { - switch (native_os) { - .linux => switch (ma.mem.handle) { - -2, -1 => {}, - else => ma.mem.close(), - }, - else => {}, - } - ma.* = undefined; -} - -fn read(ma: *MemoryAccessor, address: usize, buf: []u8) bool { - switch (native_os) { - .linux => while (true) switch (ma.mem.handle) { - -2 => break, - -1 => { - const linux = std.os.linux; - const pid = switch (@atomicLoad(posix.pid_t, &cached_pid, .monotonic)) { - -1 => pid: { - const pid = linux.getpid(); - @atomicStore(posix.pid_t, &cached_pid, pid, .monotonic); - break :pid pid; - }, - else => |pid| pid, - }; - const bytes_read = linux.process_vm_readv( - pid, - &.{.{ .base = buf.ptr, .len = buf.len }}, - &.{.{ .base = @ptrFromInt(address), .len = buf.len }}, - 0, - ); - switch (linux.E.init(bytes_read)) { - .SUCCESS => return bytes_read == buf.len, - .FAULT => return false, - .INVAL, .SRCH => unreachable, // own pid is always valid - .PERM => {}, // Known to happen in containers. - .NOMEM => {}, - .NOSYS => {}, // QEMU is known not to implement this syscall. - else => unreachable, // unexpected - } - var path_buf: [ - std.fmt.count("/proc/{d}/mem", .{std.math.minInt(posix.pid_t)}) - ]u8 = undefined; - const path = std.fmt.bufPrint(&path_buf, "/proc/{d}/mem", .{pid}) catch - unreachable; - ma.mem = std.fs.openFileAbsolute(path, .{}) catch { - ma.mem.handle = -2; - break; - }; - }, - else => return (ma.mem.pread(buf, address) catch return false) == buf.len, - }, - else => {}, - } - if (!isValidMemory(address)) return false; - @memcpy(buf, @as([*]const u8, @ptrFromInt(address))); - return true; -} - -pub fn load(ma: *MemoryAccessor, comptime Type: type, address: usize) ?Type { - var result: Type = undefined; - return if (ma.read(address, std.mem.asBytes(&result))) result else null; -} - -pub fn isValidMemory(address: usize) bool { - // We are unable to determine validity of memory for freestanding targets - if (native_os == .freestanding or native_os == .other or native_os == .uefi) return true; - - const page_size = std.heap.pageSize(); - const aligned_address = address & ~(page_size - 1); - if (aligned_address == 0) return false; - const aligned_memory = @as([*]align(page_size_min) u8, @ptrFromInt(aligned_address))[0..page_size]; - - if (native_os == .windows) { - const windows = std.os.windows; - - var memory_info: windows.MEMORY_BASIC_INFORMATION = undefined; - - // The only error this function can throw is ERROR_INVALID_PARAMETER. - // supply an address that invalid i'll be thrown. - const rc = windows.VirtualQuery(@ptrCast(aligned_memory), &memory_info, aligned_memory.len) catch { - return false; - }; - - // Result code has to be bigger than zero (number of bytes written) - if (rc == 0) { - return false; - } - - // Free pages cannot be read, they are unmapped - if (memory_info.State == windows.MEM_FREE) { - return false; - } - - return true; - } else if (have_msync) { - posix.msync(aligned_memory, posix.MSF.ASYNC) catch |err| { - switch (err) { - error.UnmappedMemory => return false, - else => unreachable, - } - }; - - return true; - } else { - // We are unable to determine validity of memory on this target. - return true; - } -} - -const have_msync = switch (native_os) { - .wasi, .emscripten, .windows => false, - else => true, -}; diff --git a/lib/std/debug/SelfInfo.zig b/lib/std/debug/SelfInfo.zig index 3f1514a957e1..fe19e7958886 100644 --- a/lib/std/debug/SelfInfo.zig +++ b/lib/std/debug/SelfInfo.zig @@ -1159,7 +1159,6 @@ pub fn unwindFrameMachO( allocator: Allocator, base_address: usize, context: *UnwindContext, - ma: *std.debug.MemoryAccessor, unwind_info: []const u8, eh_frame: ?[]const u8, ) !usize { @@ -1323,9 +1322,6 @@ pub fn unwindFrameMachO( const fp = (try regValueNative(context.thread_context, fpRegNum(reg_context), reg_context)).*; const new_sp = fp + 2 * @sizeOf(usize); - // Verify the stack range we're about to read register values from - if (ma.load(usize, new_sp) == null or ma.load(usize, fp - frame_offset + max_reg * @sizeOf(usize)) == null) return error.InvalidUnwindInfo; - const ip_ptr = fp + @sizeOf(usize); const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*; const new_fp = @as(*const usize, @ptrFromInt(fp)).*; @@ -1355,7 +1351,6 @@ pub fn unwindFrameMachO( base_address + entry.function_offset + encoding.value.x86_64.frameless.stack.indirect.sub_offset; - if (ma.load(usize, sub_offset_addr) == null) return error.InvalidUnwindInfo; // `sub_offset_addr` points to the offset of the literal within the instruction const sub_operand = @as(*align(1) const u32, @ptrFromInt(sub_offset_addr)).*; @@ -1397,7 +1392,6 @@ pub fn unwindFrameMachO( } var reg_addr = sp + stack_size - @sizeOf(usize) * @as(usize, reg_count + 1); - if (ma.load(usize, reg_addr) == null) return error.InvalidUnwindInfo; for (0..reg_count) |i| { const reg_number = try Dwarf.compactUnwindToDwarfRegNumber(registers[i]); (try regValueNative(context.thread_context, reg_number, reg_context)).* = @as(*const usize, @ptrFromInt(reg_addr)).*; @@ -1409,7 +1403,6 @@ pub fn unwindFrameMachO( const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*; const new_sp = ip_ptr + @sizeOf(usize); - if (ma.load(usize, new_sp) == null) return error.InvalidUnwindInfo; (try regValueNative(context.thread_context, spRegNum(reg_context), reg_context)).* = new_sp; (try regValueNative(context.thread_context, ip_reg_num, reg_context)).* = new_ip; @@ -1417,7 +1410,7 @@ pub fn unwindFrameMachO( break :blk new_ip; }, .DWARF => { - return unwindFrameMachODwarf(allocator, base_address, context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf)); + return unwindFrameMachODwarf(allocator, base_address, context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.x86_64.dwarf)); }, }, .aarch64, .aarch64_be => switch (encoding.mode.arm64) { @@ -1426,25 +1419,16 @@ pub fn unwindFrameMachO( const sp = (try regValueNative(context.thread_context, spRegNum(reg_context), reg_context)).*; const new_sp = sp + encoding.value.arm64.frameless.stack_size * 16; const new_ip = (try regValueNative(context.thread_context, 30, reg_context)).*; - if (ma.load(usize, new_sp) == null) return error.InvalidUnwindInfo; (try regValueNative(context.thread_context, spRegNum(reg_context), reg_context)).* = new_sp; break :blk new_ip; }, .DWARF => { - return unwindFrameMachODwarf(allocator, base_address, context, ma, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf)); + return unwindFrameMachODwarf(allocator, base_address, context, eh_frame orelse return error.MissingEhFrame, @intCast(encoding.value.arm64.dwarf)); }, .FRAME => blk: { const fp = (try regValueNative(context.thread_context, fpRegNum(reg_context), reg_context)).*; - const new_sp = fp + 16; const ip_ptr = fp + @sizeOf(usize); - const num_restored_pairs: usize = - @popCount(@as(u5, @bitCast(encoding.value.arm64.frame.x_reg_pairs))) + - @popCount(@as(u4, @bitCast(encoding.value.arm64.frame.d_reg_pairs))); - const min_reg_addr = fp - num_restored_pairs * 2 * @sizeOf(usize); - - if (ma.load(usize, new_sp) == null or ma.load(usize, min_reg_addr) == null) return error.InvalidUnwindInfo; - var reg_addr = fp - @sizeOf(usize); inline for (@typeInfo(@TypeOf(encoding.value.arm64.frame.x_reg_pairs)).@"struct".fields, 0..) |field, i| { if (@field(encoding.value.arm64.frame.x_reg_pairs, field.name) != 0) { @@ -1566,7 +1550,6 @@ pub fn unwindFrameDwarf( di: *Dwarf, base_address: usize, context: *UnwindContext, - ma: *std.debug.MemoryAccessor, explicit_fde_offset: ?usize, ) !usize { if (!supports_unwinding) return error.UnsupportedCpuArchitecture; @@ -1584,14 +1567,14 @@ pub fn unwindFrameDwarf( .endian = di.endian, }; - const fde_entry_header = try Dwarf.EntryHeader.read(&fbr, null, dwarf_section); + const fde_entry_header = try Dwarf.EntryHeader.read(&fbr, dwarf_section); if (fde_entry_header.type != .fde) return error.MissingFDE; const cie_offset = fde_entry_header.type.fde; try fbr.seekTo(cie_offset); fbr.endian = native_endian; - const cie_entry_header = try Dwarf.EntryHeader.read(&fbr, null, dwarf_section); + const cie_entry_header = try Dwarf.EntryHeader.read(&fbr, dwarf_section); if (cie_entry_header.type != .cie) return Dwarf.bad(); const cie = try Dwarf.CommonInformationEntry.parse( @@ -1619,13 +1602,16 @@ pub fn unwindFrameDwarf( // back to loading `.eh_frame`/`.debug_frame` and using those from that point on. if (di.eh_frame_hdr) |header| hdr: { - const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null; + const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else { + try di.scanCieFdeInfo(allocator, base_address); + di.eh_frame_hdr = null; + break :hdr; + }; var cie: Dwarf.CommonInformationEntry = undefined; var fde: Dwarf.FrameDescriptionEntry = undefined; header.findEntry( - ma, eh_frame_len, @intFromPtr(di.section(.eh_frame_hdr).?.ptr), context.pc, @@ -1669,7 +1655,6 @@ pub fn unwindFrameDwarf( var expression_context: Dwarf.expression.Context = .{ .format = cie.format, - .memory_accessor = ma, .compile_unit = di.findCompileUnit(fde.pc_begin) catch null, .thread_context = context.thread_context, .reg_context = context.reg_context, @@ -1704,7 +1689,6 @@ pub fn unwindFrameDwarf( else => return error.InvalidCFARule, }; - if (ma.load(usize, context.cfa.?) == null) return error.InvalidCFA; expression_context.cfa = context.cfa; // Buffering the modifications is done because copying the thread context is not portable, @@ -1740,12 +1724,7 @@ pub fn unwindFrameDwarf( .prev = prev, }; - try column.resolveValue( - context, - expression_context, - ma, - src, - ); + try column.resolveValue(context, expression_context, src); } } @@ -1833,7 +1812,6 @@ fn unwindFrameMachODwarf( allocator: Allocator, base_address: usize, context: *UnwindContext, - ma: *std.debug.MemoryAccessor, eh_frame: []const u8, fde_offset: usize, ) !usize { @@ -1848,7 +1826,7 @@ fn unwindFrameMachODwarf( .owned = false, }; - return unwindFrameDwarf(allocator, &di, base_address, context, ma, fde_offset); + return unwindFrameDwarf(allocator, &di, base_address, context, fde_offset); } /// This is a virtual machine that runs DWARF call frame instructions. @@ -1898,7 +1876,6 @@ pub const VirtualMachine = struct { self: Column, context: *SelfInfo.UnwindContext, expression_context: std.debug.Dwarf.expression.Context, - ma: *std.debug.MemoryAccessor, out: []u8, ) !void { switch (self.rule) { @@ -1919,7 +1896,6 @@ pub const VirtualMachine = struct { .offset => |offset| { if (context.cfa) |cfa| { const addr = try applyOffset(cfa, offset); - if (ma.load(usize, addr) == null) return error.InvalidAddress; const ptr: *const usize = @ptrFromInt(addr); mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian); } else return error.InvalidCFA; @@ -1942,7 +1918,6 @@ pub const VirtualMachine = struct { break :blk v.generic; } else return error.NoExpressionValue; - if (ma.load(usize, addr) == null) return error.InvalidExpressionAddress; const ptr: *usize = @ptrFromInt(addr); mem.writeInt(usize, out[0..@sizeOf(usize)], ptr.*, native_endian); },