unit md_context; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses Windows, ntapi, ucontext, kern_thr, kern_proc; const XSTATE_LEGACY_FLOATING_POINT=0; XSTATE_LEGACY_SSE =1; XSTATE_GSSE =2; XSTATE_AVX =XSTATE_GSSE; XSTATE_MASK_LEGACY_FLOATING_POINT=(1 shl XSTATE_LEGACY_FLOATING_POINT); XSTATE_MASK_LEGACY_SSE =(1 shl XSTATE_LEGACY_SSE); XSTATE_MASK_LEGACY =(XSTATE_MASK_LEGACY_FLOATING_POINT or XSTATE_MASK_LEGACY_SSE); XSTATE_MASK_GSSE =(1 shl XSTATE_GSSE); XSTATE_MASK_AVX =(XSTATE_MASK_GSSE); const CONTEXT_XSTATE =(CONTEXT_AMD64 or $0040); CONTEXT_ALLX =(CONTEXT_ALL or CONTEXT_XSTATE); type PYMMCONTEXT=^TYMMCONTEXT; TYMMCONTEXT=packed record Ymm0 :M128A; Ymm1 :M128A; Ymm2 :M128A; Ymm3 :M128A; Ymm4 :M128A; Ymm5 :M128A; Ymm6 :M128A; Ymm7 :M128A; Ymm8 :M128A; Ymm9 :M128A; Ymm10:M128A; Ymm11:M128A; Ymm12:M128A; Ymm13:M128A; Ymm14:M128A; Ymm15:M128A; end; PXSTATE=^TXSTATE; TXSTATE=packed record Mask:QWORD; CompactionMask:QWORD; Reserved:array[0..5] of QWORD; YmmContext:TYMMCONTEXT; end; TXmmSaveArea = Windows.TXmmSaveArea; PXmmSaveArea = Windows.PXmmSaveArea; PCONTEXT_CHUNK=^TCONTEXT_CHUNK; TCONTEXT_CHUNK=packed record Offset:LONG; Length:ULONG; end; PCONTEXT_EX=^TCONTEXT_EX; TCONTEXT_EX=packed record All :TCONTEXT_CHUNK; Legacy:TCONTEXT_CHUNK; XState:TCONTEXT_CHUNK; _align:QWORD; end; const _ucodesel=(8 shl 3) or 3; _udatasel=(7 shl 3) or 3; _ufssel =(2 shl 3) or 3; _ugssel =(3 shl 3) or 3; __INITIAL_FPUCW__ =$037F; __INITIAL_MXCSR__ =$1F80; __INITIAL_MXCSR_MASK__=$FFBF; procedure teb_set_kernel(td:p_kthread); procedure teb_set_user (td:p_kthread); Function GetContextSize(ContextFlags:DWORD):QWORD; function InitializeContextExtended(data:Pointer;ContextFlags:DWORD):Pointer; function _get_ctx_flags(src:p_ucontext_t):DWORD; procedure _get_fpcontext(src:PCONTEXT;xstate:Pointer); procedure _set_fpcontext(dst:PCONTEXT;xstate:Pointer); procedure fpuinit(td:p_kthread); procedure _get_frame(src:PCONTEXT;dst:p_trapframe;xstate:Pointer;is_jit:Boolean); procedure _set_frame(dst:PCONTEXT;src:p_trapframe;xstate:Pointer;is_jit:Boolean); procedure _get_ucontext(src:PCONTEXT;dst:p_ucontext_t); procedure _set_ucontext(dst:PCONTEXT;src:p_ucontext_t); function md_get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer; procedure ipi_sigreturn; function ipi_send_cpu(td:p_kthread):Integer; implementation uses errno, systm, kern_psl, signal, md_sleep; // procedure teb_set_kernel(td:p_kthread); begin //teb stack if ((td^.pcb_flags and PCB_IS_JIT)=0) then begin td^.td_teb^.sttop:=td^.td_kstack.sttop; td^.td_teb^.stack:=td^.td_kstack.stack; end; //teb stack end; procedure teb_set_user(td:p_kthread); begin //teb stack if ((td^.pcb_flags and PCB_IS_JIT)=0) then begin if (sigonstack(td^.td_frame.tf_rsp)<>0) then begin td^.td_teb^.stack:=td^.td_sigstk.ss_sp; td^.td_teb^.sttop:=td^.td_sigstk.ss_sp-td^.td_sigstk.ss_size; end else begin td^.td_teb^.stack:=td^.td_ustack.stack; td^.td_teb^.sttop:=td^.td_ustack.sttop; end; end; //teb stack end; function GetEnabledXStateFeatures:QWORD; stdcall external 'kernel32'; function InitializeContext( Buffer:Pointer; ContextFlags:DWORD; Context:Pointer; ContextLength:PDWORD ):BOOL; stdcall external 'kernel32'; function SetXStateFeaturesMask( Context:PCONTEXT; FeatureMask:QWORD ):BOOL; stdcall external 'kernel32'; Function GetContextSize(ContextFlags:DWORD):QWORD; begin Result:=0; InitializeContext(nil, ContextFlags, nil, @Result); end; function InitializeContextExtended(data:Pointer;ContextFlags:DWORD):Pointer; var ContextSize:DWORD; FeatureMask:QWORD; XstateMaskf:QWORD; XstateMaskr:QWORD; begin Result:=nil; if (data=nil) then Exit; ContextSize:=GetContextSize(ContextFlags); if (ContextSize=0) then Exit; FillChar(data^,ContextSize,0); if not InitializeContext(data, ContextFlags, @Result, @ContextSize) then begin Exit(nil); end; if ((ContextFlags and $40)<>0) then begin FeatureMask:=GetEnabledXStateFeatures; XstateMaskf:=FeatureMask and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX); XstateMaskr:=ContextFlags and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX); if (XstateMaskf<>XstateMaskr) then begin Exit(nil); end; if not SetXStateFeaturesMask(Result,XstateMaskr) then begin Exit(nil); end; end; end; function _get_ctx_flags(src:p_ucontext_t):DWORD; begin Result:=0; if ((src^.uc_flags and _UC_CPU)<>0) then begin Result:=Result or CONTEXT_INTEGER or CONTEXT_CONTROL; end; if ((src^.uc_mcontext.mc_flags and _MC_HASSEGS)<>0) then begin Result:=Result or CONTEXT_SEGMENTS; end; if ((src^.uc_mcontext.mc_flags and _MC_HASFPXSTATE)<>0) then begin Result:=Result or CONTEXT_FLOATING_POINT or CONTEXT_XSTATE; end; Result:=Result and (not CONTEXT_AMD64); end; function _get_ctx_flags(src:p_trapframe):DWORD; begin Result:=CONTEXT_INTEGER or CONTEXT_CONTROL; if ((src^.tf_flags and _MC_HASSEGS)<>0) then begin Result:=Result or CONTEXT_SEGMENTS; end; if ((src^.tf_flags and _MC_HASFPXSTATE)<>0) then begin Result:=Result or CONTEXT_FLOATING_POINT or CONTEXT_XSTATE; end; Result:=Result and (not CONTEXT_AMD64); end; procedure _get_fpcontext(src:PCONTEXT;xstate:Pointer); var context_ex:PCONTEXT_EX; xs:PXSTATE; uc_xsave :PXmmSaveArea; uc_xstate:PXSTATE; begin if (src=nil) or (xstate=nil) then Exit; context_ex:=PCONTEXT_EX(src+1); xs:=PXSTATE(PByte(context_ex)+context_ex^.XState.Offset); uc_xsave :=PXmmSaveArea(xstate); uc_xstate:=PXSTATE(uc_xsave+1); uc_xsave^:=src^.FltSave; uc_xstate^:=xs^; end; procedure _set_fpcontext(dst:PCONTEXT;xstate:Pointer); var context_ex:PCONTEXT_EX; xs:PXSTATE; uc_xsave :PXmmSaveArea; uc_xstate:PXSTATE; begin if (dst=nil) or (xstate=nil) then Exit; context_ex:=PCONTEXT_EX(dst+1); xs:=PXSTATE(PByte(context_ex)+context_ex^.XState.Offset); uc_xsave :=PXmmSaveArea(xstate); uc_xstate:=PXSTATE(uc_xsave+1); dst^.MxCsr:=uc_xsave^.MxCsr; dst^.FltSave:=uc_xsave^; xs^:=uc_xstate^; end; procedure fpuinit(td:p_kthread); var uc_xsave :PXmmSaveArea; uc_xstate:PXSTATE; begin if (td=nil) then Exit; uc_xsave :=PXmmSaveArea(@td^.td_fpstate); uc_xstate:=PXSTATE(uc_xsave+1); //uc_xstate^.Mask:= uc_xstate^.CompactionMask:=GetEnabledXStateFeatures; uc_xstate^.CompactionMask:=uc_xstate^.CompactionMask and (XSTATE_MASK_LEGACY or XSTATE_MASK_AVX); uc_xstate^.CompactionMask:=uc_xstate^.CompactionMask or QWORD(1 shl 63); uc_xsave^.ControlWord:=__INITIAL_FPUCW__; //uc_xsave^.StatusWord: WORD; uc_xsave^.MxCsr :=__INITIAL_MXCSR__; uc_xsave^.MxCsr_Mask :=__INITIAL_MXCSR_MASK__; td^.td_frame.tf_flags:=td^.td_frame.tf_flags or TF_HASFPXSTATE; end; procedure _get_frame(src:PCONTEXT;dst:p_trapframe;xstate:Pointer;is_jit:Boolean); var flags:DWORD; begin if (src=nil) or (dst=nil) then Exit; flags:=src^.ContextFlags and (not CONTEXT_AMD64); if ((flags and CONTEXT_INTEGER)<>0) then begin dst^.tf_rax:=src^.Rax; dst^.tf_rbx:=src^.Rbx; dst^.tf_rcx:=src^.Rcx; dst^.tf_rdx:=src^.Rdx; dst^.tf_rsi:=src^.Rsi; dst^.tf_rdi:=src^.Rdi; dst^.tf_r8 :=src^.R8 ; dst^.tf_r9 :=src^.R9 ; dst^.tf_r10:=src^.R10; dst^.tf_r11:=src^.R11; dst^.tf_r12:=src^.R12; if not is_jit then begin dst^.tf_r13:=src^.R13; dst^.tf_r14:=src^.R14; dst^.tf_r15:=src^.R15; dst^.tf_rbp:=src^.Rbp; end; end; if ((flags and CONTEXT_CONTROL)<>0) then begin if not is_jit then begin dst^.tf_rsp :=src^.Rsp; dst^.tf_rip :=src^.Rip; end; dst^.tf_rflags:=src^.EFlags; end; if ((flags and CONTEXT_XSTATE)<>0) then begin _get_fpcontext(src,xstate); dst^.tf_flags:=dst^.tf_flags or _MC_HASFPXSTATE; end; end; procedure _set_frame(dst:PCONTEXT;src:p_trapframe;xstate:Pointer;is_jit:Boolean); var flags:DWORD; begin if (src=nil) or (dst=nil) then Exit; flags:=_get_ctx_flags(src); flags:=flags and dst^.ContextFlags; //filter dst^.ContextFlags:=flags or CONTEXT_AMD64; //update if ((flags and CONTEXT_INTEGER)<>0) then begin dst^.Rax:=src^.tf_rax; dst^.Rbx:=src^.tf_rbx; dst^.Rcx:=src^.tf_rcx; dst^.Rdx:=src^.tf_rdx; dst^.Rsi:=src^.tf_rsi; dst^.Rdi:=src^.tf_rdi; dst^.R8 :=src^.tf_r8; dst^.R9 :=src^.tf_r9; dst^.R10:=src^.tf_r10; dst^.R11:=src^.tf_r11; if not is_jit then begin dst^.R12:=src^.tf_r12; dst^.R13:=src^.tf_r13; dst^.R14:=src^.tf_r14; dst^.R15:=src^.tf_r15; dst^.Rbp:=src^.tf_rbp; end; end; if ((flags and CONTEXT_CONTROL)<>0) then begin if not is_jit then begin dst^.Rsp :=src^.tf_rsp; dst^.Rip :=src^.tf_rip; end; dst^.EFlags:=src^.tf_rflags; end; if ((flags and CONTEXT_FLOATING_POINT)<>0) or ((flags and CONTEXT_XSTATE)<>0) then begin _set_fpcontext(dst,xstate); end; end; // procedure _get_ucontext(src:PCONTEXT;dst:p_ucontext_t); var flags:DWORD; begin if (src=nil) or (dst=nil) then Exit; flags:=src^.ContextFlags and (not CONTEXT_AMD64); if ((flags and CONTEXT_INTEGER)<>0) then begin dst^.uc_flags:=dst^.uc_flags or _UC_CPU; dst^.uc_mcontext.mc_rax:=src^.Rax; dst^.uc_mcontext.mc_rbx:=src^.Rbx; dst^.uc_mcontext.mc_rcx:=src^.Rcx; dst^.uc_mcontext.mc_rdx:=src^.Rdx; dst^.uc_mcontext.mc_rsi:=src^.Rsi; dst^.uc_mcontext.mc_rdi:=src^.Rdi; dst^.uc_mcontext.mc_r8 :=src^.R8 ; dst^.uc_mcontext.mc_r9 :=src^.R9 ; dst^.uc_mcontext.mc_r10:=src^.R10; dst^.uc_mcontext.mc_r11:=src^.R11; dst^.uc_mcontext.mc_r12:=src^.R12; dst^.uc_mcontext.mc_r13:=src^.R13; dst^.uc_mcontext.mc_r14:=src^.R14; dst^.uc_mcontext.mc_r15:=src^.R15; dst^.uc_mcontext.mc_rbp:=src^.Rbp; end; if ((flags and CONTEXT_CONTROL)<>0) then begin dst^.uc_flags:=dst^.uc_flags or _UC_CPU; dst^.uc_mcontext.mc_rsp :=src^.Rsp; dst^.uc_mcontext.mc_rip :=src^.Rip; dst^.uc_mcontext.mc_rflags:=src^.EFlags; dst^.uc_mcontext.mc_cs :=_ucodesel; dst^.uc_mcontext.mc_ss :=_udatasel; end; if ((flags and CONTEXT_SEGMENTS)<>0) then begin dst^.uc_mcontext.mc_flags:=dst^.uc_mcontext.mc_flags or _MC_HASSEGS; dst^.uc_mcontext.mc_ds:=_udatasel; dst^.uc_mcontext.mc_es:=_udatasel; dst^.uc_mcontext.mc_fs:=_ufssel; dst^.uc_mcontext.mc_gs:=_ugssel; end; if ((flags and CONTEXT_XSTATE)<>0) then begin _get_fpcontext(src,@dst^.uc_mcontext.mc_fpstate); dst^.uc_mcontext.mc_fpformat:=_MC_FPFMT_XMM; dst^.uc_mcontext.mc_ownedfp :=_MC_FPOWNED_FPU; dst^.uc_mcontext.mc_flags:=dst^.uc_mcontext.mc_flags or _MC_HASFPXSTATE; end; dst^.uc_mcontext.mc_len:=SizeOf(mcontext_t); end; procedure _set_ucontext(dst:PCONTEXT;src:p_ucontext_t); var flags:DWORD; begin if (src=nil) or (dst=nil) then Exit; flags:=_get_ctx_flags(src); flags:=flags and dst^.ContextFlags; //filter dst^.ContextFlags:=flags or CONTEXT_AMD64; //update if ((flags and CONTEXT_INTEGER)<>0) then begin dst^.Rax:=src^.uc_mcontext.mc_rax; dst^.Rbx:=src^.uc_mcontext.mc_rbx; dst^.Rcx:=src^.uc_mcontext.mc_rcx; dst^.Rdx:=src^.uc_mcontext.mc_rdx; dst^.Rsi:=src^.uc_mcontext.mc_rsi; dst^.Rdi:=src^.uc_mcontext.mc_rdi; dst^.R8 :=src^.uc_mcontext.mc_r8; dst^.R9 :=src^.uc_mcontext.mc_r9; dst^.R10:=src^.uc_mcontext.mc_r10; dst^.R11:=src^.uc_mcontext.mc_r11; dst^.R12:=src^.uc_mcontext.mc_r12; dst^.R13:=src^.uc_mcontext.mc_r13; dst^.R14:=src^.uc_mcontext.mc_r14; dst^.R15:=src^.uc_mcontext.mc_r15; dst^.Rbp:=src^.uc_mcontext.mc_rbp; end; if ((flags and CONTEXT_CONTROL)<>0) then begin dst^.Rsp :=src^.uc_mcontext.mc_rsp; dst^.Rip :=src^.uc_mcontext.mc_rip; dst^.EFlags:=src^.uc_mcontext.mc_rflags; dst^.SegCs :=KGDT64_R3_CODE or RPL_MASK; dst^.SegSs :=KGDT64_R3_DATA or RPL_MASK; end; if ((flags and CONTEXT_SEGMENTS)<>0) then begin dst^.SegDs:=KGDT64_R3_DATA or RPL_MASK; dst^.SegEs:=KGDT64_R3_DATA or RPL_MASK; dst^.SegFs:=KGDT64_R3_CMTEB or RPL_MASK; dst^.SegGs:=KGDT64_R3_DATA or RPL_MASK; end; if ((flags and CONTEXT_FLOATING_POINT)<>0) or ((flags and CONTEXT_XSTATE)<>0) then begin _set_fpcontext(dst,@src^.uc_mcontext.mc_fpstate); end; end; function cpu_get_iflag(td:p_kthread):PInteger; inline; begin Result:=@td^.td_teb^.iflag; end; function IS_TRAP_FUNC(rip:qword):Boolean; external; function IS_JIT_FUNC (rip:qword):Boolean; external; function IS_SYSTEM_STACK(td:p_kthread;rsp:qword):Boolean; inline; begin Result:=(rsp<=QWORD(td^.td_kstack.stack)) and (rsp>(QWORD(td^.td_kstack.sttop))); end; function IS_SYSCALL(rip:qword):Boolean; var w:Word; begin Result:=False; if (rip<>0) then begin w:=0; NtReadVirtualMemory(NtCurrentProcess,@PWord(Rip)[-1],@w,SizeOf(Word),nil); Result:=(w=$050F); end; end; function get_top_mem_td(td:p_kthread;size,align:qword):Pointer; begin Result:=System.Align(td^.td_kstack.sttop,align); if (SPtr>td^.td_kstack.sttop) and (SPtr<=td^.td_kstack.stack) then begin if ((Result+size)>=SPtr) then begin Result:=thread_get_local_buffer(td,size+align-1); Result:=System.Align(Result,align); end; end; end; procedure _apc_null(dwParam:PTRUINT); stdcall; begin end; function md_get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer; var td_handle:THandle; Context :PCONTEXT; begin Result :=0; td_handle:=td^.td_handle; Context:=get_top_mem_td(td,GetContextSize(CONTEXT_XSTATE),16); Assert(Context<>nil); Context:=InitializeContextExtended(Context,CONTEXT_XSTATE); if (NtGetContextThread(td_handle,Context)<>STATUS_SUCCESS) then begin Exit(ESRCH) end; //xmm,ymm _get_fpcontext(Context,xstate); mcp^.mc_flags :=mcp^.mc_flags or _MC_HASFPXSTATE; mcp^.mc_fpformat:=_MC_FPFMT_XMM; mcp^.mc_ownedfp :=_MC_FPOWNED_FPU; //xmm,ymm end; procedure switch_to_jit(td:p_kthread); external; procedure ipi_sigreturn; var td:p_kthread; Context:PCONTEXT; regs:p_trapframe; R:DWORD; begin td:=curkthread; if (td=nil) then begin Writeln(stderr,'ipi_sigreturn with zero thread'); Exit; end; //teb stack teb_set_kernel(td); //teb stack switch_to_jit(td); regs:=@td^.td_frame; if ((regs^.tf_flags and TF_HASFPXSTATE)<>0) then begin //xmm,ymm Context:=get_top_mem_td(td,GetContextSize(CONTEXT_ALLX),16); Assert(Context<>nil); Context:=InitializeContextExtended(Context,CONTEXT_ALLX); end else begin //simple Context:=get_top_mem_td(td,SizeOf(TCONTEXT),16); Assert(Context<>nil); Context^:=Default(TCONTEXT); Context^.ContextFlags:=CONTEXT_INTEGER or CONTEXT_CONTROL; end; Context^.Rdi:=regs^.tf_rdi; Context^.Rsi:=regs^.tf_rsi; Context^.Rdx:=regs^.tf_rdx; Context^.Rcx:=regs^.tf_rcx; Context^.R8 :=regs^.tf_r8 ; Context^.R9 :=regs^.tf_r9 ; Context^.Rax:=regs^.tf_rax; Context^.Rbx:=regs^.tf_rbx; Context^.Rbp:=regs^.tf_rbp; Context^.R10:=regs^.tf_r10; Context^.R11:=regs^.tf_r11; Context^.R12:=regs^.tf_r12; Context^.R13:=regs^.tf_r13; Context^.R14:=regs^.tf_r14; Context^.R15:=regs^.tf_r15; Context^.Rip :=regs^.tf_rip; Context^.EFlags:=regs^.tf_rflags; Context^.Rsp :=regs^.tf_rsp; Context^.SegGs:=KGDT64_R3_DATA or RPL_MASK; Context^.SegEs:=KGDT64_R3_DATA or RPL_MASK; Context^.SegDs:=KGDT64_R3_DATA or RPL_MASK; Context^.SegCs:=KGDT64_R3_CODE or RPL_MASK; Context^.SegSs:=KGDT64_R3_DATA or RPL_MASK; Context^.SegFs:=KGDT64_R3_CMTEB or RPL_MASK; Context^.MxCsr:=td^.td_fpstate.XMM_SAVE_AREA.MxCsr; //xmm,ymm if ((regs^.tf_flags and TF_HASFPXSTATE)<>0) then begin _set_fpcontext(Context,@td^.td_fpstate); regs^.tf_flags:=regs^.tf_flags and (not TF_HASFPXSTATE); end; //xmm,ymm //teb stack teb_set_user(td); //teb stack //Writeln('ipi_sigreturn'); R:=NtContinue(Context,False); Writeln(stderr,'NtContinue:0x',HexStr(R,8)); end; procedure host_sigipi; external; procedure on_ipi(td :p_kthread; ApcArgument2 :Pointer; ApcArgument3 :Pointer; ContextRecord:PCONTEXT); stdcall; begin if IS_SYSTEM_STACK(td,ContextRecord^.Rsp) or //system? IS_TRAP_FUNC(ContextRecord^.Rip) or //syscall func? IS_JIT_FUNC (ContextRecord^.Rip) then //syscall func? begin Exit; end; Writeln('TODO:on_ipi'); //Assert(false,'on_ipi'); end; function ipi_send_cpu(td:p_kthread):Integer; label resume, tryagain; var td_handle:THandle; iflag :PInteger; Context :PCONTEXT; w:LARGE_INTEGER; sf:sigframe; sfp:p_sigframe; regs:p_trapframe; sp:QWORD; oonstack:Integer; begin Result :=0; //td_handle:=td^.td_handle; //iflag :=cpu_get_iflag(td); Result:=NtQueueApcThreadEx( td^.td_handle, QUEUE_USER_APC_FLAGS_SPECIAL_USER_APC, @on_ipi, td, nil, nil ); Assert(Result=0,'NtQueueApcThreadEx failed'); { PROC_LOCK; tryagain: if (NtSuspendThread(td_handle,nil)<>STATUS_SUCCESS) then begin PROC_UNLOCK; Exit(ESRCH); end; w.QuadPart:=0; if (NtWaitForSingleObject(td_handle,False,@w)<>STATUS_TIMEOUT) then begin Result:=ESRCH; goto resume; end; if ((iflag^ and SIG_ALTERABLE)<>0) then //alterable? begin NtQueueApcThread(td_handle,@_apc_null,nil,nil,0); Result:=0; goto resume; end else if (iflag^<>0) then //locked? begin Result:=0; goto resume; end; { if (td^.td_teb^.jit_rsp<>nil) then //jit call? begin Result:=0; goto resume; end; } Context:=get_top_mem_td(td,GetContextSize(CONTEXT_ALLX),16); Assert(Context<>nil); Context:=InitializeContextExtended(Context,CONTEXT_ALLX); if (NtGetContextThread(td_handle,Context)<>STATUS_SUCCESS) then begin Result:=ESRCH; goto resume; end; if IS_SYSTEM_STACK(td,Context^.Rsp) or //system? IS_TRAP_FUNC(Context^.Rip) or //syscall func? IS_JIT_FUNC (Context^.Rip) then //syscall func? begin Result:=0; goto resume; end; if IS_SYSCALL(Context^.Rip) then //system call in code without blocking begin NtResumeThread(td_handle,nil); w.QuadPart:=-10000; NtDelayExecution(False,@w); //100ms goto tryagain; end; regs:=@td^.td_frame; oonstack:=sigonstack(Context^.Rsp); // Save user context. sf:=Default(sigframe); sf.sf_uc.uc_sigmask:=td^.td_sigmask; sf.sf_uc.uc_stack :=td^.td_sigstk; if ((td^.td_pflags and TDP_ALTSTACK)<>0) then begin if (oonstack<>0) then begin sf.sf_uc.uc_stack.ss_flags:=SS_ONSTACK; end else begin sf.sf_uc.uc_stack.ss_flags:=0; end; end else begin sf.sf_uc.uc_stack.ss_flags:=SS_DISABLE; end; //copy frame regs^.tf_rdi:=Context^.Rdi; regs^.tf_rsi:=Context^.Rsi; regs^.tf_rdx:=Context^.Rdx; regs^.tf_rcx:=Context^.Rcx; regs^.tf_r8 :=Context^.R8 ; regs^.tf_r9 :=Context^.R9 ; regs^.tf_rax:=Context^.Rax; regs^.tf_rbx:=Context^.Rbx; regs^.tf_rbp:=Context^.Rbp; regs^.tf_r10:=Context^.R10; regs^.tf_r11:=Context^.R11; regs^.tf_r12:=Context^.R12; regs^.tf_r13:=Context^.R13; regs^.tf_r14:=Context^.R14; regs^.tf_r15:=Context^.R15; regs^.tf_rip :=Context^.Rip; regs^.tf_rflags:=Context^.EFlags; regs^.tf_rsp :=Context^.Rsp; regs^.tf_cs:=_ucodesel; regs^.tf_ds:=_udatasel; regs^.tf_ss:=_udatasel; regs^.tf_es:=_udatasel; regs^.tf_fs:=_ufssel; regs^.tf_gs:=_ugssel; regs^.tf_flags:=TF_HASSEGS; //copy frame sf.sf_uc.uc_mcontext.mc_onstack:=oonstack; Move(regs^.tf_rdi,sf.sf_uc.uc_mcontext.mc_rdi,tf_copy_1); Move(regs^.tf_err,sf.sf_uc.uc_mcontext.mc_err,tf_copy_2); sf.sf_uc.uc_mcontext.mc_len:=sizeof(mcontext_t); sf.sf_uc.uc_mcontext.mc_fsbase:=QWORD(td^.pcb_fsbase); sf.sf_uc.uc_mcontext.mc_gsbase:=QWORD(td^.pcb_gsbase); sf.sf_uc.uc_mcontext.mc_flags:=_MC_HASSEGS or _MC_HASBASES or _MC_HASFPXSTATE; //xmm,ymm _get_fpcontext(Context,@sf.sf_uc.uc_mcontext.mc_fpstate); sf.sf_uc.uc_mcontext.mc_fpformat:=_MC_FPFMT_XMM; sf.sf_uc.uc_mcontext.mc_ownedfp :=_MC_FPOWNED_FPU; //xmm,ymm sp:=QWORD(td^.td_kstack.stack); sp:=sp-sizeof(sigframe); sfp:=p_sigframe(sp and (not $1F)); if (copyout(@sf,sfp,sizeof(sigframe))<>0) then begin Result:=EFAULT; goto resume; end; Context^.Rsp:=QWORD(sfp); Context^.Rip:=QWORD(@host_sigipi); Context^.EFlags:=Context^.EFlags and (not (PSL_T or PSL_D)); set_pcb_flags(td,PCB_FULL_IRET); if (NtSetContextThread(td_handle,Context)<>STATUS_SUCCESS) then begin Result:=ESRCH; goto resume; end; //teb stack teb_set_user(td); //teb stack resume: NtResumeThread(td_handle,nil); PROC_UNLOCK; } end; end.