mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
linux: rework getcontext to closer match the specification (saved IP/SP match the state after it would return)
debug: fixup ucontext_t check
This commit is contained in:
parent
89ef004646
commit
caa334712f
@ -136,7 +136,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
pub const StackTraceContext = blk: {
|
||||
if (native_os == .windows) {
|
||||
break :blk std.os.windows.CONTEXT;
|
||||
} else if (@hasDecl(os.system, "ucontext_t")) {
|
||||
} else if (StackIterator.supports_context) {
|
||||
break :blk os.ucontext_t;
|
||||
} else {
|
||||
break :blk void;
|
||||
|
||||
@ -394,28 +394,51 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
|
||||
return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index;
|
||||
}
|
||||
|
||||
pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
noinline fn getContextReturnAddress() usize {
|
||||
return @returnAddress();
|
||||
}
|
||||
|
||||
pub fn getContextInternal() callconv(.Naked) void {
|
||||
asm volatile (
|
||||
\\ movl %%edi, (%[edi_offset])(%[context])
|
||||
\\ movl %%esi, (%[esi_offset])(%[context])
|
||||
\\ movl %%ebp, (%[ebp_offset])(%[context])
|
||||
\\ movl %%esp, (%[esp_offset])(%[context])
|
||||
\\ movl %%ebx, (%[ebx_offset])(%[context])
|
||||
\\ movl %%edx, (%[edx_offset])(%[context])
|
||||
\\ movl %%ecx, (%[ecx_offset])(%[context])
|
||||
\\ movl %%eax, (%[eax_offset])(%[context])
|
||||
\\ movl $0, (%[flags_offset])(%%edx)
|
||||
\\ movl $0, (%[link_offset])(%%edx)
|
||||
\\ movl %%edi, (%[edi_offset])(%%edx)
|
||||
\\ movl %%esi, (%[esi_offset])(%%edx)
|
||||
\\ movl %%ebp, (%[ebp_offset])(%%edx)
|
||||
\\ movl %%ebx, (%[ebx_offset])(%%edx)
|
||||
\\ movl %%edx, (%[edx_offset])(%%edx)
|
||||
\\ movl %%ecx, (%[ecx_offset])(%%edx)
|
||||
\\ movl %%eax, (%[eax_offset])(%%edx)
|
||||
\\ movl (%%esp), %%ecx
|
||||
\\ movl %%ecx, (%[eip_offset])(%%edx)
|
||||
\\ leal 4(%%esp), %%ecx
|
||||
\\ movl %%ecx, (%[esp_offset])(%%edx)
|
||||
\\ xorl %%ecx, %%ecx
|
||||
\\ movw %%fs, %%cx
|
||||
\\ movl %%ecx, (%[fs_offset])(%[context])
|
||||
\\ leal (%[regspace_offset])(%[context]), %%ecx
|
||||
\\ movl %%ecx, (%[fpregs_offset])(%[context])
|
||||
\\ movl %%ecx, (%[fs_offset])(%%edx)
|
||||
\\ leal (%[regspace_offset])(%%edx), %%ecx
|
||||
\\ movl %%ecx, (%[fpregs_offset])(%%edx)
|
||||
\\ fnstenv (%%ecx)
|
||||
\\ fldenv (%%ecx)
|
||||
\\ call getcontext_read_eip
|
||||
\\ getcontext_read_eip: pop %%ecx
|
||||
\\ movl %%ecx, (%[eip_offset])(%[context])
|
||||
\\ pushl %%ebx
|
||||
\\ pushl %%esi
|
||||
\\ xorl %%ebx, %%ebx
|
||||
\\ movl %[sigaltstack], %%eax
|
||||
\\ leal (%[stack_offset])(%%edx), %%ecx
|
||||
\\ int $0x80
|
||||
\\ cmpl $0, %%eax
|
||||
\\ jne return
|
||||
\\ movl %[sigprocmask], %%eax
|
||||
\\ xorl %%ecx, %%ecx
|
||||
\\ leal (%[sigmask_offset])(%%edx), %%edx
|
||||
\\ movl %[sigset_size], %%esi
|
||||
\\ int $0x80
|
||||
\\ return:
|
||||
\\ popl %%esi
|
||||
\\ popl %%ebx
|
||||
:
|
||||
: [context] "{edi}" (context),
|
||||
: [flags_offset] "p" (@offsetOf(ucontext_t, "flags")),
|
||||
[link_offset] "p" (@offsetOf(ucontext_t, "link")),
|
||||
[edi_offset] "p" (comptime gpRegisterOffset(REG.EDI)),
|
||||
[esi_offset] "p" (comptime gpRegisterOffset(REG.ESI)),
|
||||
[ebp_offset] "p" (comptime gpRegisterOffset(REG.EBP)),
|
||||
@ -428,18 +451,24 @@ pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
[fs_offset] "p" (comptime gpRegisterOffset(REG.FS)),
|
||||
[fpregs_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
|
||||
[regspace_offset] "p" (@offsetOf(ucontext_t, "regspace")),
|
||||
[sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
|
||||
[stack_offset] "p" (@offsetOf(ucontext_t, "stack")),
|
||||
[sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
|
||||
[sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")),
|
||||
[sigset_size] "i" (linux.NSIG / 8),
|
||||
: "memory", "eax", "ecx", "edx"
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
// This method is used so that getContextInternal can control
|
||||
// its prologue in order to read ESP from a constant offset.
|
||||
// The unused &getContextInternal input is required so the function is included in the binary.
|
||||
return asm volatile (
|
||||
\\ call os.linux.x86.getContextInternal
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [context] "{edx}" (context),
|
||||
[getContextInternal] "X" (&getContextInternal),
|
||||
: "memory", "ecx"
|
||||
);
|
||||
|
||||
// TODO: Read CS/SS registers?
|
||||
// TODO: Store mxcsr state, need an actual definition of fpstate for that
|
||||
|
||||
// TODO: `flags` isn't present in the getcontext man page, figure out what to write here
|
||||
context.flags = 0;
|
||||
context.link = null;
|
||||
|
||||
const altstack_result = linux.sigaltstack(null, &context.stack);
|
||||
if (altstack_result != 0) return altstack_result;
|
||||
|
||||
return linux.sigprocmask(0, null, &context.sigmask);
|
||||
}
|
||||
|
||||
@ -400,35 +400,53 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
|
||||
return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index;
|
||||
}
|
||||
|
||||
pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
fn getContextInternal() callconv(.Naked) void {
|
||||
// TODO: Read GS/FS registers?
|
||||
asm volatile (
|
||||
\\ movq %%r8, (%[r8_offset])(%[context])
|
||||
\\ movq %%r9, (%[r9_offset])(%[context])
|
||||
\\ movq %%r10, (%[r10_offset])(%[context])
|
||||
\\ movq %%r11, (%[r11_offset])(%[context])
|
||||
\\ movq %%r12, (%[r12_offset])(%[context])
|
||||
\\ movq %%r13, (%[r13_offset])(%[context])
|
||||
\\ movq %%r14, (%[r14_offset])(%[context])
|
||||
\\ movq %%r15, (%[r15_offset])(%[context])
|
||||
\\ movq %%rdi, (%[rdi_offset])(%[context])
|
||||
\\ movq %%rsi, (%[rsi_offset])(%[context])
|
||||
\\ movq %%rbp, (%[rbp_offset])(%[context])
|
||||
\\ movq %%rbx, (%[rbx_offset])(%[context])
|
||||
\\ movq %%rdx, (%[rdx_offset])(%[context])
|
||||
\\ movq %%rax, (%[rax_offset])(%[context])
|
||||
\\ movq %%rcx, (%[rcx_offset])(%[context])
|
||||
\\ movq %%rsp, (%[rsp_offset])(%[context])
|
||||
\\ leaq (%%rip), %%rcx
|
||||
\\ movq %%rcx, (%[rip_offset])(%[context])
|
||||
\\ movq $0, (%[flags_offset])(%%rdi)
|
||||
\\ movq $0, (%[link_offset])(%%rdi)
|
||||
\\ movq %%r8, (%[r8_offset])(%%rdi)
|
||||
\\ movq %%r9, (%[r9_offset])(%%rdi)
|
||||
\\ movq %%r10, (%[r10_offset])(%%rdi)
|
||||
\\ movq %%r11, (%[r11_offset])(%%rdi)
|
||||
\\ movq %%r12, (%[r12_offset])(%%rdi)
|
||||
\\ movq %%r13, (%[r13_offset])(%%rdi)
|
||||
\\ movq %%r14, (%[r14_offset])(%%rdi)
|
||||
\\ movq %%r15, (%[r15_offset])(%%rdi)
|
||||
\\ movq %%rdi, (%[rdi_offset])(%%rdi)
|
||||
\\ movq %%rsi, (%[rsi_offset])(%%rdi)
|
||||
\\ movq %%rbp, (%[rbp_offset])(%%rdi)
|
||||
\\ movq %%rbx, (%[rbx_offset])(%%rdi)
|
||||
\\ movq %%rdx, (%[rdx_offset])(%%rdi)
|
||||
\\ movq %%rax, (%[rax_offset])(%%rdi)
|
||||
\\ movq %%rcx, (%[rcx_offset])(%%rdi)
|
||||
\\ movq (%%rsp), %%rcx
|
||||
\\ movq %%rcx, (%[rip_offset])(%%rdi)
|
||||
\\ leaq 8(%%rsp), %%rcx
|
||||
\\ movq %%rcx, (%[rsp_offset])(%%rdi)
|
||||
\\ pushfq
|
||||
\\ popq (%[efl_offset])(%[context])
|
||||
\\ leaq (%[fpmem_offset])(%[context]), %%rcx
|
||||
\\ movq %%rcx, (%[fpstate_offset])(%[context])
|
||||
\\ popq (%[efl_offset])(%%rdi)
|
||||
\\ leaq (%[fpmem_offset])(%%rdi), %%rcx
|
||||
\\ movq %%rcx, (%[fpstate_offset])(%%rdi)
|
||||
\\ fnstenv (%%rcx)
|
||||
\\ fldenv (%%rcx)
|
||||
\\ stmxcsr (%[mxcsr_offset])(%[context])
|
||||
\\ stmxcsr (%[mxcsr_offset])(%%rdi)
|
||||
\\ leaq (%[stack_offset])(%%rdi), %%rsi
|
||||
\\ movq %%rdi, %%r8
|
||||
\\ xorq %%rdi, %%rdi
|
||||
\\ movq %[sigaltstack], %%rax
|
||||
\\ syscall
|
||||
\\ cmpq $0, %%rax
|
||||
\\ jne return
|
||||
\\ movq %[sigprocmask], %%rax
|
||||
\\ xorq %%rsi, %%rsi
|
||||
\\ leaq (%[sigmask_offset])(%%r8), %%rdx
|
||||
\\ movq %[sigset_size], %%r10
|
||||
\\ syscall
|
||||
\\ return:
|
||||
:
|
||||
: [context] "{rdi}" (context),
|
||||
: [flags_offset] "p" (@offsetOf(ucontext_t, "flags")),
|
||||
[link_offset] "p" (@offsetOf(ucontext_t, "link")),
|
||||
[r8_offset] "p" (comptime gpRegisterOffset(REG.R8)),
|
||||
[r9_offset] "p" (comptime gpRegisterOffset(REG.R9)),
|
||||
[r10_offset] "p" (comptime gpRegisterOffset(REG.R10)),
|
||||
@ -450,17 +468,24 @@ pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
[fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
|
||||
[fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")),
|
||||
[mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")),
|
||||
: "memory", "rcx"
|
||||
[sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
|
||||
[stack_offset] "p" (@offsetOf(ucontext_t, "stack")),
|
||||
[sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
|
||||
[sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")),
|
||||
[sigset_size] "i" (linux.NSIG / 8),
|
||||
: "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
|
||||
);
|
||||
}
|
||||
|
||||
pub inline fn getcontext(context: *ucontext_t) usize {
|
||||
// This method is used so that getContextInternal can control
|
||||
// its prologue in order to read RSP from a constant offset
|
||||
// The unused &getContextInternal input is required so the function is included in the binary.
|
||||
return asm volatile (
|
||||
\\ call os.linux.x86_64.getContextInternal
|
||||
: [ret] "={rax}" (-> usize),
|
||||
: [context] "{rdi}" (context),
|
||||
[getContextInternal] "X" (&getContextInternal),
|
||||
: "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
|
||||
);
|
||||
|
||||
// TODO: Read GS/FS registers?
|
||||
|
||||
// TODO: `flags` isn't present in the getcontext man page, figure out what to write here
|
||||
context.flags = 0;
|
||||
context.link = null;
|
||||
|
||||
const altstack_result = linux.sigaltstack(null, &context.stack);
|
||||
if (altstack_result != 0) return altstack_result;
|
||||
|
||||
return linux.sigprocmask(0, null, &context.sigmask);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user