Skip to content

Commit b4b2871

Browse files
committed
Remove state from std.debug.MemoryAccessor
1 parent b8be525 commit b4b2871

File tree

6 files changed

+47
-155
lines changed

6 files changed

+47
-155
lines changed

lib/std/debug.zig

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,6 @@ pub const StackIterator = struct {
767767
first_address: ?usize,
768768
// Last known value of the frame pointer register.
769769
fp: usize,
770-
ma: MemoryAccessor = MemoryAccessor.init,
771770

772771
// When SelfInfo and a register context is available, this iterator can unwind
773772
// stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer),
@@ -819,7 +818,6 @@ pub const StackIterator = struct {
819818
}
820819

821820
pub fn deinit(it: *StackIterator) void {
822-
it.ma.deinit();
823821
if (have_ucontext and it.unwind_state != null) it.unwind_state.?.dwarf_context.deinit();
824822
}
825823

@@ -890,7 +888,6 @@ pub const StackIterator = struct {
890888
unwind_state.debug_info.allocator,
891889
module.base_address,
892890
&unwind_state.dwarf_context,
893-
&it.ma,
894891
unwind_info,
895892
module.eh_frame,
896893
)) |return_address| {
@@ -909,7 +906,6 @@ pub const StackIterator = struct {
909906
di,
910907
module.base_address,
911908
&unwind_state.dwarf_context,
912-
&it.ma,
913909
null,
914910
);
915911
} else return error.MissingDebugInfo;
@@ -945,15 +941,15 @@ pub const StackIterator = struct {
945941

946942
// Sanity check.
947943
if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) return null;
948-
const new_fp = math.add(usize, it.ma.load(usize, fp) orelse return null, fp_bias) catch
944+
const new_fp = math.add(usize, MemoryAccessor.load(usize, fp) orelse return null, fp_bias) catch
949945
return null;
950946

951947
// Sanity check: the stack grows down thus all the parent frames must be
952948
// be at addresses that are greater (or equal) than the previous one.
953949
// A zero frame pointer often signals this is the last frame, that case
954950
// is gracefully handled by the next call to next_internal.
955951
if (new_fp != 0 and new_fp < it.fp) return null;
956-
const new_pc = it.ma.load(usize, math.add(usize, fp, pc_offset) catch return null) orelse
952+
const new_pc = MemoryAccessor.load(usize, math.add(usize, fp, pc_offset) catch return null) orelse
957953
return null;
958954

959955
it.fp = new_fp;

lib/std/debug/Dwarf.zig

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,11 @@ pub const ExceptionFrameHeader = struct {
348348
};
349349
}
350350

351-
fn isValidPtr(
352-
self: ExceptionFrameHeader,
353-
comptime T: type,
354-
ptr: usize,
355-
ma: *MemoryAccessor,
356-
eh_frame_len: ?usize,
357-
) bool {
351+
fn isValidPtr(self: ExceptionFrameHeader, comptime T: type, ptr: usize, eh_frame_len: ?usize) bool {
358352
if (eh_frame_len) |len| {
359353
return ptr >= self.eh_frame_ptr and ptr <= self.eh_frame_ptr + len - @sizeOf(T);
360354
} else {
361-
return ma.load(T, ptr) != null;
355+
return MemoryAccessor.load(T, ptr) != null;
362356
}
363357
}
364358

@@ -369,7 +363,6 @@ pub const ExceptionFrameHeader = struct {
369363
/// If `eh_frame_len` is provided, then these checks can be skipped.
370364
pub fn findEntry(
371365
self: ExceptionFrameHeader,
372-
ma: *MemoryAccessor,
373366
eh_frame_len: ?usize,
374367
eh_frame_hdr_ptr: usize,
375368
pc: usize,
@@ -430,15 +423,15 @@ pub const ExceptionFrameHeader = struct {
430423
.endian = native_endian,
431424
};
432425

433-
const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
434-
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();
426+
const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, eh_frame_len == null, .eh_frame);
427+
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]), true, eh_frame_len)) return bad();
435428
if (fde_entry_header.type != .fde) return bad();
436429

437430
// CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable
438431
const cie_offset = fde_entry_header.type.fde;
439432
try eh_frame_fbr.seekTo(cie_offset);
440-
const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame);
441-
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();
433+
const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, eh_frame_len == null, .eh_frame);
434+
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]), true, eh_frame_len)) return bad();
442435
if (cie_entry_header.type != .cie) return bad();
443436

444437
cie.* = try CommonInformationEntry.parse(
@@ -485,15 +478,11 @@ pub const EntryHeader = struct {
485478

486479
/// Reads a header for either an FDE or a CIE, then advances the fbr to the position after the trailing structure.
487480
/// `fbr` must be a FixedBufferReader backed by either the .eh_frame or .debug_frame sections.
488-
pub fn read(
489-
fbr: *FixedBufferReader,
490-
opt_ma: ?*MemoryAccessor,
491-
dwarf_section: Section.Id,
492-
) !EntryHeader {
481+
pub fn read(fbr: *FixedBufferReader, checked: bool, dwarf_section: Section.Id) !EntryHeader {
493482
assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame);
494483

495484
const length_offset = fbr.pos;
496-
const unit_header = try readUnitHeader(fbr, opt_ma);
485+
const unit_header = try readUnitHeader(fbr, checked);
497486
const unit_length = cast(usize, unit_header.unit_length) orelse return bad();
498487
if (unit_length == 0) return .{
499488
.length_offset = length_offset,
@@ -505,8 +494,8 @@ pub const EntryHeader = struct {
505494
const end_offset = start_offset + unit_length;
506495
defer fbr.pos = end_offset;
507496

508-
const id = try if (opt_ma) |ma|
509-
fbr.readAddressChecked(unit_header.format, ma)
497+
const id = try if (checked)
498+
fbr.readAddressChecked(unit_header.format)
510499
else
511500
fbr.readAddress(unit_header.format);
512501
const entry_bytes = fbr.buf[fbr.pos..end_offset];
@@ -855,7 +844,7 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void {
855844
while (this_unit_offset < fbr.buf.len) {
856845
try fbr.seekTo(this_unit_offset);
857846

858-
const unit_header = try readUnitHeader(&fbr, null);
847+
const unit_header = try readUnitHeader(&fbr, false);
859848
if (unit_header.unit_length == 0) return;
860849
const next_offset = unit_header.header_length + unit_header.unit_length;
861850

@@ -1044,7 +1033,7 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator) ScanError!void {
10441033
while (this_unit_offset < fbr.buf.len) {
10451034
try fbr.seekTo(this_unit_offset);
10461035

1047-
const unit_header = try readUnitHeader(&fbr, null);
1036+
const unit_header = try readUnitHeader(&fbr, false);
10481037
if (unit_header.unit_length == 0) return;
10491038
const next_offset = unit_header.header_length + unit_header.unit_length;
10501039

@@ -1426,7 +1415,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) !
14261415
};
14271416
try fbr.seekTo(line_info_offset);
14281417

1429-
const unit_header = try readUnitHeader(&fbr, null);
1418+
const unit_header = try readUnitHeader(&fbr, false);
14301419
if (unit_header.unit_length == 0) return missing();
14311420

14321421
const next_offset = unit_header.header_length + unit_header.unit_length;
@@ -1987,8 +1976,8 @@ const UnitHeader = struct {
19871976
unit_length: u64,
19881977
};
19891978

1990-
fn readUnitHeader(fbr: *FixedBufferReader, opt_ma: ?*MemoryAccessor) ScanError!UnitHeader {
1991-
return switch (try if (opt_ma) |ma| fbr.readIntChecked(u32, ma) else fbr.readInt(u32)) {
1979+
fn readUnitHeader(fbr: *FixedBufferReader, checked: bool) ScanError!UnitHeader {
1980+
return switch (try if (checked) fbr.readIntChecked(u32) else fbr.readInt(u32)) {
19921981
0...0xfffffff0 - 1 => |unit_length| .{
19931982
.format = .@"32",
19941983
.header_length = 4,
@@ -1998,7 +1987,7 @@ fn readUnitHeader(fbr: *FixedBufferReader, opt_ma: ?*MemoryAccessor) ScanError!U
19981987
0xffffffff => .{
19991988
.format = .@"64",
20001989
.header_length = 12,
2001-
.unit_length = try if (opt_ma) |ma| fbr.readIntChecked(u64, ma) else fbr.readInt(u64),
1990+
.unit_length = try if (checked) fbr.readIntChecked(u64) else fbr.readInt(u64),
20021991
},
20031992
};
20041993
}

lib/std/debug/Dwarf/expression.zig

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ const assert = std.debug.assert;
1515
pub const Context = struct {
1616
/// The dwarf format of the section this expression is in
1717
format: std.dwarf.Format = .@"32",
18-
/// If specified, any addresses will pass through before being accessed
19-
memory_accessor: ?*std.debug.MemoryAccessor = null,
18+
/// When true, addresses will be validated before being accessed
19+
check_memory: bool = false,
2020
/// The compilation unit this expression relates to, if any
2121
compile_unit: ?*const std.debug.Dwarf.CompileUnit = null,
2222
/// When evaluating a user-presented expression, this is the address of the object being evaluated
@@ -465,12 +465,12 @@ pub fn StackMachine(comptime options: Options) type {
465465
else => unreachable,
466466
};
467467

468-
if (context.memory_accessor) |memory_accessor| {
468+
if (context.check_memory) {
469469
if (!switch (size) {
470-
1 => memory_accessor.load(u8, addr) != null,
471-
2 => memory_accessor.load(u16, addr) != null,
472-
4 => memory_accessor.load(u32, addr) != null,
473-
8 => memory_accessor.load(u64, addr) != null,
470+
1 => std.debug.MemoryAccessor.load(u8, addr) != null,
471+
2 => std.debug.MemoryAccessor.load(u16, addr) != null,
472+
4 => std.debug.MemoryAccessor.load(u32, addr) != null,
473+
8 => std.debug.MemoryAccessor.load(u64, addr) != null,
474474
else => return error.InvalidExpression,
475475
}) return error.InvalidExpression;
476476
}

lib/std/debug/FixedBufferReader.zig

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ pub fn readInt(fbr: *FixedBufferReader, comptime T: type) Error!T {
3838
return std.mem.readInt(T, fbr.buf[fbr.pos..][0..size], fbr.endian);
3939
}
4040

41-
pub fn readIntChecked(
42-
fbr: *FixedBufferReader,
43-
comptime T: type,
44-
ma: *MemoryAccessor,
45-
) Error!T {
46-
if (ma.load(T, @intFromPtr(fbr.buf[fbr.pos..].ptr)) == null)
41+
pub fn readIntChecked(fbr: *FixedBufferReader, comptime T: type) Error!T {
42+
if (MemoryAccessor.load(T, @intFromPtr(fbr.buf[fbr.pos..].ptr)) == null)
4743
return error.InvalidBuffer;
4844

4945
return fbr.readInt(T);
@@ -64,14 +60,10 @@ pub fn readAddress(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64
6460
};
6561
}
6662

67-
pub fn readAddressChecked(
68-
fbr: *FixedBufferReader,
69-
format: std.dwarf.Format,
70-
ma: *MemoryAccessor,
71-
) Error!u64 {
63+
pub fn readAddressChecked(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64 {
7264
return switch (format) {
73-
.@"32" => try fbr.readIntChecked(u32, ma),
74-
.@"64" => try fbr.readIntChecked(u64, ma),
65+
.@"32" => try fbr.readIntChecked(u32),
66+
.@"64" => try fbr.readIntChecked(u64),
7567
};
7668
}
7769

lib/std/debug/MemoryAccessor.zig

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -11,90 +11,11 @@ const page_size_min = std.heap.page_size_min;
1111

1212
const MemoryAccessor = @This();
1313

14-
var cached_pid: posix.pid_t = -1;
15-
16-
mem: switch (native_os) {
17-
.linux => File,
18-
else => void,
19-
},
20-
21-
pub const init: MemoryAccessor = .{
22-
.mem = switch (native_os) {
23-
.linux => .{ .handle = -1 },
24-
else => {},
25-
},
26-
};
27-
28-
pub fn deinit(ma: *MemoryAccessor) void {
29-
switch (native_os) {
30-
.linux => switch (ma.mem.handle) {
31-
-2, -1 => {},
32-
else => ma.mem.close(),
33-
},
34-
else => {},
35-
}
36-
ma.* = undefined;
37-
}
38-
39-
fn read(ma: *MemoryAccessor, address: usize, buf: []u8) bool {
40-
switch (native_os) {
41-
.linux => linux: switch (ma.mem.handle) {
42-
-2 => break :linux,
43-
-1 => {
44-
const linux = std.os.linux;
45-
const pid = switch (@atomicLoad(posix.pid_t, &cached_pid, .monotonic)) {
46-
-1 => pid: {
47-
const pid = linux.getpid();
48-
@atomicStore(posix.pid_t, &cached_pid, pid, .monotonic);
49-
break :pid pid;
50-
},
51-
else => |pid| pid,
52-
};
53-
const bytes_read = linux.process_vm_readv(
54-
pid,
55-
&.{.{ .base = buf.ptr, .len = buf.len }},
56-
&.{.{ .base = @ptrFromInt(address), .len = buf.len }},
57-
0,
58-
);
59-
switch (linux.E.init(bytes_read)) {
60-
.SUCCESS => return bytes_read == buf.len,
61-
.FAULT => return false,
62-
.INVAL => unreachable, // EINVAL is returned when flags to process_vm_readv is non-zero
63-
.SRCH => {
64-
// process with pid does not exist, but it should be our pid, so we'll try again.
65-
// This can happen after a call to fork() without a corresponding exec()
66-
const newpid = linux.getpid();
67-
std.debug.assert(newpid != pid);
68-
@atomicStore(posix.pid_t, &cached_pid, newpid, .monotonic);
69-
continue :linux -1;
70-
},
71-
.PERM => {}, // Known to happen in containers.
72-
.NOMEM => {},
73-
.NOSYS => {}, // QEMU is known not to implement this syscall.
74-
else => unreachable, // unexpected
75-
}
76-
var path_buf: [
77-
std.fmt.count("/proc/{d}/mem", .{std.math.minInt(posix.pid_t)})
78-
]u8 = undefined;
79-
const path = std.fmt.bufPrint(&path_buf, "/proc/{d}/mem", .{pid}) catch
80-
unreachable;
81-
ma.mem = std.fs.openFileAbsolute(path, .{}) catch {
82-
ma.mem.handle = -2;
83-
break :linux;
84-
};
85-
},
86-
else => return (ma.mem.pread(buf, address) catch return false) == buf.len,
87-
},
88-
else => {},
89-
}
90-
if (!isValidMemory(address)) return false;
91-
@memcpy(buf, @as([*]const u8, @ptrFromInt(address)));
92-
return true;
93-
}
94-
95-
pub fn load(ma: *MemoryAccessor, comptime Type: type, address: usize) ?Type {
14+
pub fn load(comptime Type: type, address: usize) ?Type {
15+
if (!isValidMemory(address)) return null;
9616
var result: Type = undefined;
97-
return if (ma.read(address, std.mem.asBytes(&result))) result else null;
17+
@memcpy(std.mem.asBytes(&result), @as([*]const u8, @ptrFromInt(address)));
18+
return result;
9819
}
9920

10021
pub fn isValidMemory(address: usize) bool {

0 commit comments

Comments
 (0)