include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / ntdll / signal_x86_64.c
blob0daf27f6850cc3988ce5befd30941b7c2dab3219
1 /*
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
21 #if 0
22 #pragma makedep arm64ec_x64
23 #endif
25 #ifdef __x86_64__
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <setjmp.h>
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #include "windef.h"
34 #include "winternl.h"
35 #include "ddk/wdm.h"
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 /**************************************************************************
44 * __chkstk (NTDLL.@)
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 /*******************************************************************
58 * syscalls
60 #define SYSCALL_ENTRY(id,name,args) __ASM_SYSCALL_FUNC( id, name )
61 ALL_SYSCALLS64
62 #undef SYSCALL_ENTRY
65 /***********************************************************************
66 * virtual_unwind
68 static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context )
70 LDR_DATA_TABLE_ENTRY *module;
71 NTSTATUS status;
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, &params );
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,
104 "pushfq\n\t"
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 */
136 "ret" );
139 /***********************************************************************
140 * call_seh_handler
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"
153 "ret" )
154 #else
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;
159 DWORD res;
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 );
165 return res;
167 #endif
170 /**********************************************************************
171 * call_seh_handlers
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;
180 CONTEXT context;
181 NTSTATUS status;
182 ULONG_PTR frame;
183 DWORD res;
185 context = *orig_context;
186 context.ContextFlags &= ~0x40; /* Clear xstate flag. */
188 dispatch.TargetIp = 0;
189 dispatch.ContextRecord = &context;
190 dispatch.HistoryTable = &table;
191 for (;;)
193 status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context );
194 if (status != STATUS_SUCCESS) return status;
196 unwind_done:
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;
204 break;
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 );
216 switch (res)
218 case ExceptionContinueExecution:
219 if (rec->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
220 return STATUS_SUCCESS;
221 case ExceptionContinueSearch:
222 break;
223 case ExceptionNestedException:
224 rec->ExceptionFlags |= EXCEPTION_NESTED_CALL;
225 TRACE( "nested exception\n" );
226 break;
227 case ExceptionCollidedUnwind:
228 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase, dispatch.ControlPc,
229 dispatch.FunctionEntry, &context, NULL, &frame, NULL );
230 goto unwind_done;
231 default:
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 );
244 switch (res)
246 case ExceptionContinueExecution:
247 if (rec->ExceptionFlags & EXCEPTION_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
248 return STATUS_SUCCESS;
249 case ExceptionContinueSearch:
250 break;
251 case ExceptionNestedException:
252 rec->ExceptionFlags |= EXCEPTION_NESTED_CALL;
253 TRACE( "nested exception\n" );
254 break;
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;
259 goto unwind_done;
260 default:
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")
299 "cld\n\t"
300 /* some anticheats need this exact instruction here */
301 "mov " __ASM_NAME("pWow64PrepareForException") "(%rip),%rax\n\t"
302 "test %rax,%rax\n\t"
303 "jz 1f\n\t"
304 "mov %rsp,%rdx\n\t" /* context */
305 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
306 "call *%rax\n"
307 "1:\tmov %rsp,%rdx\n\t" /* context */
308 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
309 "call " __ASM_NAME("dispatch_exception") "\n\t"
310 "int3" )
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 */
345 "callq *%rax\n\t"
346 "movq %rsp,%rcx\n\t" /* context */
347 "movl $1,%edx\n\t" /* alertable */
348 "call " __ASM_NAME("NtContinue") "\n\t"
349 "int3" )
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"
374 #else
375 "call " __ASM_NAME("dispatch_user_callback") "\n\t"
376 #endif
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"
383 "int3" )
386 /**************************************************************************
387 * RtlIsEcCode (NTDLL.@)
389 BOOLEAN WINAPI RtlIsEcCode( ULONG_PTR ptr )
391 return FALSE;
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"
448 "ret" )
449 #else
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;
454 DWORD res;
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 );
461 return res;
463 #endif
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,
485 "pushq %rbp\n\t"
486 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
487 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
488 "movq %rsp,%rbp\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")
555 "pushq %rsi\n\t"
556 "pushq %rdi\n\t"
557 "leaq 0x200(%rcx),%rsi\n\t"
558 "leaq 0x70(%rsp),%rdi\n\t"
559 "movq $0x14,%rcx\n\t"
560 "cld\n\t"
561 "rep; movsq\n\t"
562 "popq %rdi\n\t"
563 "popq %rsi\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. */
576 "movq %r8,%rcx\n\t"
577 "callq *%rdx\n\t"
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
581 * machine frame. */
582 "leaq 0(%rbp),%rsp\n\t"
583 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
584 "popq %rbp\n\t"
585 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
586 __ASM_CFI(".cfi_same_value %rbp\n\t")
587 "ret")
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;
642 CONTEXT new_context;
643 NTSTATUS status;
644 ULONG_PTR frame;
645 DWORD i, res;
647 RtlCaptureContext( context );
648 new_context = *context;
650 /* build an exception record, if we do not have one */
651 if (!rec)
653 record.ExceptionCode = STATUS_UNWIND;
654 record.ExceptionFlags = 0;
655 record.ExceptionRecord = NULL;
656 record.ExceptionAddress = (void *)context->Rip;
657 record.NumberParameters = 0;
658 rec = &record;
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;
674 for (;;)
676 status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context );
677 if (status != STATUS_SUCCESS) raise_status( status, rec );
679 unwind_done:
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;
687 break;
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 );
705 switch (res)
707 case ExceptionContinueSearch:
708 rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
709 break;
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;
716 goto unwind_done;
717 default:
718 raise_status( STATUS_INVALID_DISPOSITION, rec );
719 break;
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 );
735 switch (res)
737 case ExceptionContinueSearch:
738 rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
739 break;
740 case ExceptionCollidedUnwind:
741 new_context = *context;
742 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
743 dispatch.ControlPc, dispatch.FunctionEntry,
744 &new_context, &dispatch.HandlerData,
745 &frame, NULL );
746 rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
747 goto unwind_done;
748 default:
749 raise_status( STATUS_INVALID_DISPOSITION, rec );
750 break;
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 */
785 "movl $1,%r8d\n\t"
786 "movq %gs:(0x30),%rax\n\t" /* Teb */
787 "movq 0x60(%rax),%rax\n\t" /* Peb */
788 "cmpb $0,0x02(%rax)\n\t" /* BeingDebugged */
789 "jne 1f\n\t"
790 "call " __ASM_NAME("dispatch_exception") "\n"
791 "1:\tcall " __ASM_NAME("NtRaiseException") "\n\t"
792 "movq %rax,%rcx\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;
824 CONTEXT context;
825 void *data;
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 ))
835 break;
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;
841 return num_entries;
845 /***********************************************************************
846 * _setjmp (NTDLL.@)
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 */
876 "xorq %rax,%rax\n\t"
877 "retq" )
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 */
894 "fnclex\n\t"
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 */
907 "jmp *%rdx" )
909 /*******************************************************************
910 * longjmp (MSVCRT.@)
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"
937 "movq %rdx,%r8\n\t"
938 "movq %rcx,%rdx\n\t"
939 "xorq %rcx,%rcx\n\t"
940 "movq " __ASM_NAME( "pBaseThreadInitThunk" ) "(%rip),%r9\n\t"
941 "call *%r9\n\t"
942 "int3\n\t"
943 ".seh_handler " __ASM_NAME("call_unhandled_exception_handler") ", @except" )
944 #else
945 void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
947 __TRY
949 pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE)entry, arg );
951 __EXCEPT(call_unhandled_exception_filter)
953 NtTerminateProcess( GetCurrentProcess(), GetExceptionCode() );
955 __ENDTRY
957 #endif
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"
969 "movq %rdi,%rsp\n\t"
970 "subq %rdi,%rcx\n\t"
971 "xorl %eax,%eax\n\t"
972 "shrq $3,%rcx\n\t"
973 "rep; stosq\n\t"
974 /* switch to the initial context */
975 "leaq -32(%rbx),%rsp\n\t"
976 "movq %rbx,%rcx\n\t"
977 "movl $1,%edx\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 /***********************************************************************
993 * process_breakpoint
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"
999 "int $3\n\t"
1000 "ret\n"
1001 "process_breakpoint_handler:\n\t"
1002 "incq 0xf8(%r8)\n\t" /* context->Rip */
1003 "xorl %eax,%eax\n\t" /* ExceptionContinueExecution */
1004 "ret" )
1005 #else
1006 void WINAPI process_breakpoint(void)
1008 __TRY
1010 __asm__ volatile("int $3");
1012 __EXCEPT_ALL
1014 /* do nothing */
1016 __ENDTRY
1018 #endif
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"
1033 "je 1f\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 */
1039 "jmp 1b" )
1040 #else
1041 void WINAPI DbgUiRemoteBreakin( void *arg )
1043 if (NtCurrentTeb()->Peb->BeingDebugged)
1045 __TRY
1047 DbgBreakPoint();
1049 __EXCEPT_ALL
1051 /* do nothing */
1053 __ENDTRY
1055 RtlExitUserThread( STATUS_SUCCESS );
1057 #endif
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__ */