| author | |
| committer | |
| log | caa334712fc8f540349e54fa3008aa3fdef64e13 |
| tree | 5cc39b79cc97a305cfbc981d9e426cf1896947d4 |
| parent | 89ef004646896a145ec0607678882a395fabda3d |
debug: fixup ucontext_t check3 files changed, 118 insertions(+), 64 deletions(-)
lib/std/debug.zig+1-1| ... | @@ -136,7 +136,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | ... | @@ -136,7 +136,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 136 | pub const StackTraceContext = blk: { | 136 | pub const StackTraceContext = blk: { |
| 137 | if (native_os == .windows) { | 137 | if (native_os == .windows) { |
| 138 | break :blk std.os.windows.CONTEXT; | 138 | break :blk std.os.windows.CONTEXT; |
| 139 | } else if (@hasDecl(os.system, "ucontext_t")) { | 139 | } else if (StackIterator.supports_context) { |
| 140 | break :blk os.ucontext_t; | 140 | break :blk os.ucontext_t; |
| 141 | } else { | 141 | } else { |
| 142 | break :blk void; | 142 | break :blk void; |
lib/std/os/linux/x86.zig+57-28| ... | @@ -394,28 +394,51 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize { | ... | @@ -394,28 +394,51 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize { |
| 394 | return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index; | 394 | return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | pub inline fn getcontext(context: *ucontext_t) usize { | 397 | noinline fn getContextReturnAddress() usize { |
| 398 | return @returnAddress(); | ||
| 399 | } | ||
| 400 | |||
| 401 | pub fn getContextInternal() callconv(.Naked) void { | ||
| 398 | asm volatile ( | 402 | asm volatile ( |
| 399 | \\ movl %%edi, (%[edi_offset])(%[context]) | 403 | \\ movl $0, (%[flags_offset])(%%edx) |
| 400 | \\ movl %%esi, (%[esi_offset])(%[context]) | 404 | \\ movl $0, (%[link_offset])(%%edx) |
| 401 | \\ movl %%ebp, (%[ebp_offset])(%[context]) | 405 | \\ movl %%edi, (%[edi_offset])(%%edx) |
| 402 | \\ movl %%esp, (%[esp_offset])(%[context]) | 406 | \\ movl %%esi, (%[esi_offset])(%%edx) |
| 403 | \\ movl %%ebx, (%[ebx_offset])(%[context]) | 407 | \\ movl %%ebp, (%[ebp_offset])(%%edx) |
| 404 | \\ movl %%edx, (%[edx_offset])(%[context]) | 408 | \\ movl %%ebx, (%[ebx_offset])(%%edx) |
| 405 | \\ movl %%ecx, (%[ecx_offset])(%[context]) | 409 | \\ movl %%edx, (%[edx_offset])(%%edx) |
| 406 | \\ movl %%eax, (%[eax_offset])(%[context]) | 410 | \\ movl %%ecx, (%[ecx_offset])(%%edx) |
| 411 | \\ movl %%eax, (%[eax_offset])(%%edx) | ||
| 412 | \\ movl (%%esp), %%ecx | ||
| 413 | \\ movl %%ecx, (%[eip_offset])(%%edx) | ||
| 414 | \\ leal 4(%%esp), %%ecx | ||
| 415 | \\ movl %%ecx, (%[esp_offset])(%%edx) | ||
| 407 | \\ xorl %%ecx, %%ecx | 416 | \\ xorl %%ecx, %%ecx |
| 408 | \\ movw %%fs, %%cx | 417 | \\ movw %%fs, %%cx |
| 409 | \\ movl %%ecx, (%[fs_offset])(%[context]) | 418 | \\ movl %%ecx, (%[fs_offset])(%%edx) |
| 410 | \\ leal (%[regspace_offset])(%[context]), %%ecx | 419 | \\ leal (%[regspace_offset])(%%edx), %%ecx |
| 411 | \\ movl %%ecx, (%[fpregs_offset])(%[context]) | 420 | \\ movl %%ecx, (%[fpregs_offset])(%%edx) |
| 412 | \\ fnstenv (%%ecx) | 421 | \\ fnstenv (%%ecx) |
| 413 | \\ fldenv (%%ecx) | 422 | \\ fldenv (%%ecx) |
| 414 | \\ call getcontext_read_eip | 423 | \\ pushl %%ebx |
| 415 | \\ getcontext_read_eip: pop %%ecx | 424 | \\ pushl %%esi |
| 416 | \\ movl %%ecx, (%[eip_offset])(%[context]) | 425 | \\ xorl %%ebx, %%ebx |
| 426 | \\ movl %[sigaltstack], %%eax | ||
| 427 | \\ leal (%[stack_offset])(%%edx), %%ecx | ||
| 428 | \\ int $0x80 | ||
| 429 | \\ cmpl $0, %%eax | ||
| 430 | \\ jne return | ||
| 431 | \\ movl %[sigprocmask], %%eax | ||
| 432 | \\ xorl %%ecx, %%ecx | ||
| 433 | \\ leal (%[sigmask_offset])(%%edx), %%edx | ||
| 434 | \\ movl %[sigset_size], %%esi | ||
| 435 | \\ int $0x80 | ||
| 436 | \\ return: | ||
| 437 | \\ popl %%esi | ||
| 438 | \\ popl %%ebx | ||
| 417 | : | 439 | : |
| 418 | : [context] "{edi}" (context), | 440 | : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")), |
| 441 | [link_offset] "p" (@offsetOf(ucontext_t, "link")), | ||
| 419 | [edi_offset] "p" (comptime gpRegisterOffset(REG.EDI)), | 442 | [edi_offset] "p" (comptime gpRegisterOffset(REG.EDI)), |
| 420 | [esi_offset] "p" (comptime gpRegisterOffset(REG.ESI)), | 443 | [esi_offset] "p" (comptime gpRegisterOffset(REG.ESI)), |
| 421 | [ebp_offset] "p" (comptime gpRegisterOffset(REG.EBP)), | 444 | [ebp_offset] "p" (comptime gpRegisterOffset(REG.EBP)), |
| ... | @@ -428,18 +451,24 @@ pub inline fn getcontext(context: *ucontext_t) usize { | ... | @@ -428,18 +451,24 @@ pub inline fn getcontext(context: *ucontext_t) usize { |
| 428 | [fs_offset] "p" (comptime gpRegisterOffset(REG.FS)), | 451 | [fs_offset] "p" (comptime gpRegisterOffset(REG.FS)), |
| 429 | [fpregs_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | 452 | [fpregs_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), |
| 430 | [regspace_offset] "p" (@offsetOf(ucontext_t, "regspace")), | 453 | [regspace_offset] "p" (@offsetOf(ucontext_t, "regspace")), |
| 431 | : "memory", "ecx" | 454 | [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)), |
| 455 | [stack_offset] "p" (@offsetOf(ucontext_t, "stack")), | ||
| 456 | [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)), | ||
| 457 | [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")), | ||
| 458 | [sigset_size] "i" (linux.NSIG / 8), | ||
| 459 | : "memory", "eax", "ecx", "edx" | ||
| 432 | ); | 460 | ); |
| 461 | } | ||
| 433 | 462 | ||
| 434 | // TODO: Read CS/SS registers? | 463 | pub inline fn getcontext(context: *ucontext_t) usize { |
| 435 | // TODO: Store mxcsr state, need an actual definition of fpstate for that | 464 | // This method is used so that getContextInternal can control |
| 436 | 465 | // its prologue in order to read ESP from a constant offset. | |
| 437 | // TODO: `flags` isn't present in the getcontext man page, figure out what to write here | 466 | // The unused &getContextInternal input is required so the function is included in the binary. |
| 438 | context.flags = 0; | 467 | return asm volatile ( |
| 439 | context.link = null; | 468 | \\ call os.linux.x86.getContextInternal |
| 440 | 469 | : [ret] "={eax}" (-> usize), | |
| 441 | const altstack_result = linux.sigaltstack(null, &context.stack); | 470 | : [context] "{edx}" (context), |
| 442 | if (altstack_result != 0) return altstack_result; | 471 | [getContextInternal] "X" (&getContextInternal), |
| 443 | 472 | : "memory", "ecx" | |
| 444 | return linux.sigprocmask(0, null, &context.sigmask); | 473 | ); |
| 445 | } | 474 | } |
lib/std/os/linux/x86_64.zig+60-35| ... | @@ -400,35 +400,53 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize { | ... | @@ -400,35 +400,53 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize { |
| 400 | return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index; | 400 | return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | pub inline fn getcontext(context: *ucontext_t) usize { | 403 | fn getContextInternal() callconv(.Naked) void { |
| 404 | // TODO: Read GS/FS registers? | ||
| 404 | asm volatile ( | 405 | asm volatile ( |
| 405 | \\ movq %%r8, (%[r8_offset])(%[context]) | 406 | \\ movq $0, (%[flags_offset])(%%rdi) |
| 406 | \\ movq %%r9, (%[r9_offset])(%[context]) | 407 | \\ movq $0, (%[link_offset])(%%rdi) |
| 407 | \\ movq %%r10, (%[r10_offset])(%[context]) | 408 | \\ movq %%r8, (%[r8_offset])(%%rdi) |
| 408 | \\ movq %%r11, (%[r11_offset])(%[context]) | 409 | \\ movq %%r9, (%[r9_offset])(%%rdi) |
| 409 | \\ movq %%r12, (%[r12_offset])(%[context]) | 410 | \\ movq %%r10, (%[r10_offset])(%%rdi) |
| 410 | \\ movq %%r13, (%[r13_offset])(%[context]) | 411 | \\ movq %%r11, (%[r11_offset])(%%rdi) |
| 411 | \\ movq %%r14, (%[r14_offset])(%[context]) | 412 | \\ movq %%r12, (%[r12_offset])(%%rdi) |
| 412 | \\ movq %%r15, (%[r15_offset])(%[context]) | 413 | \\ movq %%r13, (%[r13_offset])(%%rdi) |
| 413 | \\ movq %%rdi, (%[rdi_offset])(%[context]) | 414 | \\ movq %%r14, (%[r14_offset])(%%rdi) |
| 414 | \\ movq %%rsi, (%[rsi_offset])(%[context]) | 415 | \\ movq %%r15, (%[r15_offset])(%%rdi) |
| 415 | \\ movq %%rbp, (%[rbp_offset])(%[context]) | 416 | \\ movq %%rdi, (%[rdi_offset])(%%rdi) |
| 416 | \\ movq %%rbx, (%[rbx_offset])(%[context]) | 417 | \\ movq %%rsi, (%[rsi_offset])(%%rdi) |
| 417 | \\ movq %%rdx, (%[rdx_offset])(%[context]) | 418 | \\ movq %%rbp, (%[rbp_offset])(%%rdi) |
| 418 | \\ movq %%rax, (%[rax_offset])(%[context]) | 419 | \\ movq %%rbx, (%[rbx_offset])(%%rdi) |
| 419 | \\ movq %%rcx, (%[rcx_offset])(%[context]) | 420 | \\ movq %%rdx, (%[rdx_offset])(%%rdi) |
| 420 | \\ movq %%rsp, (%[rsp_offset])(%[context]) | 421 | \\ movq %%rax, (%[rax_offset])(%%rdi) |
| 421 | \\ leaq (%%rip), %%rcx | 422 | \\ movq %%rcx, (%[rcx_offset])(%%rdi) |
| 422 | \\ movq %%rcx, (%[rip_offset])(%[context]) | 423 | \\ movq (%%rsp), %%rcx |
| 424 | \\ movq %%rcx, (%[rip_offset])(%%rdi) | ||
| 425 | \\ leaq 8(%%rsp), %%rcx | ||
| 426 | \\ movq %%rcx, (%[rsp_offset])(%%rdi) | ||
| 423 | \\ pushfq | 427 | \\ pushfq |
| 424 | \\ popq (%[efl_offset])(%[context]) | 428 | \\ popq (%[efl_offset])(%%rdi) |
| 425 | \\ leaq (%[fpmem_offset])(%[context]), %%rcx | 429 | \\ leaq (%[fpmem_offset])(%%rdi), %%rcx |
| 426 | \\ movq %%rcx, (%[fpstate_offset])(%[context]) | 430 | \\ movq %%rcx, (%[fpstate_offset])(%%rdi) |
| 427 | \\ fnstenv (%%rcx) | 431 | \\ fnstenv (%%rcx) |
| 428 | \\ fldenv (%%rcx) | 432 | \\ fldenv (%%rcx) |
| 429 | \\ stmxcsr (%[mxcsr_offset])(%[context]) | 433 | \\ stmxcsr (%[mxcsr_offset])(%%rdi) |
| 434 | \\ leaq (%[stack_offset])(%%rdi), %%rsi | ||
| 435 | \\ movq %%rdi, %%r8 | ||
| 436 | \\ xorq %%rdi, %%rdi | ||
| 437 | \\ movq %[sigaltstack], %%rax | ||
| 438 | \\ syscall | ||
| 439 | \\ cmpq $0, %%rax | ||
| 440 | \\ jne return | ||
| 441 | \\ movq %[sigprocmask], %%rax | ||
| 442 | \\ xorq %%rsi, %%rsi | ||
| 443 | \\ leaq (%[sigmask_offset])(%%r8), %%rdx | ||
| 444 | \\ movq %[sigset_size], %%r10 | ||
| 445 | \\ syscall | ||
| 446 | \\ return: | ||
| 430 | : | 447 | : |
| 431 | : [context] "{rdi}" (context), | 448 | : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")), |
| 449 | [link_offset] "p" (@offsetOf(ucontext_t, "link")), | ||
| 432 | [r8_offset] "p" (comptime gpRegisterOffset(REG.R8)), | 450 | [r8_offset] "p" (comptime gpRegisterOffset(REG.R8)), |
| 433 | [r9_offset] "p" (comptime gpRegisterOffset(REG.R9)), | 451 | [r9_offset] "p" (comptime gpRegisterOffset(REG.R9)), |
| 434 | [r10_offset] "p" (comptime gpRegisterOffset(REG.R10)), | 452 | [r10_offset] "p" (comptime gpRegisterOffset(REG.R10)), |
| ... | @@ -450,17 +468,24 @@ pub inline fn getcontext(context: *ucontext_t) usize { | ... | @@ -450,17 +468,24 @@ pub inline fn getcontext(context: *ucontext_t) usize { |
| 450 | [fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | 468 | [fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), |
| 451 | [fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")), | 469 | [fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")), |
| 452 | [mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")), | 470 | [mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")), |
| 453 | : "memory", "rcx" | 471 | [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)), |
| 472 | [stack_offset] "p" (@offsetOf(ucontext_t, "stack")), | ||
| 473 | [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)), | ||
| 474 | [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")), | ||
| 475 | [sigset_size] "i" (linux.NSIG / 8), | ||
| 476 | : "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11" | ||
| 454 | ); | 477 | ); |
| 478 | } | ||
| 455 | 479 | ||
| 456 | // TODO: Read GS/FS registers? | 480 | pub inline fn getcontext(context: *ucontext_t) usize { |
| 457 | 481 | // This method is used so that getContextInternal can control | |
| 458 | // TODO: `flags` isn't present in the getcontext man page, figure out what to write here | 482 | // its prologue in order to read RSP from a constant offset |
| 459 | context.flags = 0; | 483 | // The unused &getContextInternal input is required so the function is included in the binary. |
| 460 | context.link = null; | 484 | return asm volatile ( |
| 461 | 485 | \\ call os.linux.x86_64.getContextInternal | |
| 462 | const altstack_result = linux.sigaltstack(null, &context.stack); | 486 | : [ret] "={rax}" (-> usize), |
| 463 | if (altstack_result != 0) return altstack_result; | 487 | : [context] "{rdi}" (context), |
| 464 | 488 | [getContextInternal] "X" (&getContextInternal), | |
| 465 | return linux.sigprocmask(0, null, &context.sigmask); | 489 | : "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11" |
| 490 | ); | ||
| 466 | } | 491 | } |