mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Our usage of `ucontext_t` in the standard library was kind of problematic. We unnecessarily mimiced libc-specific structures, and our `getcontext` implementation was overkill for our use case of stack tracing. This commit introduces a new namespace, `std.debug.cpu_context`, which contains "context" types for various architectures (currently x86, x86_64, ARM, and AARCH64) containing the general-purpose CPU registers; the ones needed in practice for stack unwinding. Each implementation has a function `current` which populates the structure using inline assembly. The structure is user-overrideable, though that should only be necessary if the standard library does not have an implementation for the *architecture*: that is to say, none of this is OS-dependent. Of course, in POSIX signal handlers, we get a `ucontext_t` from the kernel. The function `std.debug.cpu_context.fromPosixSignalContext` converts this to a `std.debug.cpu_context.Native` with a big ol' target switch. This functionality is not exposed from `std.c` or `std.posix`, and neither are `ucontext_t`, `mcontext_t`, or `getcontext`. The rationale is that these types and functions do not conform to a specific ABI, and in fact tend to get updated over time based on CPU features and extensions; in addition, different libcs use different structures which are "partially compatible" with the kernel structure. Overall, it's a mess, but all we need is the kernel context, so we can just define a kernel-compatible structure as long as we don't claim C compatibility by putting it in `std.c` or `std.posix`. This change resulted in a few nice `std.debug` simplifications, but nothing too noteworthy. However, the main benefit of this change is that DWARF unwinding---sometimes necessary for collecting stack traces reliably---now requires far less target-specific integration. Also fix a bug I noticed in `PageAllocator` (I found this due to a bug in my distro's QEMU distribution; thanks, broken QEMU patch!) and I think a couple of minor bugs in `std.debug`. Resolves: #23801 Resolves: #23802
123 lines
3.8 KiB
Zig
123 lines
3.8 KiB
Zig
const std = @import("../std.zig");
|
|
const fd_t = std.c.fd_t;
|
|
const off_t = std.c.off_t;
|
|
const unexpectedErrno = std.posix.unexpectedErrno;
|
|
const errno = std.posix.errno;
|
|
const builtin = @import("builtin");
|
|
|
|
pub const CopyFileRangeError = std.posix.UnexpectedError || error{
|
|
/// If infd is not open for reading or outfd is not open for writing, or
|
|
/// opened for writing with O_APPEND, or if infd and outfd refer to the
|
|
/// same file.
|
|
BadFileFlags,
|
|
/// If the copy exceeds the process's file size limit or the maximum
|
|
/// file size for the file system outfd re- sides on.
|
|
FileTooBig,
|
|
/// A signal interrupted the system call before it could be completed.
|
|
/// This may happen for files on some NFS mounts. When this happens,
|
|
/// the values pointed to by inoffp and outoffp are reset to the
|
|
/// initial values for the system call.
|
|
Interrupted,
|
|
/// One of:
|
|
/// * infd and outfd refer to the same file and the byte ranges overlap.
|
|
/// * The flags argument is not zero.
|
|
/// * Either infd or outfd refers to a file object that is not a regular file.
|
|
InvalidArguments,
|
|
/// An I/O error occurred while reading/writing the files.
|
|
InputOutput,
|
|
/// Corrupted data was detected while reading from a file system.
|
|
CorruptedData,
|
|
/// Either infd or outfd refers to a directory.
|
|
IsDir,
|
|
/// File system that stores outfd is full.
|
|
NoSpaceLeft,
|
|
};
|
|
|
|
pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: u32) CopyFileRangeError!usize {
|
|
const rc = std.c.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
|
|
switch (errno(rc)) {
|
|
.SUCCESS => return @intCast(rc),
|
|
.BADF => return error.BadFileFlags,
|
|
.FBIG => return error.FileTooBig,
|
|
.INTR => return error.Interrupted,
|
|
.INVAL => return error.InvalidArguments,
|
|
.IO => return error.InputOutput,
|
|
.INTEGRITY => return error.CorruptedData,
|
|
.ISDIR => return error.IsDir,
|
|
.NOSPC => return error.NoSpaceLeft,
|
|
else => |err| return unexpectedErrno(err),
|
|
}
|
|
}
|
|
|
|
pub const ucontext_t = extern struct {
|
|
sigmask: std.c.sigset_t,
|
|
mcontext: mcontext_t,
|
|
link: ?*ucontext_t,
|
|
stack: std.c.stack_t,
|
|
flags: c_int,
|
|
__spare__: [4]c_int,
|
|
const mcontext_t = switch (builtin.cpu.arch) {
|
|
.x86_64 => extern struct {
|
|
onstack: u64,
|
|
rdi: u64,
|
|
rsi: u64,
|
|
rdx: u64,
|
|
rcx: u64,
|
|
r8: u64,
|
|
r9: u64,
|
|
rax: u64,
|
|
rbx: u64,
|
|
rbp: u64,
|
|
r10: u64,
|
|
r11: u64,
|
|
r12: u64,
|
|
r13: u64,
|
|
r14: u64,
|
|
r15: u64,
|
|
trapno: u32,
|
|
fs: u16,
|
|
gs: u16,
|
|
addr: u64,
|
|
flags: u32,
|
|
es: u16,
|
|
ds: u16,
|
|
err: u64,
|
|
rip: u64,
|
|
cs: u64,
|
|
rflags: u64,
|
|
rsp: u64,
|
|
ss: u64,
|
|
len: u64,
|
|
fpformat: u64,
|
|
ownedfp: u64,
|
|
fpstate: [64]u64 align(16),
|
|
fsbase: u64,
|
|
gsbase: u64,
|
|
xfpustate: u64,
|
|
xfpustate_len: u64,
|
|
spare: [4]u64,
|
|
},
|
|
.aarch64 => extern struct {
|
|
gpregs: extern struct {
|
|
x: [30]u64,
|
|
lr: u64,
|
|
sp: u64,
|
|
elr: u64,
|
|
spsr: u32,
|
|
_pad: u32,
|
|
},
|
|
fpregs: extern struct {
|
|
q: [32]u128,
|
|
sr: u32,
|
|
cr: u32,
|
|
flags: u32,
|
|
_pad: u32,
|
|
},
|
|
flags: u32,
|
|
_pad: u32,
|
|
_spare: [8]u64,
|
|
},
|
|
else => void,
|
|
};
|
|
};
|