2 * x86-64 signal handling routines
4 * Copyright 1999, 2005 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #pragma makedep arm64ec_x64
32 #define WIN32_NO_STATUS
36 #include "wine/exception.h"
37 #include "wine/list.h"
38 #include "ntdll_misc.h"
39 #include "wine/debug.h"
40 #include "ntsyscalls.h"
43 /**************************************************************************
46 * Supposed to touch all the stack pages, but we shouldn't need that.
48 __ASM_GLOBAL_FUNC( __chkstk
, "ret" );
51 #ifndef __arm64ec_x64__
53 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
54 WINE_DECLARE_DEBUG_CHANNEL(relay
);
57 /*******************************************************************
60 #define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id, name )
65 /***********************************************************************
68 static NTSTATUS
virtual_unwind( ULONG type
, DISPATCHER_CONTEXT
*dispatch
, CONTEXT
*context
)
70 LDR_DATA_TABLE_ENTRY
*module
;
73 dispatch
->ImageBase
= 0;
74 dispatch
->ScopeIndex
= 0;
75 dispatch
->ControlPc
= context
->Rip
;
76 dispatch
->FunctionEntry
= RtlLookupFunctionEntry( context
->Rip
, &dispatch
->ImageBase
,
77 dispatch
->HistoryTable
);
79 /* look for host system exception information */
80 if (!dispatch
->FunctionEntry
&&
81 (LdrFindEntryForAddress( (void *)context
->Rip
, &module
) || (module
->Flags
& LDR_WINE_INTERNAL
)))
83 struct unwind_builtin_dll_params params
= { type
, dispatch
, context
};
85 status
= WINE_UNIX_CALL( unix_unwind_builtin_dll
, ¶ms
);
86 if (!status
&& dispatch
->LanguageHandler
&& !module
)
88 FIXME( "calling personality routine in system library not supported yet\n" );
89 dispatch
->LanguageHandler
= NULL
;
91 if (status
!= STATUS_UNSUCCESSFUL
) return status
;
94 return RtlVirtualUnwind2( type
, dispatch
->ImageBase
, context
->Rip
, dispatch
->FunctionEntry
,
95 context
, NULL
, &dispatch
->HandlerData
, &dispatch
->EstablisherFrame
,
96 NULL
, NULL
, NULL
, &dispatch
->LanguageHandler
, 0 );
100 /***********************************************************************
101 * RtlCaptureContext (NTDLL.@)
103 __ASM_GLOBAL_FUNC( RtlCaptureContext
,
105 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
106 "movl $0x10000f,0x30(%rcx)\n\t" /* context->ContextFlags */
107 "stmxcsr 0x34(%rcx)\n\t" /* context->MxCsr */
108 "movw %cs,0x38(%rcx)\n\t" /* context->SegCs */
109 "movw %ds,0x3a(%rcx)\n\t" /* context->SegDs */
110 "movw %es,0x3c(%rcx)\n\t" /* context->SegEs */
111 "movw %fs,0x3e(%rcx)\n\t" /* context->SegFs */
112 "movw %gs,0x40(%rcx)\n\t" /* context->SegGs */
113 "movw %ss,0x42(%rcx)\n\t" /* context->SegSs */
114 "popq 0x44(%rcx)\n\t" /* context->Eflags */
115 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
116 "movq %rax,0x78(%rcx)\n\t" /* context->Rax */
117 "movq %rcx,0x80(%rcx)\n\t" /* context->Rcx */
118 "movq %rdx,0x88(%rcx)\n\t" /* context->Rdx */
119 "movq %rbx,0x90(%rcx)\n\t" /* context->Rbx */
120 "leaq 8(%rsp),%rax\n\t"
121 "movq %rax,0x98(%rcx)\n\t" /* context->Rsp */
122 "movq %rbp,0xa0(%rcx)\n\t" /* context->Rbp */
123 "movq %rsi,0xa8(%rcx)\n\t" /* context->Rsi */
124 "movq %rdi,0xb0(%rcx)\n\t" /* context->Rdi */
125 "movq %r8,0xb8(%rcx)\n\t" /* context->R8 */
126 "movq %r9,0xc0(%rcx)\n\t" /* context->R9 */
127 "movq %r10,0xc8(%rcx)\n\t" /* context->R10 */
128 "movq %r11,0xd0(%rcx)\n\t" /* context->R11 */
129 "movq %r12,0xd8(%rcx)\n\t" /* context->R12 */
130 "movq %r13,0xe0(%rcx)\n\t" /* context->R13 */
131 "movq %r14,0xe8(%rcx)\n\t" /* context->R14 */
132 "movq %r15,0xf0(%rcx)\n\t" /* context->R15 */
133 "movq (%rsp),%rax\n\t"
134 "movq %rax,0xf8(%rcx)\n\t" /* context->Rip */
135 "fxsave 0x100(%rcx)\n\t" /* context->FltSave */
139 /***********************************************************************
142 #ifdef __WINE_PE_BUILD
143 DWORD WINAPI
call_seh_handler( EXCEPTION_RECORD
*rec
, ULONG_PTR frame
,
144 CONTEXT
*context
, void *dispatch
, PEXCEPTION_ROUTINE handler
);
145 __ASM_GLOBAL_FUNC( call_seh_handler
,
146 "subq $0x28, %rsp\n\t"
147 ".seh_stackalloc 0x28\n\t"
148 ".seh_endprologue\n\t"
149 ".seh_handler nested_exception_handler, @except\n\t"
150 "callq *0x50(%rsp)\n\t" /* handler */
151 "nop\n\t" /* avoid epilogue so handler is called */
152 "addq $0x28, %rsp\n\t"
155 static DWORD
call_seh_handler( EXCEPTION_RECORD
*rec
, ULONG_PTR frame
,
156 CONTEXT
*context
, void *dispatch
, PEXCEPTION_ROUTINE handler
)
158 EXCEPTION_REGISTRATION_RECORD wrapper_frame
;
161 wrapper_frame
.Handler
= (PEXCEPTION_HANDLER
)nested_exception_handler
;
162 __wine_push_frame( &wrapper_frame
);
163 res
= handler( rec
, (void *)frame
, context
, dispatch
);
164 __wine_pop_frame( &wrapper_frame
);
170 /**********************************************************************
173 * Call the SEH handlers chain.
175 NTSTATUS
call_seh_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*orig_context
)
177 EXCEPTION_REGISTRATION_RECORD
*teb_frame
= NtCurrentTeb()->Tib
.ExceptionList
;
178 UNWIND_HISTORY_TABLE table
;
179 DISPATCHER_CONTEXT dispatch
;
185 context
= *orig_context
;
186 context
.ContextFlags
&= ~0x40; /* Clear xstate flag. */
188 dispatch
.TargetIp
= 0;
189 dispatch
.ContextRecord
= &context
;
190 dispatch
.HistoryTable
= &table
;
193 status
= virtual_unwind( UNW_FLAG_EHANDLER
, &dispatch
, &context
);
194 if (status
!= STATUS_SUCCESS
) return status
;
197 if (!dispatch
.EstablisherFrame
) break;
199 if (!is_valid_frame( dispatch
.EstablisherFrame
))
201 ERR( "invalid frame %p (%p-%p)\n", (void *)dispatch
.EstablisherFrame
,
202 NtCurrentTeb()->Tib
.StackLimit
, NtCurrentTeb()->Tib
.StackBase
);
203 rec
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
207 if (dispatch
.LanguageHandler
)
209 TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n",
210 dispatch
.LanguageHandler
, rec
, dispatch
.EstablisherFrame
, orig_context
, &dispatch
);
211 res
= call_seh_handler( rec
, dispatch
.EstablisherFrame
, orig_context
,
212 &dispatch
, dispatch
.LanguageHandler
);
213 rec
->ExceptionFlags
&= EXCEPTION_NONCONTINUABLE
;
214 TRACE( "handler at %p returned %lu\n", dispatch
.LanguageHandler
, res
);
218 case ExceptionContinueExecution
:
219 if (rec
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
) return STATUS_NONCONTINUABLE_EXCEPTION
;
220 return STATUS_SUCCESS
;
221 case ExceptionContinueSearch
:
223 case ExceptionNestedException
:
224 rec
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
225 TRACE( "nested exception\n" );
227 case ExceptionCollidedUnwind
:
228 RtlVirtualUnwind( UNW_FLAG_NHANDLER
, dispatch
.ImageBase
, dispatch
.ControlPc
,
229 dispatch
.FunctionEntry
, &context
, NULL
, &frame
, NULL
);
232 return STATUS_INVALID_DISPOSITION
;
235 /* hack: call wine handlers registered in the tib list */
236 else while (is_valid_frame( (ULONG_PTR
)teb_frame
) && (ULONG64
)teb_frame
< context
.Rsp
)
238 TRACE( "calling TEB handler %p (rec=%p frame=%p context=%p dispatch=%p) sp=%I64x\n",
239 teb_frame
->Handler
, rec
, teb_frame
, orig_context
, &dispatch
, context
.Rsp
);
240 res
= call_seh_handler( rec
, (ULONG_PTR
)teb_frame
, orig_context
,
241 &dispatch
, (PEXCEPTION_ROUTINE
)teb_frame
->Handler
);
242 TRACE( "TEB handler at %p returned %lu\n", teb_frame
->Handler
, res
);
246 case ExceptionContinueExecution
:
247 if (rec
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
) return STATUS_NONCONTINUABLE_EXCEPTION
;
248 return STATUS_SUCCESS
;
249 case ExceptionContinueSearch
:
251 case ExceptionNestedException
:
252 rec
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
253 TRACE( "nested exception\n" );
255 case ExceptionCollidedUnwind
:
256 RtlVirtualUnwind( UNW_FLAG_NHANDLER
, dispatch
.ImageBase
, dispatch
.ControlPc
,
257 dispatch
.FunctionEntry
, &context
, NULL
, &frame
, NULL
);
258 teb_frame
= teb_frame
->Prev
;
261 return STATUS_INVALID_DISPOSITION
;
263 teb_frame
= teb_frame
->Prev
;
266 if (context
.Rsp
== (ULONG64
)NtCurrentTeb()->Tib
.StackBase
) break;
268 return STATUS_UNHANDLED_EXCEPTION
;
272 /*******************************************************************
273 * KiUserExceptionDispatcher (NTDLL.@)
275 __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher
,
276 __ASM_SEH(".seh_pushframe\n\t")
277 __ASM_SEH(".seh_stackalloc 0x590\n\t")
278 __ASM_SEH(".seh_savereg %rbx,0x90\n\t")
279 __ASM_SEH(".seh_savereg %rbp,0xa0\n\t")
280 __ASM_SEH(".seh_savereg %rsi,0xa8\n\t")
281 __ASM_SEH(".seh_savereg %rdi,0xb0\n\t")
282 __ASM_SEH(".seh_savereg %r12,0xd8\n\t")
283 __ASM_SEH(".seh_savereg %r13,0xe0\n\t")
284 __ASM_SEH(".seh_savereg %r14,0xe8\n\t")
285 __ASM_SEH(".seh_savereg %r15,0xf0\n\t")
286 __ASM_SEH(".seh_endprologue\n\t")
287 __ASM_CFI(".cfi_signal_frame\n\t")
288 __ASM_CFI(".cfi_def_cfa_offset 0\n\t")
289 __ASM_CFI(".cfi_offset %rbx,0x90\n\t")
290 __ASM_CFI(".cfi_offset %rbp,0xa0\n\t")
291 __ASM_CFI(".cfi_offset %rsi,0xa8\n\t")
292 __ASM_CFI(".cfi_offset %rdi,0xb0\n\t")
293 __ASM_CFI(".cfi_offset %r12,0xd8\n\t")
294 __ASM_CFI(".cfi_offset %r13,0xe0\n\t")
295 __ASM_CFI(".cfi_offset %r14,0xe8\n\t")
296 __ASM_CFI(".cfi_offset %r15,0xf0\n\t")
297 __ASM_CFI(".cfi_offset %rip,0x590\n\t")
298 __ASM_CFI(".cfi_offset %rsp,0x5a8\n\t")
300 /* some anticheats need this exact instruction here */
301 "mov " __ASM_NAME("pWow64PrepareForException") "(%rip),%rax\n\t"
304 "mov %rsp,%rdx\n\t" /* context */
305 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
307 "1:\tmov %rsp,%rdx\n\t" /* context */
308 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
309 "call " __ASM_NAME("dispatch_exception") "\n\t"
313 /*******************************************************************
314 * KiUserApcDispatcher (NTDLL.@)
316 __ASM_GLOBAL_FUNC( KiUserApcDispatcher
,
317 __ASM_SEH(".seh_pushframe\n\t")
318 __ASM_SEH(".seh_stackalloc 0x4d0\n\t") /* sizeof(CONTEXT) */
319 __ASM_SEH(".seh_savereg %rbx,0x90\n\t")
320 __ASM_SEH(".seh_savereg %rbp,0xa0\n\t")
321 __ASM_SEH(".seh_savereg %rsi,0xa8\n\t")
322 __ASM_SEH(".seh_savereg %rdi,0xb0\n\t")
323 __ASM_SEH(".seh_savereg %r12,0xd8\n\t")
324 __ASM_SEH(".seh_savereg %r13,0xe0\n\t")
325 __ASM_SEH(".seh_savereg %r14,0xe8\n\t")
326 __ASM_SEH(".seh_savereg %r15,0xf0\n\t")
327 __ASM_SEH(".seh_endprologue\n\t")
328 __ASM_CFI(".cfi_signal_frame\n\t")
329 __ASM_CFI(".cfi_def_cfa_offset 0\n\t")
330 __ASM_CFI(".cfi_offset %rbx,0x90\n\t")
331 __ASM_CFI(".cfi_offset %rbp,0xa0\n\t")
332 __ASM_CFI(".cfi_offset %rsi,0xa8\n\t")
333 __ASM_CFI(".cfi_offset %rdi,0xb0\n\t")
334 __ASM_CFI(".cfi_offset %r12,0xd8\n\t")
335 __ASM_CFI(".cfi_offset %r13,0xe0\n\t")
336 __ASM_CFI(".cfi_offset %r14,0xe8\n\t")
337 __ASM_CFI(".cfi_offset %r15,0xf0\n\t")
338 __ASM_CFI(".cfi_offset %rip,0x4d0\n\t")
339 __ASM_CFI(".cfi_offset %rsp,0x4e8\n\t")
340 "movq 0x00(%rsp),%rcx\n\t" /* context->P1Home = arg1 */
341 "movq 0x08(%rsp),%rdx\n\t" /* context->P2Home = arg2 */
342 "movq 0x10(%rsp),%r8\n\t" /* context->P3Home = arg3 */
343 "movq 0x18(%rsp),%rax\n\t" /* context->P4Home = func */
344 "movq %rsp,%r9\n\t" /* context */
346 "movq %rsp,%rcx\n\t" /* context */
347 "movl $1,%edx\n\t" /* alertable */
348 "call " __ASM_NAME("NtContinue") "\n\t"
352 /*******************************************************************
353 * KiUserCallbackDispatcher (NTDLL.@)
355 __ASM_GLOBAL_FUNC( KiUserCallbackDispatcher
,
356 __ASM_SEH(".seh_pushframe\n\t")
357 __ASM_SEH(".seh_stackalloc 0x30\n\t")
358 __ASM_SEH(".seh_endprologue\n\t")
359 __ASM_CFI(".cfi_signal_frame\n\t")
360 __ASM_CFI(".cfi_def_cfa_offset 0\n\t")
361 __ASM_CFI(".cfi_offset %rip,0x30\n\t")
362 __ASM_CFI(".cfi_offset %rsp,0x48\n\t")
363 "movq 0x20(%rsp),%rcx\n\t" /* args */
364 "movl 0x28(%rsp),%edx\n\t" /* len */
365 "movl 0x2c(%rsp),%r8d\n\t" /* id */
366 #ifdef __WINE_PE_BUILD
367 "movq %gs:0x30,%rax\n\t" /* NtCurrentTeb() */
368 "movq 0x60(%rax),%rax\n\t" /* peb */
369 "movq 0x58(%rax),%rax\n\t" /* peb->KernelCallbackTable */
370 "call *(%rax,%r8,8)\n\t" /* KernelCallbackTable[id] */
371 ".seh_handler " __ASM_NAME("user_callback_handler") ", @except\n\t"
372 ".globl " __ASM_NAME("KiUserCallbackDispatcherReturn") "\n"
373 __ASM_NAME("KiUserCallbackDispatcherReturn") ":\n\t"
375 "call " __ASM_NAME("dispatch_user_callback") "\n\t"
377 "xorq %rcx,%rcx\n\t" /* ret_ptr */
378 "xorl %edx,%edx\n\t" /* ret_len */
379 "movl %eax,%r8d\n\t" /* status */
380 "call " __ASM_NAME("NtCallbackReturn") "\n\t"
381 "movl %eax,%ecx\n\t" /* status */
382 "call " __ASM_NAME("RtlRaiseStatus") "\n\t"
386 /**************************************************************************
387 * RtlIsEcCode (NTDLL.@)
389 BOOLEAN WINAPI
RtlIsEcCode( ULONG_PTR ptr
)
395 struct unwind_exception_frame
397 EXCEPTION_REGISTRATION_RECORD frame
;
398 char dummy
[0x10]; /* Layout 'dispatch' accessed from unwind_exception_handler() so it is above register
399 * save space when .seh handler is used. */
400 DISPATCHER_CONTEXT
*dispatch
;
402 C_ASSERT( sizeof(struct unwind_exception_frame
) == 0x28 );
403 C_ASSERT( offsetof(struct unwind_exception_frame
, dispatch
) == 0x20 );
406 /**********************************************************************
407 * unwind_exception_handler
409 * Handler for exceptions happening while calling an unwind handler.
411 DWORD __cdecl
unwind_exception_handler( EXCEPTION_RECORD
*rec
, EXCEPTION_REGISTRATION_RECORD
*frame
,
412 CONTEXT
*context
, EXCEPTION_REGISTRATION_RECORD
**dispatcher
)
414 struct unwind_exception_frame
*unwind_frame
= (struct unwind_exception_frame
*)frame
;
415 DISPATCHER_CONTEXT
*dispatch
= (DISPATCHER_CONTEXT
*)dispatcher
;
417 /* copy the original dispatcher into the current one, except for the TargetIp */
418 dispatch
->ControlPc
= unwind_frame
->dispatch
->ControlPc
;
419 dispatch
->ImageBase
= unwind_frame
->dispatch
->ImageBase
;
420 dispatch
->FunctionEntry
= unwind_frame
->dispatch
->FunctionEntry
;
421 dispatch
->EstablisherFrame
= unwind_frame
->dispatch
->EstablisherFrame
;
422 dispatch
->LanguageHandler
= unwind_frame
->dispatch
->LanguageHandler
;
423 dispatch
->HandlerData
= unwind_frame
->dispatch
->HandlerData
;
424 dispatch
->HistoryTable
= unwind_frame
->dispatch
->HistoryTable
;
425 dispatch
->ScopeIndex
= unwind_frame
->dispatch
->ScopeIndex
;
426 *dispatch
->ContextRecord
= *unwind_frame
->dispatch
->ContextRecord
;
427 dispatch
->ContextRecord
->ContextFlags
&= ~0x40;
428 TRACE( "detected collided unwind\n" );
429 return ExceptionCollidedUnwind
;
433 /**********************************************************************
434 * call_unwind_handler
436 #ifdef __WINE_PE_BUILD
437 DWORD WINAPI
call_unwind_handler( EXCEPTION_RECORD
*rec
, ULONG_PTR frame
,
438 CONTEXT
*context
, void *dispatch
, PEXCEPTION_ROUTINE handler
);
439 __ASM_GLOBAL_FUNC( call_unwind_handler
,
440 "subq $0x28,%rsp\n\t"
441 ".seh_stackalloc 0x28\n\t"
442 ".seh_endprologue\n\t"
443 ".seh_handler unwind_exception_handler, @except, @unwind\n\t"
444 "movq %r9,0x20(%rsp)\n\t" /* unwind_exception_frame->dispatch */
445 "callq *0x50(%rsp)\n\t" /* handler */
446 "nop\n\t" /* avoid epilogue so handler is called */
447 "addq $0x28, %rsp\n\t"
450 static DWORD
call_unwind_handler( EXCEPTION_RECORD
*rec
, ULONG_PTR frame
,
451 CONTEXT
*context
, void *dispatch
, PEXCEPTION_ROUTINE handler
)
453 struct unwind_exception_frame wrapper_frame
;
456 wrapper_frame
.frame
.Handler
= unwind_exception_handler
;
457 wrapper_frame
.dispatch
= dispatch
;
458 __wine_push_frame( &wrapper_frame
.frame
);
459 res
= handler( rec
, (void *)frame
, context
, dispatch
);
460 __wine_pop_frame( &wrapper_frame
.frame
);
466 /**********************************************************************
467 * call_consolidate_callback
469 * Wrapper function to call a consolidate callback from a fake frame.
470 * If the callback executes RtlUnwindEx (like for example done in C++ handlers),
471 * we have to skip all frames which were already processed. To do that we
472 * trick the unwinding functions into thinking the call came from the specified
473 * context. All CFI instructions are either DW_CFA_def_cfa_expression or
474 * DW_CFA_expression, and the expressions have the following format:
476 * DW_OP_breg6; sleb128 0x10 | Load %rbp + 0x10
477 * DW_OP_deref | Get *(%rbp + 0x10) == context
478 * DW_OP_plus_uconst; uleb128 <OFFSET> | Add offset to get struct member
479 * [DW_OP_deref] | Dereference, only for CFA
481 extern void * WINAPI
call_consolidate_callback( CONTEXT
*context
,
482 void *(CALLBACK
*callback
)(EXCEPTION_RECORD
*),
483 EXCEPTION_RECORD
*rec
);
484 __ASM_GLOBAL_FUNC( call_consolidate_callback
,
486 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
487 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
489 __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
491 /* Setup SEH machine frame. */
492 "subq $0x28,%rsp\n\t"
493 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
494 "movq 0xf8(%rcx),%rax\n\t" /* Context->Rip */
495 "movq %rax,(%rsp)\n\t"
496 "movq 0x98(%rcx),%rax\n\t" /* context->Rsp */
497 "movq %rax,0x18(%rsp)\n\t"
498 __ASM_SEH(".seh_pushframe\n\t")
499 __ASM_SEH(".seh_endprologue\n\t")
501 "subq $0x108,%rsp\n\t" /* 10*16 (float regs) + 8*8 (int regs) + 32 (shadow store) + 8 (align). */
502 __ASM_SEH(".seh_stackalloc 0x108\n\t")
503 __ASM_CFI(".cfi_adjust_cfa_offset 0x108\n\t")
505 /* Setup CFI unwind to context. */
506 "movq %rcx,0x10(%rbp)\n\t"
507 __ASM_CFI(".cfi_remember_state\n\t")
508 __ASM_CFI(".cfi_escape 0x0f,0x07,0x76,0x10,0x06,0x23,0x98,0x01,0x06\n\t") /* CFA */
509 __ASM_CFI(".cfi_escape 0x10,0x03,0x06,0x76,0x10,0x06,0x23,0x90,0x01\n\t") /* %rbx */
510 __ASM_CFI(".cfi_escape 0x10,0x04,0x06,0x76,0x10,0x06,0x23,0xa8,0x01\n\t") /* %rsi */
511 __ASM_CFI(".cfi_escape 0x10,0x05,0x06,0x76,0x10,0x06,0x23,0xb0,0x01\n\t") /* %rdi */
512 __ASM_CFI(".cfi_escape 0x10,0x06,0x06,0x76,0x10,0x06,0x23,0xa0,0x01\n\t") /* %rbp */
513 __ASM_CFI(".cfi_escape 0x10,0x0c,0x06,0x76,0x10,0x06,0x23,0xd8,0x01\n\t") /* %r12 */
514 __ASM_CFI(".cfi_escape 0x10,0x0d,0x06,0x76,0x10,0x06,0x23,0xe0,0x01\n\t") /* %r13 */
515 __ASM_CFI(".cfi_escape 0x10,0x0e,0x06,0x76,0x10,0x06,0x23,0xe8,0x01\n\t") /* %r14 */
516 __ASM_CFI(".cfi_escape 0x10,0x0f,0x06,0x76,0x10,0x06,0x23,0xf0,0x01\n\t") /* %r15 */
517 __ASM_CFI(".cfi_escape 0x10,0x10,0x06,0x76,0x10,0x06,0x23,0xf8,0x01\n\t") /* %rip */
518 __ASM_CFI(".cfi_escape 0x10,0x17,0x06,0x76,0x10,0x06,0x23,0x80,0x04\n\t") /* %xmm6 */
519 __ASM_CFI(".cfi_escape 0x10,0x18,0x06,0x76,0x10,0x06,0x23,0x90,0x04\n\t") /* %xmm7 */
520 __ASM_CFI(".cfi_escape 0x10,0x19,0x06,0x76,0x10,0x06,0x23,0xa0,0x04\n\t") /* %xmm8 */
521 __ASM_CFI(".cfi_escape 0x10,0x1a,0x06,0x76,0x10,0x06,0x23,0xb0,0x04\n\t") /* %xmm9 */
522 __ASM_CFI(".cfi_escape 0x10,0x1b,0x06,0x76,0x10,0x06,0x23,0xc0,0x04\n\t") /* %xmm10 */
523 __ASM_CFI(".cfi_escape 0x10,0x1c,0x06,0x76,0x10,0x06,0x23,0xd0,0x04\n\t") /* %xmm11 */
524 __ASM_CFI(".cfi_escape 0x10,0x1d,0x06,0x76,0x10,0x06,0x23,0xe0,0x04\n\t") /* %xmm12 */
525 __ASM_CFI(".cfi_escape 0x10,0x1e,0x06,0x76,0x10,0x06,0x23,0xf0,0x04\n\t") /* %xmm13 */
526 __ASM_CFI(".cfi_escape 0x10,0x1f,0x06,0x76,0x10,0x06,0x23,0x80,0x05\n\t") /* %xmm14 */
527 __ASM_CFI(".cfi_escape 0x10,0x20,0x06,0x76,0x10,0x06,0x23,0x90,0x05\n\t") /* %xmm15 */
529 /* Setup SEH unwind registers restore. */
530 "movq 0xa0(%rcx),%rax\n\t" /* context->Rbp */
531 "movq %rax,0x100(%rsp)\n\t"
532 __ASM_SEH(".seh_savereg %rbp, 0x100\n\t")
533 "movq 0x90(%rcx),%rax\n\t" /* context->Rbx */
534 "movq %rax,0x20(%rsp)\n\t"
535 __ASM_SEH(".seh_savereg %rbx, 0x20\n\t")
536 "movq 0xa8(%rcx),%rax\n\t" /* context->Rsi */
537 "movq %rax,0x28(%rsp)\n\t"
538 __ASM_SEH(".seh_savereg %rsi, 0x28\n\t")
539 "movq 0xb0(%rcx),%rax\n\t" /* context->Rdi */
540 "movq %rax,0x30(%rsp)\n\t"
541 __ASM_SEH(".seh_savereg %rdi, 0x30\n\t")
543 "movq 0xd8(%rcx),%rax\n\t" /* context->R12 */
544 "movq %rax,0x38(%rsp)\n\t"
545 __ASM_SEH(".seh_savereg %r12, 0x38\n\t")
546 "movq 0xe0(%rcx),%rax\n\t" /* context->R13 */
547 "movq %rax,0x40(%rsp)\n\t"
548 __ASM_SEH(".seh_savereg %r13, 0x40\n\t")
549 "movq 0xe8(%rcx),%rax\n\t" /* context->R14 */
550 "movq %rax,0x48(%rsp)\n\t"
551 __ASM_SEH(".seh_savereg %r14, 0x48\n\t")
552 "movq 0xf0(%rcx),%rax\n\t" /* context->R15 */
553 "movq %rax,0x50(%rsp)\n\t"
554 __ASM_SEH(".seh_savereg %r15, 0x50\n\t")
557 "leaq 0x200(%rcx),%rsi\n\t"
558 "leaq 0x70(%rsp),%rdi\n\t"
559 "movq $0x14,%rcx\n\t"
564 __ASM_SEH(".seh_savexmm %xmm6, 0x60\n\t")
565 __ASM_SEH(".seh_savexmm %xmm7, 0x70\n\t")
566 __ASM_SEH(".seh_savexmm %xmm8, 0x80\n\t")
567 __ASM_SEH(".seh_savexmm %xmm9, 0x90\n\t")
568 __ASM_SEH(".seh_savexmm %xmm10, 0xa0\n\t")
569 __ASM_SEH(".seh_savexmm %xmm11, 0xb0\n\t")
570 __ASM_SEH(".seh_savexmm %xmm12, 0xc0\n\t")
571 __ASM_SEH(".seh_savexmm %xmm13, 0xd0\n\t")
572 __ASM_SEH(".seh_savexmm %xmm14, 0xe0\n\t")
573 __ASM_SEH(".seh_savexmm %xmm15, 0xf0\n\t")
575 /* call the callback. */
578 __ASM_CFI(".cfi_restore_state\n\t")
579 "nop\n\t" /* Otherwise RtlVirtualUnwind() will think we are inside epilogue and
580 * interpret / execute the rest of opcodes here instead of unwind through
582 "leaq 0(%rbp),%rsp\n\t"
583 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
585 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
586 __ASM_CFI(".cfi_same_value %rbp\n\t")
589 /*******************************************************************
590 * RtlRestoreContext (NTDLL.@)
592 void CDECL
RtlRestoreContext( CONTEXT
*context
, EXCEPTION_RECORD
*rec
)
594 EXCEPTION_REGISTRATION_RECORD
*teb_frame
= NtCurrentTeb()->Tib
.ExceptionList
;
596 if (rec
&& rec
->ExceptionCode
== STATUS_LONGJUMP
&& rec
->NumberParameters
>= 1)
598 struct _JUMP_BUFFER
*jmp
= (struct _JUMP_BUFFER
*)rec
->ExceptionInformation
[0];
599 context
->Rbx
= jmp
->Rbx
;
600 context
->Rsp
= jmp
->Rsp
;
601 context
->Rbp
= jmp
->Rbp
;
602 context
->Rsi
= jmp
->Rsi
;
603 context
->Rdi
= jmp
->Rdi
;
604 context
->R12
= jmp
->R12
;
605 context
->R13
= jmp
->R13
;
606 context
->R14
= jmp
->R14
;
607 context
->R15
= jmp
->R15
;
608 context
->Rip
= jmp
->Rip
;
609 context
->MxCsr
= jmp
->MxCsr
;
610 context
->FltSave
.MxCsr
= jmp
->MxCsr
;
611 context
->FltSave
.ControlWord
= jmp
->FpCsr
;
612 memcpy( &context
->Xmm6
, &jmp
->Xmm6
, 10 * sizeof(M128A
) );
614 else if (rec
&& rec
->ExceptionCode
== STATUS_UNWIND_CONSOLIDATE
&& rec
->NumberParameters
>= 1)
616 PVOID (CALLBACK
*consolidate
)(EXCEPTION_RECORD
*) = (void *)rec
->ExceptionInformation
[0];
617 TRACE( "calling consolidate callback %p (rec=%p)\n", consolidate
, rec
);
618 context
->Rip
= (ULONG64
)call_consolidate_callback( context
, consolidate
, rec
);
621 /* hack: remove no longer accessible TEB frames */
622 while (is_valid_frame( (ULONG_PTR
)teb_frame
) && (ULONG64
)teb_frame
< context
->Rsp
)
624 TRACE( "removing TEB frame: %p\n", teb_frame
);
625 teb_frame
= __wine_pop_frame( teb_frame
);
628 TRACE( "returning to %p stack %p\n", (void *)context
->Rip
, (void *)context
->Rsp
);
629 NtContinue( context
, FALSE
);
633 /*******************************************************************
634 * RtlUnwindEx (NTDLL.@)
636 void WINAPI
RtlUnwindEx( PVOID end_frame
, PVOID target_ip
, EXCEPTION_RECORD
*rec
,
637 PVOID retval
, CONTEXT
*context
, UNWIND_HISTORY_TABLE
*table
)
639 EXCEPTION_REGISTRATION_RECORD
*teb_frame
= NtCurrentTeb()->Tib
.ExceptionList
;
640 EXCEPTION_RECORD record
;
641 DISPATCHER_CONTEXT dispatch
;
647 RtlCaptureContext( context
);
648 new_context
= *context
;
650 /* build an exception record, if we do not have one */
653 record
.ExceptionCode
= STATUS_UNWIND
;
654 record
.ExceptionFlags
= 0;
655 record
.ExceptionRecord
= NULL
;
656 record
.ExceptionAddress
= (void *)context
->Rip
;
657 record
.NumberParameters
= 0;
661 rec
->ExceptionFlags
|= EXCEPTION_UNWINDING
| (end_frame
? 0 : EXCEPTION_EXIT_UNWIND
);
663 TRACE( "code=%lx flags=%lx end_frame=%p target_ip=%p\n",
664 rec
->ExceptionCode
, rec
->ExceptionFlags
, end_frame
, target_ip
);
665 for (i
= 0; i
< min( EXCEPTION_MAXIMUM_PARAMETERS
, rec
->NumberParameters
); i
++)
666 TRACE( " info[%ld]=%016I64x\n", i
, rec
->ExceptionInformation
[i
] );
667 TRACE_CONTEXT( context
);
669 dispatch
.EstablisherFrame
= context
->Rsp
;
670 dispatch
.TargetIp
= (ULONG64
)target_ip
;
671 dispatch
.ContextRecord
= context
;
672 dispatch
.HistoryTable
= table
;
676 status
= virtual_unwind( UNW_FLAG_UHANDLER
, &dispatch
, &new_context
);
677 if (status
!= STATUS_SUCCESS
) raise_status( status
, rec
);
680 if (!dispatch
.EstablisherFrame
) break;
682 if (!is_valid_frame( dispatch
.EstablisherFrame
))
684 ERR( "invalid frame %p (%p-%p)\n", (void *)dispatch
.EstablisherFrame
,
685 NtCurrentTeb()->Tib
.StackLimit
, NtCurrentTeb()->Tib
.StackBase
);
686 rec
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
690 if (dispatch
.LanguageHandler
)
692 if (end_frame
&& (dispatch
.EstablisherFrame
> (ULONG64
)end_frame
))
694 ERR( "invalid end frame %p/%p\n", (void *)dispatch
.EstablisherFrame
, end_frame
);
695 raise_status( STATUS_INVALID_UNWIND_TARGET
, rec
);
697 if (dispatch
.EstablisherFrame
== (ULONG64
)end_frame
) rec
->ExceptionFlags
|= EXCEPTION_TARGET_UNWIND
;
698 TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n",
699 dispatch
.LanguageHandler
, rec
, dispatch
.EstablisherFrame
,
700 dispatch
.ContextRecord
, &dispatch
);
701 res
= call_unwind_handler( rec
, dispatch
.EstablisherFrame
, dispatch
.ContextRecord
,
702 &dispatch
, dispatch
.LanguageHandler
);
703 TRACE( "handler %p returned %lx\n", dispatch
.LanguageHandler
, res
);
707 case ExceptionContinueSearch
:
708 rec
->ExceptionFlags
&= ~EXCEPTION_COLLIDED_UNWIND
;
710 case ExceptionCollidedUnwind
:
711 new_context
= *context
;
712 RtlVirtualUnwind( UNW_FLAG_NHANDLER
, dispatch
.ImageBase
,
713 dispatch
.ControlPc
, dispatch
.FunctionEntry
,
714 &new_context
, NULL
, &frame
, NULL
);
715 rec
->ExceptionFlags
|= EXCEPTION_COLLIDED_UNWIND
;
718 raise_status( STATUS_INVALID_DISPOSITION
, rec
);
722 else /* hack: call builtin handlers registered in the tib list */
724 while (is_valid_frame( (ULONG_PTR
)teb_frame
) &&
725 (ULONG64
)teb_frame
< new_context
.Rsp
&&
726 (ULONG64
)teb_frame
< (ULONG64
)end_frame
)
728 TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
729 teb_frame
->Handler
, rec
, teb_frame
, dispatch
.ContextRecord
, &dispatch
);
730 res
= call_unwind_handler( rec
, (ULONG_PTR
)teb_frame
, dispatch
.ContextRecord
, &dispatch
,
731 (PEXCEPTION_ROUTINE
)teb_frame
->Handler
);
732 TRACE( "handler at %p returned %lu\n", teb_frame
->Handler
, res
);
733 teb_frame
= __wine_pop_frame( teb_frame
);
737 case ExceptionContinueSearch
:
738 rec
->ExceptionFlags
&= ~EXCEPTION_COLLIDED_UNWIND
;
740 case ExceptionCollidedUnwind
:
741 new_context
= *context
;
742 RtlVirtualUnwind( UNW_FLAG_NHANDLER
, dispatch
.ImageBase
,
743 dispatch
.ControlPc
, dispatch
.FunctionEntry
,
744 &new_context
, &dispatch
.HandlerData
,
746 rec
->ExceptionFlags
|= EXCEPTION_COLLIDED_UNWIND
;
749 raise_status( STATUS_INVALID_DISPOSITION
, rec
);
753 if ((ULONG64
)teb_frame
== (ULONG64
)end_frame
&& (ULONG64
)end_frame
< new_context
.Rsp
) break;
756 if (dispatch
.EstablisherFrame
== (ULONG64
)end_frame
) break;
757 *context
= new_context
;
760 context
->Rax
= (ULONG64
)retval
;
761 if (rec
->ExceptionCode
!= STATUS_UNWIND_CONSOLIDATE
) context
->Rip
= (ULONG64
)target_ip
;
762 RtlRestoreContext(context
, rec
);
766 /***********************************************************************
767 * RtlRaiseException (NTDLL.@)
769 __ASM_GLOBAL_FUNC( RtlRaiseException
,
770 "sub $0x4f8,%rsp\n\t"
771 __ASM_SEH(".seh_stackalloc 0x4f8\n\t")
772 __ASM_SEH(".seh_endprologue\n\t")
773 __ASM_CFI(".cfi_adjust_cfa_offset 0x4f8\n\t")
774 "movq %rcx,0x500(%rsp)\n\t"
775 "leaq 0x20(%rsp),%rcx\n\t"
776 "call " __ASM_NAME("RtlCaptureContext") "\n\t"
777 "leaq 0x20(%rsp),%rdx\n\t" /* context pointer */
778 "leaq 0x500(%rsp),%rax\n\t" /* orig stack pointer */
779 "movq %rax,0x98(%rdx)\n\t" /* context->Rsp */
780 "movq (%rax),%rcx\n\t" /* original first parameter */
781 "movq %rcx,0x80(%rdx)\n\t" /* context->Rcx */
782 "movq 0x4f8(%rsp),%rax\n\t" /* return address */
783 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
784 "movq %rax,0x10(%rcx)\n\t" /* rec->ExceptionAddress */
786 "movq %gs:(0x30),%rax\n\t" /* Teb */
787 "movq 0x60(%rax),%rax\n\t" /* Peb */
788 "cmpb $0,0x02(%rax)\n\t" /* BeingDebugged */
790 "call " __ASM_NAME("dispatch_exception") "\n"
791 "1:\tcall " __ASM_NAME("NtRaiseException") "\n\t"
793 "call " __ASM_NAME("RtlRaiseStatus") /* does not return */ );
796 /*************************************************************************
797 * RtlGetNativeSystemInformation (NTDLL.@)
799 NTSTATUS WINAPI
RtlGetNativeSystemInformation( SYSTEM_INFORMATION_CLASS
class,
800 void *info
, ULONG size
, ULONG
*ret_size
)
802 return NtQuerySystemInformation( class, info
, size
, ret_size
);
806 /***********************************************************************
807 * RtlIsProcessorFeaturePresent [NTDLL.@]
809 BOOLEAN WINAPI
RtlIsProcessorFeaturePresent( UINT feature
)
811 return feature
< PROCESSOR_FEATURE_MAX
&& user_shared_data
->ProcessorFeatures
[feature
];
815 /*************************************************************************
816 * RtlWalkFrameChain (NTDLL.@)
818 ULONG WINAPI
RtlWalkFrameChain( void **buffer
, ULONG count
, ULONG flags
)
820 UNWIND_HISTORY_TABLE table
;
821 RUNTIME_FUNCTION
*func
;
822 PEXCEPTION_ROUTINE handler
;
823 ULONG_PTR frame
, base
;
826 ULONG i
, skip
= flags
>> 8, num_entries
= 0;
828 RtlCaptureContext( &context
);
830 for (i
= 0; i
< count
; i
++)
832 func
= RtlLookupFunctionEntry( context
.Rip
, &base
, &table
);
833 if (RtlVirtualUnwind2( UNW_FLAG_NHANDLER
, base
, context
.Rip
, func
, &context
, NULL
,
834 &data
, &frame
, NULL
, NULL
, NULL
, &handler
, 0 ))
836 if (!context
.Rip
) break;
837 if (!frame
|| !is_valid_frame( frame
)) break;
838 if (context
.Rsp
== (ULONG_PTR
)NtCurrentTeb()->Tib
.StackBase
) break;
839 if (i
>= skip
) buffer
[num_entries
++] = (void *)context
.Rip
;
845 /***********************************************************************
847 * _setjmpex (NTDLL.@)
849 __ASM_GLOBAL_FUNC( NTDLL__setjmpex
,
850 __ASM_SEH(".seh_endprologue\n\t")
851 "movq %rdx,(%rcx)\n\t" /* jmp_buf->Frame */
852 "movq %rbx,0x8(%rcx)\n\t" /* jmp_buf->Rbx */
853 "leaq 0x8(%rsp),%rax\n\t"
854 "movq %rax,0x10(%rcx)\n\t" /* jmp_buf->Rsp */
855 "movq %rbp,0x18(%rcx)\n\t" /* jmp_buf->Rbp */
856 "movq %rsi,0x20(%rcx)\n\t" /* jmp_buf->Rsi */
857 "movq %rdi,0x28(%rcx)\n\t" /* jmp_buf->Rdi */
858 "movq %r12,0x30(%rcx)\n\t" /* jmp_buf->R12 */
859 "movq %r13,0x38(%rcx)\n\t" /* jmp_buf->R13 */
860 "movq %r14,0x40(%rcx)\n\t" /* jmp_buf->R14 */
861 "movq %r15,0x48(%rcx)\n\t" /* jmp_buf->R15 */
862 "movq (%rsp),%rax\n\t"
863 "movq %rax,0x50(%rcx)\n\t" /* jmp_buf->Rip */
864 "stmxcsr 0x58(%rcx)\n\t" /* jmp_buf->MxCsr */
865 "fnstcw 0x5c(%rcx)\n\t" /* jmp_buf->FpCsr */
866 "movdqa %xmm6,0x60(%rcx)\n\t" /* jmp_buf->Xmm6 */
867 "movdqa %xmm7,0x70(%rcx)\n\t" /* jmp_buf->Xmm7 */
868 "movdqa %xmm8,0x80(%rcx)\n\t" /* jmp_buf->Xmm8 */
869 "movdqa %xmm9,0x90(%rcx)\n\t" /* jmp_buf->Xmm9 */
870 "movdqa %xmm10,0xa0(%rcx)\n\t" /* jmp_buf->Xmm10 */
871 "movdqa %xmm11,0xb0(%rcx)\n\t" /* jmp_buf->Xmm11 */
872 "movdqa %xmm12,0xc0(%rcx)\n\t" /* jmp_buf->Xmm12 */
873 "movdqa %xmm13,0xd0(%rcx)\n\t" /* jmp_buf->Xmm13 */
874 "movdqa %xmm14,0xe0(%rcx)\n\t" /* jmp_buf->Xmm14 */
875 "movdqa %xmm15,0xf0(%rcx)\n\t" /* jmp_buf->Xmm15 */
880 void __cdecl DECLSPEC_NORETURN
longjmp_regs( _JUMP_BUFFER
*buf
, int retval
);
881 __ASM_GLOBAL_FUNC( longjmp_regs
,
882 __ASM_SEH(".seh_endprologue\n\t")
883 "movq %rdx,%rax\n\t" /* retval */
884 "movq 0x8(%rcx),%rbx\n\t" /* jmp_buf->Rbx */
885 "movq 0x18(%rcx),%rbp\n\t" /* jmp_buf->Rbp */
886 "movq 0x20(%rcx),%rsi\n\t" /* jmp_buf->Rsi */
887 "movq 0x28(%rcx),%rdi\n\t" /* jmp_buf->Rdi */
888 "movq 0x30(%rcx),%r12\n\t" /* jmp_buf->R12 */
889 "movq 0x38(%rcx),%r13\n\t" /* jmp_buf->R13 */
890 "movq 0x40(%rcx),%r14\n\t" /* jmp_buf->R14 */
891 "movq 0x48(%rcx),%r15\n\t" /* jmp_buf->R15 */
892 "movq 0x50(%rcx),%rdx\n\t" /* jmp_buf->Rip */
893 "ldmxcsr 0x58(%rcx)\n\t" /* jmp_buf->MxCsr */
895 "fldcw 0x5c(%rcx)\n\t" /* jmp_buf->FpCsr */
896 "movdqa 0x60(%rcx),%xmm6\n\t" /* jmp_buf->Xmm6 */
897 "movdqa 0x70(%rcx),%xmm7\n\t" /* jmp_buf->Xmm7 */
898 "movdqa 0x80(%rcx),%xmm8\n\t" /* jmp_buf->Xmm8 */
899 "movdqa 0x90(%rcx),%xmm9\n\t" /* jmp_buf->Xmm9 */
900 "movdqa 0xa0(%rcx),%xmm10\n\t" /* jmp_buf->Xmm10 */
901 "movdqa 0xb0(%rcx),%xmm11\n\t" /* jmp_buf->Xmm11 */
902 "movdqa 0xc0(%rcx),%xmm12\n\t" /* jmp_buf->Xmm12 */
903 "movdqa 0xd0(%rcx),%xmm13\n\t" /* jmp_buf->Xmm13 */
904 "movdqa 0xe0(%rcx),%xmm14\n\t" /* jmp_buf->Xmm14 */
905 "movdqa 0xf0(%rcx),%xmm15\n\t" /* jmp_buf->Xmm15 */
906 "movq 0x10(%rcx),%rsp\n\t" /* jmp_buf->Rsp */
909 /*******************************************************************
912 void __cdecl
NTDLL_longjmp( _JUMP_BUFFER
*buf
, int retval
)
914 EXCEPTION_RECORD rec
;
916 if (!retval
) retval
= 1;
917 if (!buf
->Frame
) longjmp_regs( buf
, retval
);
919 rec
.ExceptionCode
= STATUS_LONGJUMP
;
920 rec
.ExceptionFlags
= 0;
921 rec
.ExceptionRecord
= NULL
;
922 rec
.ExceptionAddress
= NULL
;
923 rec
.NumberParameters
= 1;
924 rec
.ExceptionInformation
[0] = (DWORD_PTR
)buf
;
925 RtlUnwind( (void *)buf
->Frame
, (void *)buf
->Rip
, &rec
, IntToPtr(retval
) );
929 /***********************************************************************
930 * RtlUserThreadStart (NTDLL.@)
932 #ifdef __WINE_PE_BUILD
933 __ASM_GLOBAL_FUNC( RtlUserThreadStart
,
934 "subq $0x28,%rsp\n\t"
935 ".seh_stackalloc 0x28\n\t"
936 ".seh_endprologue\n\t"
940 "movq " __ASM_NAME( "pBaseThreadInitThunk" ) "(%rip),%r9\n\t"
943 ".seh_handler " __ASM_NAME("call_unhandled_exception_handler") ", @except" )
945 void WINAPI
RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry
, void *arg
)
949 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE
)entry
, arg
);
951 __EXCEPT(call_unhandled_exception_filter
)
953 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
960 /***********************************************************************
961 * signal_start_thread
963 extern void CDECL DECLSPEC_NORETURN
signal_start_thread( CONTEXT
*ctx
);
964 __ASM_GLOBAL_FUNC( signal_start_thread
,
965 "movq %rcx,%rbx\n\t" /* context */
966 /* clear the thread stack */
967 "andq $~0xfff,%rcx\n\t" /* round down to page size */
968 "leaq -0xf0000(%rcx),%rdi\n\t"
974 /* switch to the initial context */
975 "leaq -32(%rbx),%rsp\n\t"
978 "call " __ASM_NAME("NtContinue") )
981 /******************************************************************
982 * LdrInitializeThunk (NTDLL.@)
984 void WINAPI
LdrInitializeThunk( CONTEXT
*context
, ULONG_PTR unk2
, ULONG_PTR unk3
, ULONG_PTR unk4
)
986 loader_init( context
, (void **)&context
->Rcx
);
987 TRACE_(relay
)( "\1Starting thread proc %p (arg=%p)\n", (void *)context
->Rcx
, (void *)context
->Rdx
);
988 signal_start_thread( context
);
992 /***********************************************************************
995 #ifdef __WINE_PE_BUILD
996 __ASM_GLOBAL_FUNC( process_breakpoint
,
997 ".seh_endprologue\n\t"
998 ".seh_handler process_breakpoint_handler, @except\n\t"
1001 "process_breakpoint_handler:\n\t"
1002 "incq 0xf8(%r8)\n\t" /* context->Rip */
1003 "xorl %eax,%eax\n\t" /* ExceptionContinueExecution */
1006 void WINAPI
process_breakpoint(void)
1010 __asm__
volatile("int $3");
1021 /***********************************************************************
1022 * DbgUiRemoteBreakin (NTDLL.@)
1024 #ifdef __WINE_PE_BUILD
1025 __ASM_GLOBAL_FUNC( DbgUiRemoteBreakin
,
1026 "subq $0x28,%rsp\n\t"
1027 ".seh_stackalloc 0x28\n\t"
1028 ".seh_endprologue\n\t"
1029 ".seh_handler DbgUiRemoteBreakin_handler, @except\n\t"
1030 "mov %gs:0x30,%rax\n\t"
1031 "mov 0x60(%rax),%rax\n\t"
1032 "cmpb $0,2(%rax)\n\t"
1034 "call " __ASM_NAME("DbgBreakPoint") "\n"
1035 "1:\txorl %ecx,%ecx\n\t"
1036 "call " __ASM_NAME("RtlExitUserThread") "\n"
1037 "DbgUiRemoteBreakin_handler:\n\t"
1038 "movq %rdx,%rsp\n\t" /* frame */
1041 void WINAPI
DbgUiRemoteBreakin( void *arg
)
1043 if (NtCurrentTeb()->Peb
->BeingDebugged
)
1055 RtlExitUserThread( STATUS_SUCCESS
);
1059 /**********************************************************************
1060 * DbgBreakPoint (NTDLL.@)
1062 __ASM_GLOBAL_FUNC( DbgBreakPoint
, "int $3; ret"
1063 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
1064 "\n\tnop; nop; nop; nop; nop; nop" );
1066 /**********************************************************************
1067 * DbgUserBreakPoint (NTDLL.@)
1069 __ASM_GLOBAL_FUNC( DbgUserBreakPoint
, "int $3; ret"
1070 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
1071 "\n\tnop; nop; nop; nop; nop; nop" );
1073 #endif /* __arm64ec_x64__ */
1074 #endif /* __x86_64__ */