windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / ntdll / signal_x86_64.c
blob2f7715a0a600399347ea03575c8f26cbd257e188
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 #ifdef __x86_64__
23 #include <stdlib.h>
24 #include <stdarg.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winternl.h"
30 #include "wine/exception.h"
31 #include "wine/list.h"
32 #include "ntdll_misc.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(unwind);
36 WINE_DECLARE_DEBUG_CHANNEL(seh);
37 WINE_DECLARE_DEBUG_CHANNEL(threadname);
39 typedef struct _SCOPE_TABLE
41 ULONG Count;
42 struct
44 ULONG BeginAddress;
45 ULONG EndAddress;
46 ULONG HandlerAddress;
47 ULONG JumpTarget;
48 } ScopeRecord[1];
49 } SCOPE_TABLE, *PSCOPE_TABLE;
52 /* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
53 struct MSVCRT_JUMP_BUFFER
55 ULONG64 Frame;
56 ULONG64 Rbx;
57 ULONG64 Rsp;
58 ULONG64 Rbp;
59 ULONG64 Rsi;
60 ULONG64 Rdi;
61 ULONG64 R12;
62 ULONG64 R13;
63 ULONG64 R14;
64 ULONG64 R15;
65 ULONG64 Rip;
66 ULONG MxCsr;
67 USHORT FpCsr;
68 USHORT Spare;
69 M128A Xmm6;
70 M128A Xmm7;
71 M128A Xmm8;
72 M128A Xmm9;
73 M128A Xmm10;
74 M128A Xmm11;
75 M128A Xmm12;
76 M128A Xmm13;
77 M128A Xmm14;
78 M128A Xmm15;
81 /***********************************************************************
82 * Definitions for Win32 unwind tables
85 union handler_data
87 RUNTIME_FUNCTION chain;
88 ULONG handler;
91 struct opcode
93 BYTE offset;
94 BYTE code : 4;
95 BYTE info : 4;
98 struct UNWIND_INFO
100 BYTE version : 3;
101 BYTE flags : 5;
102 BYTE prolog;
103 BYTE count;
104 BYTE frame_reg : 4;
105 BYTE frame_offset : 4;
106 struct opcode opcodes[1]; /* info->count entries */
107 /* followed by handler_data */
110 #define UWOP_PUSH_NONVOL 0
111 #define UWOP_ALLOC_LARGE 1
112 #define UWOP_ALLOC_SMALL 2
113 #define UWOP_SET_FPREG 3
114 #define UWOP_SAVE_NONVOL 4
115 #define UWOP_SAVE_NONVOL_FAR 5
116 #define UWOP_EPILOG 6
117 #define UWOP_SAVE_XMM128 8
118 #define UWOP_SAVE_XMM128_FAR 9
119 #define UWOP_PUSH_MACHFRAME 10
121 static void dump_unwind_info( ULONG64 base, RUNTIME_FUNCTION *function )
123 static const char * const reg_names[16] =
124 { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
125 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
127 union handler_data *handler_data;
128 struct UNWIND_INFO *info;
129 unsigned int i, count;
131 TRACE( "**** func %lx-%lx\n", function->BeginAddress, function->EndAddress );
132 for (;;)
134 if (function->UnwindData & 1)
136 RUNTIME_FUNCTION *next = (RUNTIME_FUNCTION *)((char *)base + (function->UnwindData & ~1));
137 TRACE( "unwind info for function %p-%p chained to function %p-%p\n",
138 (char *)base + function->BeginAddress, (char *)base + function->EndAddress,
139 (char *)base + next->BeginAddress, (char *)base + next->EndAddress );
140 function = next;
141 continue;
143 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
145 TRACE( "unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
146 info, info->flags, info->prolog,
147 (char *)base + function->BeginAddress, (char *)base + function->EndAddress );
149 if (info->frame_reg)
150 TRACE( " frame register %s offset 0x%x(%%rsp)\n",
151 reg_names[info->frame_reg], info->frame_offset * 16 );
153 for (i = 0; i < info->count; i++)
155 TRACE( " 0x%x: ", info->opcodes[i].offset );
156 switch (info->opcodes[i].code)
158 case UWOP_PUSH_NONVOL:
159 TRACE( "pushq %%%s\n", reg_names[info->opcodes[i].info] );
160 break;
161 case UWOP_ALLOC_LARGE:
162 if (info->opcodes[i].info)
164 count = *(DWORD *)&info->opcodes[i+1];
165 i += 2;
167 else
169 count = *(USHORT *)&info->opcodes[i+1] * 8;
170 i++;
172 TRACE( "subq $0x%x,%%rsp\n", count );
173 break;
174 case UWOP_ALLOC_SMALL:
175 count = (info->opcodes[i].info + 1) * 8;
176 TRACE( "subq $0x%x,%%rsp\n", count );
177 break;
178 case UWOP_SET_FPREG:
179 TRACE( "leaq 0x%x(%%rsp),%s\n",
180 info->frame_offset * 16, reg_names[info->frame_reg] );
181 break;
182 case UWOP_SAVE_NONVOL:
183 count = *(USHORT *)&info->opcodes[i+1] * 8;
184 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
185 i++;
186 break;
187 case UWOP_SAVE_NONVOL_FAR:
188 count = *(DWORD *)&info->opcodes[i+1];
189 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
190 i += 2;
191 break;
192 case UWOP_SAVE_XMM128:
193 count = *(USHORT *)&info->opcodes[i+1] * 16;
194 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
195 i++;
196 break;
197 case UWOP_SAVE_XMM128_FAR:
198 count = *(DWORD *)&info->opcodes[i+1];
199 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
200 i += 2;
201 break;
202 case UWOP_PUSH_MACHFRAME:
203 TRACE( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
204 break;
205 case UWOP_EPILOG:
206 if (info->version == 2)
208 unsigned int offset;
209 if (info->opcodes[i].info)
210 offset = info->opcodes[i].offset;
211 else
212 offset = (info->opcodes[i+1].info << 8) + info->opcodes[i+1].offset;
213 TRACE("epilog %p-%p\n", (char *)base + function->EndAddress - offset,
214 (char *)base + function->EndAddress - offset + info->opcodes[i].offset );
215 i += 1;
216 break;
218 default:
219 FIXME( "unknown code %u\n", info->opcodes[i].code );
220 break;
224 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
225 if (info->flags & UNW_FLAG_CHAININFO)
227 TRACE( " chained to function %p-%p\n",
228 (char *)base + handler_data->chain.BeginAddress,
229 (char *)base + handler_data->chain.EndAddress );
230 function = &handler_data->chain;
231 continue;
233 if (info->flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
234 TRACE( " handler %p data at %p\n",
235 (char *)base + handler_data->handler, &handler_data->handler + 1 );
236 break;
240 static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table )
242 unsigned int i;
244 TRACE( "scope table at %p\n", table );
245 for (i = 0; i < table->Count; i++)
246 TRACE( " %u: %p-%p handler %p target %p\n", i,
247 (char *)base + table->ScopeRecord[i].BeginAddress,
248 (char *)base + table->ScopeRecord[i].EndAddress,
249 (char *)base + table->ScopeRecord[i].HandlerAddress,
250 (char *)base + table->ScopeRecord[i].JumpTarget );
254 /***********************************************************************
255 * virtual_unwind
257 static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context )
259 LDR_DATA_TABLE_ENTRY *module;
260 NTSTATUS status;
262 dispatch->ImageBase = 0;
263 dispatch->ScopeIndex = 0;
264 dispatch->ControlPc = context->Rip;
266 /* first look for PE exception information */
268 if ((dispatch->FunctionEntry = lookup_function_info( context->Rip, &dispatch->ImageBase, &module )))
270 dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Rip,
271 dispatch->FunctionEntry, context,
272 &dispatch->HandlerData, &dispatch->EstablisherFrame,
273 NULL );
274 return STATUS_SUCCESS;
277 /* then look for host system exception information */
279 if (!module || (module->Flags & LDR_WINE_INTERNAL))
281 struct unwind_builtin_dll_params params = { type, dispatch, context };
283 status = WINE_UNIX_CALL( unix_unwind_builtin_dll, &params );
284 if (!status && dispatch->LanguageHandler && !module)
286 FIXME( "calling personality routine in system library not supported yet\n" );
287 dispatch->LanguageHandler = NULL;
289 if (status != STATUS_UNSUCCESSFUL) return status;
291 else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
293 /* no exception information, treat as a leaf function */
295 dispatch->EstablisherFrame = context->Rsp;
296 dispatch->LanguageHandler = NULL;
297 context->Rip = *(ULONG64 *)context->Rsp;
298 context->Rsp = context->Rsp + sizeof(ULONG64);
299 return STATUS_SUCCESS;
303 /**************************************************************************
304 * __chkstk (NTDLL.@)
306 * Supposed to touch all the stack pages, but we shouldn't need that.
308 __ASM_GLOBAL_FUNC( __chkstk, "ret" );
311 /***********************************************************************
312 * RtlCaptureContext (NTDLL.@)
314 __ASM_GLOBAL_FUNC( RtlCaptureContext,
315 "pushfq\n\t"
316 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
317 "movl $0x10000f,0x30(%rcx)\n\t" /* context->ContextFlags */
318 "stmxcsr 0x34(%rcx)\n\t" /* context->MxCsr */
319 "movw %cs,0x38(%rcx)\n\t" /* context->SegCs */
320 "movw %ds,0x3a(%rcx)\n\t" /* context->SegDs */
321 "movw %es,0x3c(%rcx)\n\t" /* context->SegEs */
322 "movw %fs,0x3e(%rcx)\n\t" /* context->SegFs */
323 "movw %gs,0x40(%rcx)\n\t" /* context->SegGs */
324 "movw %ss,0x42(%rcx)\n\t" /* context->SegSs */
325 "popq 0x44(%rcx)\n\t" /* context->Eflags */
326 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
327 "movq %rax,0x78(%rcx)\n\t" /* context->Rax */
328 "movq %rcx,0x80(%rcx)\n\t" /* context->Rcx */
329 "movq %rdx,0x88(%rcx)\n\t" /* context->Rdx */
330 "movq %rbx,0x90(%rcx)\n\t" /* context->Rbx */
331 "leaq 8(%rsp),%rax\n\t"
332 "movq %rax,0x98(%rcx)\n\t" /* context->Rsp */
333 "movq %rbp,0xa0(%rcx)\n\t" /* context->Rbp */
334 "movq %rsi,0xa8(%rcx)\n\t" /* context->Rsi */
335 "movq %rdi,0xb0(%rcx)\n\t" /* context->Rdi */
336 "movq %r8,0xb8(%rcx)\n\t" /* context->R8 */
337 "movq %r9,0xc0(%rcx)\n\t" /* context->R9 */
338 "movq %r10,0xc8(%rcx)\n\t" /* context->R10 */
339 "movq %r11,0xd0(%rcx)\n\t" /* context->R11 */
340 "movq %r12,0xd8(%rcx)\n\t" /* context->R12 */
341 "movq %r13,0xe0(%rcx)\n\t" /* context->R13 */
342 "movq %r14,0xe8(%rcx)\n\t" /* context->R14 */
343 "movq %r15,0xf0(%rcx)\n\t" /* context->R15 */
344 "movq (%rsp),%rax\n\t"
345 "movq %rax,0xf8(%rcx)\n\t" /* context->Rip */
346 "fxsave 0x100(%rcx)\n\t" /* context->FltSave */
347 "ret" );
349 static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
350 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
352 if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
353 rec->ExceptionFlags |= EH_NESTED_CALL;
355 return ExceptionContinueSearch;
358 /**********************************************************************
359 * call_handler
361 * Call a single exception handler.
362 * FIXME: Handle nested exceptions.
364 static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
366 EXCEPTION_REGISTRATION_RECORD frame;
367 DWORD res;
369 frame.Handler = nested_exception_handler;
370 __wine_push_frame( &frame );
372 TRACE_(seh)( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
373 dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
374 res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, context, dispatch );
375 TRACE_(seh)( "handler at %p returned %lu\n", dispatch->LanguageHandler, res );
377 rec->ExceptionFlags &= EH_NONCONTINUABLE;
378 __wine_pop_frame( &frame );
379 return res;
383 /**********************************************************************
384 * call_teb_handler
386 * Call a single exception handler from the TEB chain.
387 * FIXME: Handle nested exceptions.
389 static DWORD call_teb_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch,
390 EXCEPTION_REGISTRATION_RECORD *teb_frame )
392 DWORD res;
394 TRACE_(seh)( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
395 teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
396 res = teb_frame->Handler( rec, teb_frame, context, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
397 TRACE_(seh)( "handler at %p returned %lu\n", teb_frame->Handler, res );
398 return res;
402 /**********************************************************************
403 * call_stack_handlers
405 * Call the stack handlers chain.
407 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
409 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
410 UNWIND_HISTORY_TABLE table;
411 DISPATCHER_CONTEXT dispatch;
412 CONTEXT context;
413 NTSTATUS status;
415 context = *orig_context;
416 context.ContextFlags &= ~0x40; /* Clear xstate flag. */
418 dispatch.TargetIp = 0;
419 dispatch.ContextRecord = &context;
420 dispatch.HistoryTable = &table;
421 for (;;)
423 status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context );
424 if (status != STATUS_SUCCESS) return status;
426 unwind_done:
427 if (!dispatch.EstablisherFrame) break;
429 if ((dispatch.EstablisherFrame & 7) ||
430 dispatch.EstablisherFrame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
431 dispatch.EstablisherFrame > (ULONG64)NtCurrentTeb()->Tib.StackBase)
433 ERR_(seh)( "invalid frame %p (%p-%p)\n", (void *)dispatch.EstablisherFrame,
434 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
435 rec->ExceptionFlags |= EH_STACK_INVALID;
436 break;
439 if (dispatch.LanguageHandler)
441 switch (call_handler( rec, orig_context, &dispatch ))
443 case ExceptionContinueExecution:
444 if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
445 return STATUS_SUCCESS;
446 case ExceptionContinueSearch:
447 break;
448 case ExceptionNestedException:
449 FIXME_(seh)( "nested exception\n" );
450 break;
451 case ExceptionCollidedUnwind: {
452 ULONG64 frame;
454 context = *dispatch.ContextRecord;
455 dispatch.ContextRecord = &context;
456 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
457 dispatch.ControlPc, dispatch.FunctionEntry,
458 &context, NULL, &frame, NULL );
459 goto unwind_done;
461 default:
462 return STATUS_INVALID_DISPOSITION;
465 /* hack: call wine handlers registered in the tib list */
466 else while ((ULONG64)teb_frame < context.Rsp)
468 TRACE_(seh)( "found wine frame %p rsp %p handler %p\n",
469 teb_frame, (void *)context.Rsp, teb_frame->Handler );
470 dispatch.EstablisherFrame = (ULONG64)teb_frame;
471 switch (call_teb_handler( rec, orig_context, &dispatch, teb_frame ))
473 case ExceptionContinueExecution:
474 if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
475 return STATUS_SUCCESS;
476 case ExceptionContinueSearch:
477 break;
478 case ExceptionNestedException:
479 FIXME_(seh)( "nested exception\n" );
480 break;
481 case ExceptionCollidedUnwind: {
482 ULONG64 frame;
484 context = *dispatch.ContextRecord;
485 dispatch.ContextRecord = &context;
486 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
487 dispatch.ControlPc, dispatch.FunctionEntry,
488 &context, NULL, &frame, NULL );
489 teb_frame = teb_frame->Prev;
490 goto unwind_done;
492 default:
493 return STATUS_INVALID_DISPOSITION;
495 teb_frame = teb_frame->Prev;
498 if (context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
500 return STATUS_UNHANDLED_EXCEPTION;
504 NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
506 NTSTATUS status;
507 DWORD c;
509 if (pWow64PrepareForException) pWow64PrepareForException( rec, context );
511 TRACE_(seh)( "code=%lx flags=%lx addr=%p ip=%Ix\n",
512 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Rip );
513 for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
514 TRACE_(seh)( " info[%ld]=%016I64x\n", c, rec->ExceptionInformation[c] );
516 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
518 if (rec->ExceptionInformation[1] >> 16)
519 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
520 rec->ExceptionAddress,
521 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
522 else
523 MESSAGE( "wine: Call from %p to unimplemented function %s.%I64d, aborting\n",
524 rec->ExceptionAddress,
525 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
527 else if (rec->ExceptionCode == EXCEPTION_WINE_NAME_THREAD && rec->ExceptionInformation[0] == 0x1000)
529 if ((DWORD)rec->ExceptionInformation[2] == -1 || (DWORD)rec->ExceptionInformation[2] == GetCurrentThreadId())
530 WARN_(threadname)( "Thread renamed to %s\n", debugstr_a((char *)rec->ExceptionInformation[1]) );
531 else
532 WARN_(threadname)( "Thread ID %04lx renamed to %s\n", (DWORD)rec->ExceptionInformation[2],
533 debugstr_a((char *)rec->ExceptionInformation[1]) );
535 set_native_thread_name((DWORD)rec->ExceptionInformation[2], (char *)rec->ExceptionInformation[1]);
537 else if (rec->ExceptionCode == DBG_PRINTEXCEPTION_C)
539 WARN_(seh)( "%s\n", debugstr_an((char *)rec->ExceptionInformation[1], rec->ExceptionInformation[0] - 1) );
541 else if (rec->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C)
543 WARN_(seh)( "%s\n", debugstr_wn((WCHAR *)rec->ExceptionInformation[1], rec->ExceptionInformation[0] - 1) );
545 else
547 if (rec->ExceptionCode == STATUS_ASSERTION_FAILURE)
548 ERR_(seh)( "%s exception (code=%lx) raised\n", debugstr_exception_code(rec->ExceptionCode), rec->ExceptionCode );
549 else
550 WARN_(seh)( "%s exception (code=%lx) raised\n", debugstr_exception_code(rec->ExceptionCode), rec->ExceptionCode );
552 TRACE_(seh)( " rax=%016I64x rbx=%016I64x rcx=%016I64x rdx=%016I64x\n",
553 context->Rax, context->Rbx, context->Rcx, context->Rdx );
554 TRACE_(seh)( " rsi=%016I64x rdi=%016I64x rbp=%016I64x rsp=%016I64x\n",
555 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
556 TRACE_(seh)( " r8=%016I64x r9=%016I64x r10=%016I64x r11=%016I64x\n",
557 context->R8, context->R9, context->R10, context->R11 );
558 TRACE_(seh)( " r12=%016I64x r13=%016I64x r14=%016I64x r15=%016I64x\n",
559 context->R12, context->R13, context->R14, context->R15 );
562 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
563 NtContinue( context, FALSE );
565 if ((status = call_stack_handlers( rec, context )) == STATUS_SUCCESS)
566 NtContinue( context, FALSE );
568 if (status != STATUS_UNHANDLED_EXCEPTION) RtlRaiseStatus( status );
569 return NtRaiseException( rec, context, FALSE );
573 NTSTATUS WINAPI dispatch_wow_exception( EXCEPTION_RECORD *rec_ptr, CONTEXT *context_ptr )
575 char buffer[sizeof(CONTEXT) + sizeof(CONTEXT_EX) + sizeof(XSTATE) + 128];
576 CONTEXT *context;
577 CONTEXT_EX *context_ex;
578 EXCEPTION_RECORD rec = *rec_ptr;
580 RtlInitializeExtendedContext( buffer, context_ptr->ContextFlags, &context_ex );
581 context = RtlLocateLegacyContext( context_ex, NULL );
582 RtlCopyContext( context, context_ptr->ContextFlags, context_ptr );
583 return dispatch_exception( &rec, context );
587 /*******************************************************************
588 * KiUserExceptionDispatcher (NTDLL.@)
590 __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
591 "mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */
592 "movw %cs,%ax\n\t"
593 "cmpw %ax,0x38(%rsp)\n\t" /* context->SegCs */
594 "je 1f\n\t"
595 "mov %rsp,%rdx\n\t" /* context */
596 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
597 "movq %r14,%rsp\n\t" /* switch to 64-bit stack */
598 "call " __ASM_NAME("dispatch_wow_exception") "\n\t"
599 "int3\n"
600 "1:\tmov 0xf8(%rsp),%rdx\n\t" /* context->Rip */
601 "mov %rdx,-0x8(%rcx)\n\t"
602 "mov %rbp,-0x10(%rcx)\n\t"
603 "mov %rdi,-0x18(%rcx)\n\t"
604 "mov %rsi,-0x20(%rcx)\n\t"
605 "lea -0x20(%rcx),%rbp\n\t"
606 "mov %rsp,%rdx\n\t" /* context */
607 "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
608 __ASM_SEH(".seh_pushreg %rbp\n\t")
609 __ASM_SEH(".seh_pushreg %rdi\n\t")
610 __ASM_SEH(".seh_pushreg %rsi\n\t")
611 __ASM_SEH(".seh_setframe %rbp,0\n\t")
612 __ASM_SEH(".seh_endprologue\n\t")
614 __ASM_CFI(".cfi_signal_frame\n\t")
615 __ASM_CFI(".cfi_adjust_cfa_offset 0x20\n\t")
616 __ASM_CFI(".cfi_def_cfa %rbp,0x20\n\t")
617 __ASM_CFI(".cfi_rel_offset %rip,0x18\n\t")
618 __ASM_CFI(".cfi_rel_offset %rbp,0x10\n\t")
619 __ASM_CFI(".cfi_rel_offset %rdi,0x8\n\t")
620 __ASM_CFI(".cfi_rel_offset %rsi,0\n\t")
621 "call " __ASM_NAME("dispatch_exception") "\n\t"
622 "int3")
625 /*******************************************************************
626 * KiUserApcDispatcher (NTDLL.@)
628 void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
629 void (CALLBACK *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR,CONTEXT*) )
631 func( arg1, arg2, arg3, context );
632 NtContinue( context, TRUE );
635 __ASM_GLOBAL_FUNC( KiUserApcDispatcher,
636 "addq $0x8,%rsp\n\t"
637 "mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
638 "mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
639 "mov %r11,-0x8(%r10)\n\t"
640 "mov %rbp,-0x10(%r10)\n\t"
641 "lea -0x10(%r10),%rbp\n\t"
642 __ASM_SEH(".seh_pushreg %rbp\n\t")
643 __ASM_SEH(".seh_setframe %rbp,0\n\t")
644 __ASM_SEH(".seh_endprologue\n\t")
645 __ASM_CFI(".cfi_signal_frame\n\t")
646 __ASM_CFI(".cfi_adjust_cfa_offset 0x10\n\t")
647 __ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
648 __ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
649 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
650 "call " __ASM_NAME("dispatch_apc") "\n\t"
651 "int3")
654 /*******************************************************************
655 * KiUserCallbackDispatcher (NTDLL.@)
657 * FIXME: not binary compatible
659 void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len )
661 NTSTATUS status;
663 __TRY
665 NTSTATUS (WINAPI *func)(void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id];
666 status = NtCallbackReturn( NULL, 0, func( args, len ));
668 __EXCEPT_ALL
670 ERR_(seh)( "ignoring exception\n" );
671 status = NtCallbackReturn( 0, 0, 0 );
673 __ENDTRY
675 RtlRaiseStatus( status );
679 /**************************************************************************
680 * RtlIsEcCode (NTDLL.@)
682 BOOLEAN WINAPI RtlIsEcCode( const void *ptr )
684 const UINT64 *map = (const UINT64 *)NtCurrentTeb()->Peb->EcCodeBitMap;
685 ULONG_PTR page = (ULONG_PTR)ptr / page_size;
686 if (!map) return FALSE;
687 return (map[page / 64] >> (page & 63)) & 1;
691 static ULONG64 get_int_reg( CONTEXT *context, int reg )
693 return *(&context->Rax + reg);
696 static void set_int_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, ULONG64 *val )
698 *(&context->Rax + reg) = *val;
699 if (ctx_ptr) ctx_ptr->IntegerContext[reg] = val;
702 static void set_float_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, M128A *val )
704 /* Use a memcpy() to avoid issues if val is misaligned. */
705 memcpy(&context->Xmm0 + reg, val, sizeof(*val));
706 if (ctx_ptr) ctx_ptr->FloatingContext[reg] = val;
709 static int get_opcode_size( struct opcode op )
711 switch (op.code)
713 case UWOP_ALLOC_LARGE:
714 return 2 + (op.info != 0);
715 case UWOP_SAVE_NONVOL:
716 case UWOP_SAVE_XMM128:
717 case UWOP_EPILOG:
718 return 2;
719 case UWOP_SAVE_NONVOL_FAR:
720 case UWOP_SAVE_XMM128_FAR:
721 return 3;
722 default:
723 return 1;
727 static BOOL is_inside_epilog( BYTE *pc, ULONG64 base, const RUNTIME_FUNCTION *function )
729 /* add or lea must be the first instruction, and it must have a rex.W prefix */
730 if ((pc[0] & 0xf8) == 0x48)
732 switch (pc[1])
734 case 0x81: /* add $nnnn,%rsp */
735 if (pc[0] == 0x48 && pc[2] == 0xc4)
737 pc += 7;
738 break;
740 return FALSE;
741 case 0x83: /* add $n,%rsp */
742 if (pc[0] == 0x48 && pc[2] == 0xc4)
744 pc += 4;
745 break;
747 return FALSE;
748 case 0x8d: /* lea n(reg),%rsp */
749 if (pc[0] & 0x06) return FALSE; /* rex.RX must be cleared */
750 if (((pc[2] >> 3) & 7) != 4) return FALSE; /* dest reg mus be %rsp */
751 if ((pc[2] & 7) == 4) return FALSE; /* no SIB byte allowed */
752 if ((pc[2] >> 6) == 1) /* 8-bit offset */
754 pc += 4;
755 break;
757 if ((pc[2] >> 6) == 2) /* 32-bit offset */
759 pc += 7;
760 break;
762 return FALSE;
766 /* now check for various pop instructions */
768 for (;;)
770 if ((*pc & 0xf0) == 0x40) pc++; /* rex prefix */
772 switch (*pc)
774 case 0x58: /* pop %rax/%r8 */
775 case 0x59: /* pop %rcx/%r9 */
776 case 0x5a: /* pop %rdx/%r10 */
777 case 0x5b: /* pop %rbx/%r11 */
778 case 0x5c: /* pop %rsp/%r12 */
779 case 0x5d: /* pop %rbp/%r13 */
780 case 0x5e: /* pop %rsi/%r14 */
781 case 0x5f: /* pop %rdi/%r15 */
782 pc++;
783 continue;
784 case 0xc2: /* ret $nn */
785 case 0xc3: /* ret */
786 return TRUE;
787 case 0xe9: /* jmp nnnn */
788 pc += 5 + *(LONG *)(pc + 1);
789 if (pc - (BYTE *)base >= function->BeginAddress && pc - (BYTE *)base < function->EndAddress)
790 continue;
791 break;
792 case 0xeb: /* jmp n */
793 pc += 2 + (signed char)pc[1];
794 if (pc - (BYTE *)base >= function->BeginAddress && pc - (BYTE *)base < function->EndAddress)
795 continue;
796 break;
797 case 0xf3: /* rep; ret (for amd64 prediction bug) */
798 return pc[1] == 0xc3;
800 return FALSE;
804 /* execute a function epilog, which must have been validated with is_inside_epilog() */
805 static void interpret_epilog( BYTE *pc, CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
807 for (;;)
809 BYTE rex = 0;
811 if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f; /* rex prefix */
813 switch (*pc)
815 case 0x58: /* pop %rax/r8 */
816 case 0x59: /* pop %rcx/r9 */
817 case 0x5a: /* pop %rdx/r10 */
818 case 0x5b: /* pop %rbx/r11 */
819 case 0x5c: /* pop %rsp/r12 */
820 case 0x5d: /* pop %rbp/r13 */
821 case 0x5e: /* pop %rsi/r14 */
822 case 0x5f: /* pop %rdi/r15 */
823 set_int_reg( context, ctx_ptr, *pc - 0x58 + (rex & 1) * 8, (ULONG64 *)context->Rsp );
824 context->Rsp += sizeof(ULONG64);
825 pc++;
826 continue;
827 case 0x81: /* add $nnnn,%rsp */
828 context->Rsp += *(LONG *)(pc + 2);
829 pc += 2 + sizeof(LONG);
830 continue;
831 case 0x83: /* add $n,%rsp */
832 context->Rsp += (signed char)pc[2];
833 pc += 3;
834 continue;
835 case 0x8d:
836 if ((pc[1] >> 6) == 1) /* lea n(reg),%rsp */
838 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + (signed char)pc[2];
839 pc += 3;
841 else /* lea nnnn(reg),%rsp */
843 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + *(LONG *)(pc + 2);
844 pc += 2 + sizeof(LONG);
846 continue;
847 case 0xc2: /* ret $nn */
848 context->Rip = *(ULONG64 *)context->Rsp;
849 context->Rsp += sizeof(ULONG64) + *(WORD *)(pc + 1);
850 return;
851 case 0xc3: /* ret */
852 case 0xf3: /* rep; ret */
853 context->Rip = *(ULONG64 *)context->Rsp;
854 context->Rsp += sizeof(ULONG64);
855 return;
856 case 0xe9: /* jmp nnnn */
857 pc += 5 + *(LONG *)(pc + 1);
858 continue;
859 case 0xeb: /* jmp n */
860 pc += 2 + (signed char)pc[1];
861 continue;
863 return;
867 /**********************************************************************
868 * RtlVirtualUnwind (NTDLL.@)
870 PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
871 RUNTIME_FUNCTION *function, CONTEXT *context,
872 PVOID *data, ULONG64 *frame_ret,
873 KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
875 union handler_data *handler_data;
876 ULONG64 frame, off;
877 struct UNWIND_INFO *info;
878 unsigned int i, prolog_offset;
879 BOOL mach_frame = FALSE;
881 TRACE( "type %lx rip %I64x rsp %I64x\n", type, pc, context->Rsp );
882 if (TRACE_ON(seh)) dump_unwind_info( base, function );
884 frame = *frame_ret = context->Rsp;
885 for (;;)
887 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
888 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
890 if (info->version != 1 && info->version != 2)
892 FIXME( "unknown unwind info version %u at %p\n", info->version, info );
893 return NULL;
896 if (info->frame_reg)
897 frame = get_int_reg( context, info->frame_reg ) - info->frame_offset * 16;
899 /* check if in prolog */
900 if (pc >= base + function->BeginAddress && pc < base + function->BeginAddress + info->prolog)
902 TRACE("inside prolog.\n");
903 prolog_offset = pc - base - function->BeginAddress;
905 else
907 prolog_offset = ~0;
908 /* Since Win10 1809 epilogue does not have a special treatment in case of zero opcode count. */
909 if (info->count && is_inside_epilog( (BYTE *)pc, base, function ))
911 TRACE("inside epilog.\n");
912 interpret_epilog( (BYTE *)pc, context, ctx_ptr );
913 *frame_ret = frame;
914 return NULL;
918 for (i = 0; i < info->count; i += get_opcode_size(info->opcodes[i]))
920 if (prolog_offset < info->opcodes[i].offset) continue; /* skip it */
922 switch (info->opcodes[i].code)
924 case UWOP_PUSH_NONVOL: /* pushq %reg */
925 set_int_reg( context, ctx_ptr, info->opcodes[i].info, (ULONG64 *)context->Rsp );
926 context->Rsp += sizeof(ULONG64);
927 break;
928 case UWOP_ALLOC_LARGE: /* subq $nn,%rsp */
929 if (info->opcodes[i].info) context->Rsp += *(DWORD *)&info->opcodes[i+1];
930 else context->Rsp += *(USHORT *)&info->opcodes[i+1] * 8;
931 break;
932 case UWOP_ALLOC_SMALL: /* subq $n,%rsp */
933 context->Rsp += (info->opcodes[i].info + 1) * 8;
934 break;
935 case UWOP_SET_FPREG: /* leaq nn(%rsp),%framereg */
936 context->Rsp = *frame_ret = frame;
937 break;
938 case UWOP_SAVE_NONVOL: /* movq %reg,n(%rsp) */
939 off = frame + *(USHORT *)&info->opcodes[i+1] * 8;
940 set_int_reg( context, ctx_ptr, info->opcodes[i].info, (ULONG64 *)off );
941 break;
942 case UWOP_SAVE_NONVOL_FAR: /* movq %reg,nn(%rsp) */
943 off = frame + *(DWORD *)&info->opcodes[i+1];
944 set_int_reg( context, ctx_ptr, info->opcodes[i].info, (ULONG64 *)off );
945 break;
946 case UWOP_SAVE_XMM128: /* movaps %xmmreg,n(%rsp) */
947 off = frame + *(USHORT *)&info->opcodes[i+1] * 16;
948 set_float_reg( context, ctx_ptr, info->opcodes[i].info, (M128A *)off );
949 break;
950 case UWOP_SAVE_XMM128_FAR: /* movaps %xmmreg,nn(%rsp) */
951 off = frame + *(DWORD *)&info->opcodes[i+1];
952 set_float_reg( context, ctx_ptr, info->opcodes[i].info, (M128A *)off );
953 break;
954 case UWOP_PUSH_MACHFRAME:
955 if (info->flags & UNW_FLAG_CHAININFO)
957 FIXME("PUSH_MACHFRAME with chained unwind info.\n");
958 break;
960 if (i + get_opcode_size(info->opcodes[i]) < info->count )
962 FIXME("PUSH_MACHFRAME is not the last opcode.\n");
963 break;
966 if (info->opcodes[i].info)
967 context->Rsp += 0x8;
969 context->Rip = *(ULONG64 *)context->Rsp;
970 context->Rsp = *(ULONG64 *)(context->Rsp + 24);
971 mach_frame = TRUE;
972 break;
973 case UWOP_EPILOG:
974 if (info->version == 2)
975 break; /* nothing to do */
976 default:
977 FIXME( "unknown code %u\n", info->opcodes[i].code );
978 break;
982 if (!(info->flags & UNW_FLAG_CHAININFO)) break;
983 function = &handler_data->chain; /* restart with the chained info */
986 if (!mach_frame)
988 /* now pop return address */
989 context->Rip = *(ULONG64 *)context->Rsp;
990 context->Rsp += sizeof(ULONG64);
993 if (!(info->flags & type)) return NULL; /* no matching handler */
994 if (prolog_offset != ~0) return NULL; /* inside prolog */
996 *data = &handler_data->handler + 1;
997 return (char *)base + handler_data->handler;
1000 struct unwind_exception_frame
1002 EXCEPTION_REGISTRATION_RECORD frame;
1003 DISPATCHER_CONTEXT *dispatch;
1006 /**********************************************************************
1007 * unwind_exception_handler
1009 * Handler for exceptions happening while calling an unwind handler.
1011 static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
1012 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
1014 struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame;
1015 DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher;
1017 /* copy the original dispatcher into the current one, except for the TargetIp */
1018 dispatch->ControlPc = unwind_frame->dispatch->ControlPc;
1019 dispatch->ImageBase = unwind_frame->dispatch->ImageBase;
1020 dispatch->FunctionEntry = unwind_frame->dispatch->FunctionEntry;
1021 dispatch->EstablisherFrame = unwind_frame->dispatch->EstablisherFrame;
1022 dispatch->ContextRecord = unwind_frame->dispatch->ContextRecord;
1023 dispatch->LanguageHandler = unwind_frame->dispatch->LanguageHandler;
1024 dispatch->HandlerData = unwind_frame->dispatch->HandlerData;
1025 dispatch->HistoryTable = unwind_frame->dispatch->HistoryTable;
1026 dispatch->ScopeIndex = unwind_frame->dispatch->ScopeIndex;
1027 TRACE( "detected collided unwind\n" );
1028 return ExceptionCollidedUnwind;
1031 /**********************************************************************
1032 * call_unwind_handler
1034 * Call a single unwind handler.
1036 static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
1038 struct unwind_exception_frame frame;
1039 DWORD res;
1041 frame.frame.Handler = unwind_exception_handler;
1042 frame.dispatch = dispatch;
1043 __wine_push_frame( &frame.frame );
1045 TRACE( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
1046 dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
1047 res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
1048 TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res );
1050 __wine_pop_frame( &frame.frame );
1052 switch (res)
1054 case ExceptionContinueSearch:
1055 case ExceptionCollidedUnwind:
1056 break;
1057 default:
1058 raise_status( STATUS_INVALID_DISPOSITION, rec );
1059 break;
1062 return res;
1066 /**********************************************************************
1067 * call_teb_unwind_handler
1069 * Call a single unwind handler from the TEB chain.
1071 static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
1072 EXCEPTION_REGISTRATION_RECORD *teb_frame )
1074 DWORD res;
1076 TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
1077 teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
1078 res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
1079 TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res );
1081 switch (res)
1083 case ExceptionContinueSearch:
1084 case ExceptionCollidedUnwind:
1085 break;
1086 default:
1087 raise_status( STATUS_INVALID_DISPOSITION, rec );
1088 break;
1091 return res;
1095 /**********************************************************************
1096 * call_consolidate_callback
1098 * Wrapper function to call a consolidate callback from a fake frame.
1099 * If the callback executes RtlUnwindEx (like for example done in C++ handlers),
1100 * we have to skip all frames which were already processed. To do that we
1101 * trick the unwinding functions into thinking the call came from the specified
1102 * context. All CFI instructions are either DW_CFA_def_cfa_expression or
1103 * DW_CFA_expression, and the expressions have the following format:
1105 * DW_OP_breg6; sleb128 0x10 | Load %rbp + 0x10
1106 * DW_OP_deref | Get *(%rbp + 0x10) == context
1107 * DW_OP_plus_uconst; uleb128 <OFFSET> | Add offset to get struct member
1108 * [DW_OP_deref] | Dereference, only for CFA
1110 extern void * WINAPI call_consolidate_callback( CONTEXT *context,
1111 void *(CALLBACK *callback)(EXCEPTION_RECORD *),
1112 EXCEPTION_RECORD *rec );
1113 __ASM_GLOBAL_FUNC( call_consolidate_callback,
1114 "pushq %rbp\n\t"
1115 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
1116 __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
1117 "movq %rsp,%rbp\n\t"
1118 __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
1120 /* Setup SEH machine frame. */
1121 "subq $0x28,%rsp\n\t"
1122 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1123 "movq 0xf8(%rcx),%rax\n\t" /* Context->Rip */
1124 "movq %rax,(%rsp)\n\t"
1125 "movq 0x98(%rcx),%rax\n\t" /* context->Rsp */
1126 "movq %rax,0x18(%rsp)\n\t"
1127 __ASM_SEH(".seh_pushframe\n\t")
1128 __ASM_SEH(".seh_endprologue\n\t")
1130 "subq $0x108,%rsp\n\t" /* 10*16 (float regs) + 8*8 (int regs) + 32 (shadow store) + 8 (align). */
1131 __ASM_SEH(".seh_stackalloc 0x108\n\t")
1132 __ASM_CFI(".cfi_adjust_cfa_offset 0x108\n\t")
1134 /* Setup CFI unwind to context. */
1135 "movq %rcx,0x10(%rbp)\n\t"
1136 __ASM_CFI(".cfi_remember_state\n\t")
1137 __ASM_CFI(".cfi_escape 0x0f,0x07,0x76,0x10,0x06,0x23,0x98,0x01,0x06\n\t") /* CFA */
1138 __ASM_CFI(".cfi_escape 0x10,0x03,0x06,0x76,0x10,0x06,0x23,0x90,0x01\n\t") /* %rbx */
1139 __ASM_CFI(".cfi_escape 0x10,0x04,0x06,0x76,0x10,0x06,0x23,0xa8,0x01\n\t") /* %rsi */
1140 __ASM_CFI(".cfi_escape 0x10,0x05,0x06,0x76,0x10,0x06,0x23,0xb0,0x01\n\t") /* %rdi */
1141 __ASM_CFI(".cfi_escape 0x10,0x06,0x06,0x76,0x10,0x06,0x23,0xa0,0x01\n\t") /* %rbp */
1142 __ASM_CFI(".cfi_escape 0x10,0x0c,0x06,0x76,0x10,0x06,0x23,0xd8,0x01\n\t") /* %r12 */
1143 __ASM_CFI(".cfi_escape 0x10,0x0d,0x06,0x76,0x10,0x06,0x23,0xe0,0x01\n\t") /* %r13 */
1144 __ASM_CFI(".cfi_escape 0x10,0x0e,0x06,0x76,0x10,0x06,0x23,0xe8,0x01\n\t") /* %r14 */
1145 __ASM_CFI(".cfi_escape 0x10,0x0f,0x06,0x76,0x10,0x06,0x23,0xf0,0x01\n\t") /* %r15 */
1146 __ASM_CFI(".cfi_escape 0x10,0x10,0x06,0x76,0x10,0x06,0x23,0xf8,0x01\n\t") /* %rip */
1147 __ASM_CFI(".cfi_escape 0x10,0x17,0x06,0x76,0x10,0x06,0x23,0x80,0x04\n\t") /* %xmm6 */
1148 __ASM_CFI(".cfi_escape 0x10,0x18,0x06,0x76,0x10,0x06,0x23,0x90,0x04\n\t") /* %xmm7 */
1149 __ASM_CFI(".cfi_escape 0x10,0x19,0x06,0x76,0x10,0x06,0x23,0xa0,0x04\n\t") /* %xmm8 */
1150 __ASM_CFI(".cfi_escape 0x10,0x1a,0x06,0x76,0x10,0x06,0x23,0xb0,0x04\n\t") /* %xmm9 */
1151 __ASM_CFI(".cfi_escape 0x10,0x1b,0x06,0x76,0x10,0x06,0x23,0xc0,0x04\n\t") /* %xmm10 */
1152 __ASM_CFI(".cfi_escape 0x10,0x1c,0x06,0x76,0x10,0x06,0x23,0xd0,0x04\n\t") /* %xmm11 */
1153 __ASM_CFI(".cfi_escape 0x10,0x1d,0x06,0x76,0x10,0x06,0x23,0xe0,0x04\n\t") /* %xmm12 */
1154 __ASM_CFI(".cfi_escape 0x10,0x1e,0x06,0x76,0x10,0x06,0x23,0xf0,0x04\n\t") /* %xmm13 */
1155 __ASM_CFI(".cfi_escape 0x10,0x1f,0x06,0x76,0x10,0x06,0x23,0x80,0x05\n\t") /* %xmm14 */
1156 __ASM_CFI(".cfi_escape 0x10,0x20,0x06,0x76,0x10,0x06,0x23,0x90,0x05\n\t") /* %xmm15 */
1158 /* Setup SEH unwind registers restore. */
1159 "movq 0xa0(%rcx),%rax\n\t" /* context->Rbp */
1160 "movq %rax,0x100(%rsp)\n\t"
1161 __ASM_SEH(".seh_savereg %rbp, 0x100\n\t")
1162 "movq 0x90(%rcx),%rax\n\t" /* context->Rbx */
1163 "movq %rax,0x20(%rsp)\n\t"
1164 __ASM_SEH(".seh_savereg %rbx, 0x20\n\t")
1165 "movq 0xa8(%rcx),%rax\n\t" /* context->Rsi */
1166 "movq %rax,0x28(%rsp)\n\t"
1167 __ASM_SEH(".seh_savereg %rsi, 0x28\n\t")
1168 "movq 0xb0(%rcx),%rax\n\t" /* context->Rdi */
1169 "movq %rax,0x30(%rsp)\n\t"
1170 __ASM_SEH(".seh_savereg %rdi, 0x30\n\t")
1172 "movq 0xd8(%rcx),%rax\n\t" /* context->R12 */
1173 "movq %rax,0x38(%rsp)\n\t"
1174 __ASM_SEH(".seh_savereg %r12, 0x38\n\t")
1175 "movq 0xe0(%rcx),%rax\n\t" /* context->R13 */
1176 "movq %rax,0x40(%rsp)\n\t"
1177 __ASM_SEH(".seh_savereg %r13, 0x40\n\t")
1178 "movq 0xe8(%rcx),%rax\n\t" /* context->R14 */
1179 "movq %rax,0x48(%rsp)\n\t"
1180 __ASM_SEH(".seh_savereg %r14, 0x48\n\t")
1181 "movq 0xf0(%rcx),%rax\n\t" /* context->R15 */
1182 "movq %rax,0x50(%rsp)\n\t"
1183 __ASM_SEH(".seh_savereg %r15, 0x50\n\t")
1184 "pushq %rsi\n\t"
1185 "pushq %rdi\n\t"
1186 "leaq 0x200(%rcx),%rsi\n\t"
1187 "leaq 0x70(%rsp),%rdi\n\t"
1188 "movq $0x14,%rcx\n\t"
1189 "cld\n\t"
1190 "rep; movsq\n\t"
1191 "popq %rdi\n\t"
1192 "popq %rsi\n\t"
1193 __ASM_SEH(".seh_savexmm %xmm6, 0x60\n\t")
1194 __ASM_SEH(".seh_savexmm %xmm7, 0x70\n\t")
1195 __ASM_SEH(".seh_savexmm %xmm8, 0x80\n\t")
1196 __ASM_SEH(".seh_savexmm %xmm9, 0x90\n\t")
1197 __ASM_SEH(".seh_savexmm %xmm10, 0xa0\n\t")
1198 __ASM_SEH(".seh_savexmm %xmm11, 0xb0\n\t")
1199 __ASM_SEH(".seh_savexmm %xmm12, 0xc0\n\t")
1200 __ASM_SEH(".seh_savexmm %xmm13, 0xd0\n\t")
1201 __ASM_SEH(".seh_savexmm %xmm14, 0xe0\n\t")
1202 __ASM_SEH(".seh_savexmm %xmm15, 0xf0\n\t")
1204 /* call the callback. */
1205 "movq %r8,%rcx\n\t"
1206 "callq *%rdx\n\t"
1207 __ASM_CFI(".cfi_restore_state\n\t")
1208 "nop\n\t" /* Otherwise RtlVirtualUnwind() will think we are inside epilogue and
1209 * interpret / execute the rest of opcodes here instead of unwind through
1210 * machine frame. */
1211 "leaq 0(%rbp),%rsp\n\t"
1212 __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
1213 "popq %rbp\n\t"
1214 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
1215 __ASM_CFI(".cfi_same_value %rbp\n\t")
1216 "ret")
1218 /*******************************************************************
1219 * RtlRestoreContext (NTDLL.@)
1221 void CDECL RtlRestoreContext( CONTEXT *context, EXCEPTION_RECORD *rec )
1223 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
1225 if (rec && rec->ExceptionCode == STATUS_LONGJUMP && rec->NumberParameters >= 1)
1227 struct MSVCRT_JUMP_BUFFER *jmp = (struct MSVCRT_JUMP_BUFFER *)rec->ExceptionInformation[0];
1228 context->Rbx = jmp->Rbx;
1229 context->Rsp = jmp->Rsp;
1230 context->Rbp = jmp->Rbp;
1231 context->Rsi = jmp->Rsi;
1232 context->Rdi = jmp->Rdi;
1233 context->R12 = jmp->R12;
1234 context->R13 = jmp->R13;
1235 context->R14 = jmp->R14;
1236 context->R15 = jmp->R15;
1237 context->Rip = jmp->Rip;
1238 context->Xmm6 = jmp->Xmm6;
1239 context->Xmm7 = jmp->Xmm7;
1240 context->Xmm8 = jmp->Xmm8;
1241 context->Xmm9 = jmp->Xmm9;
1242 context->Xmm10 = jmp->Xmm10;
1243 context->Xmm11 = jmp->Xmm11;
1244 context->Xmm12 = jmp->Xmm12;
1245 context->Xmm13 = jmp->Xmm13;
1246 context->Xmm14 = jmp->Xmm14;
1247 context->Xmm15 = jmp->Xmm15;
1248 context->MxCsr = jmp->MxCsr;
1249 context->FltSave.MxCsr = jmp->MxCsr;
1250 context->FltSave.ControlWord = jmp->FpCsr;
1252 else if (rec && rec->ExceptionCode == STATUS_UNWIND_CONSOLIDATE && rec->NumberParameters >= 1)
1254 PVOID (CALLBACK *consolidate)(EXCEPTION_RECORD *) = (void *)rec->ExceptionInformation[0];
1255 TRACE_(seh)( "calling consolidate callback %p (rec=%p)\n", consolidate, rec );
1256 context->Rip = (ULONG64)call_consolidate_callback( context, consolidate, rec );
1259 /* hack: remove no longer accessible TEB frames */
1260 while ((ULONG64)teb_frame < context->Rsp)
1262 TRACE_(seh)( "removing TEB frame: %p\n", teb_frame );
1263 teb_frame = __wine_pop_frame( teb_frame );
1266 TRACE_(seh)( "returning to %p stack %p\n", (void *)context->Rip, (void *)context->Rsp );
1267 NtContinue( context, FALSE );
1271 /*******************************************************************
1272 * RtlUnwindEx (NTDLL.@)
1274 void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec,
1275 PVOID retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
1277 EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
1278 EXCEPTION_RECORD record;
1279 DISPATCHER_CONTEXT dispatch;
1280 CONTEXT new_context;
1281 NTSTATUS status;
1282 DWORD i;
1284 RtlCaptureContext( context );
1285 new_context = *context;
1287 /* build an exception record, if we do not have one */
1288 if (!rec)
1290 record.ExceptionCode = STATUS_UNWIND;
1291 record.ExceptionFlags = 0;
1292 record.ExceptionRecord = NULL;
1293 record.ExceptionAddress = (void *)context->Rip;
1294 record.NumberParameters = 0;
1295 rec = &record;
1298 rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND);
1300 TRACE( "code=%lx flags=%lx end_frame=%p target_ip=%p rip=%016I64x\n",
1301 rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip, context->Rip );
1302 for (i = 0; i < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); i++)
1303 TRACE( " info[%ld]=%016I64x\n", i, rec->ExceptionInformation[i] );
1304 TRACE(" rax=%016I64x rbx=%016I64x rcx=%016I64x rdx=%016I64x\n",
1305 context->Rax, context->Rbx, context->Rcx, context->Rdx );
1306 TRACE(" rsi=%016I64x rdi=%016I64x rbp=%016I64x rsp=%016I64x\n",
1307 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
1308 TRACE(" r8=%016I64x r9=%016I64x r10=%016I64x r11=%016I64x\n",
1309 context->R8, context->R9, context->R10, context->R11 );
1310 TRACE(" r12=%016I64x r13=%016I64x r14=%016I64x r15=%016I64x\n",
1311 context->R12, context->R13, context->R14, context->R15 );
1313 dispatch.EstablisherFrame = context->Rsp;
1314 dispatch.TargetIp = (ULONG64)target_ip;
1315 dispatch.ContextRecord = context;
1316 dispatch.HistoryTable = table;
1318 for (;;)
1320 status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context );
1321 if (status != STATUS_SUCCESS) raise_status( status, rec );
1323 unwind_done:
1324 if (!dispatch.EstablisherFrame) break;
1326 if ((dispatch.EstablisherFrame & 7) ||
1327 dispatch.EstablisherFrame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
1328 dispatch.EstablisherFrame > (ULONG64)NtCurrentTeb()->Tib.StackBase)
1330 ERR( "invalid frame %p (%p-%p)\n", (void *)dispatch.EstablisherFrame,
1331 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
1332 rec->ExceptionFlags |= EH_STACK_INVALID;
1333 break;
1336 if (dispatch.LanguageHandler)
1338 if (end_frame && (dispatch.EstablisherFrame > (ULONG64)end_frame))
1340 ERR( "invalid end frame %p/%p\n", (void *)dispatch.EstablisherFrame, end_frame );
1341 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1343 if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EH_TARGET_UNWIND;
1344 if (call_unwind_handler( rec, &dispatch ) == ExceptionCollidedUnwind)
1346 ULONG64 frame;
1348 new_context = *dispatch.ContextRecord;
1349 new_context.ContextFlags &= ~0x40;
1350 *context = new_context;
1351 dispatch.ContextRecord = context;
1352 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
1353 dispatch.ControlPc, dispatch.FunctionEntry,
1354 &new_context, NULL, &frame, NULL );
1355 rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
1356 goto unwind_done;
1358 rec->ExceptionFlags &= ~EH_COLLIDED_UNWIND;
1360 else /* hack: call builtin handlers registered in the tib list */
1362 DWORD64 backup_frame = dispatch.EstablisherFrame;
1363 while ((ULONG64)teb_frame < new_context.Rsp && (ULONG64)teb_frame < (ULONG64)end_frame)
1365 TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler );
1366 dispatch.EstablisherFrame = (ULONG64)teb_frame;
1367 if (call_teb_unwind_handler( rec, &dispatch, teb_frame ) == ExceptionCollidedUnwind)
1369 ULONG64 frame;
1371 teb_frame = __wine_pop_frame( teb_frame );
1373 new_context = *dispatch.ContextRecord;
1374 new_context.ContextFlags &= ~0x40;
1375 *context = new_context;
1376 dispatch.ContextRecord = context;
1377 RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
1378 dispatch.ControlPc, dispatch.FunctionEntry,
1379 &new_context, NULL, &frame, NULL );
1380 rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
1381 goto unwind_done;
1383 teb_frame = __wine_pop_frame( teb_frame );
1385 if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Rsp) break;
1386 dispatch.EstablisherFrame = backup_frame;
1389 if (dispatch.EstablisherFrame == (ULONG64)end_frame) break;
1390 *context = new_context;
1393 context->Rax = (ULONG64)retval;
1394 context->Rip = (ULONG64)target_ip;
1395 RtlRestoreContext(context, rec);
1399 /*******************************************************************
1400 * RtlUnwind (NTDLL.@)
1402 void WINAPI RtlUnwind( void *frame, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
1404 CONTEXT context;
1405 RtlUnwindEx( frame, target_ip, rec, retval, &context, NULL );
1409 /*******************************************************************
1410 * _local_unwind (NTDLL.@)
1412 void WINAPI _local_unwind( void *frame, void *target_ip )
1414 CONTEXT context;
1415 RtlUnwindEx( frame, target_ip, NULL, NULL, &context, NULL );
1418 /*******************************************************************
1419 * __C_specific_handler (NTDLL.@)
1421 EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
1422 void *frame,
1423 CONTEXT *context,
1424 struct _DISPATCHER_CONTEXT *dispatch )
1426 SCOPE_TABLE *table = dispatch->HandlerData;
1427 ULONG i;
1429 TRACE_(seh)( "%p %p %p %p\n", rec, frame, context, dispatch );
1430 if (TRACE_ON(seh)) dump_scope_table( dispatch->ImageBase, table );
1432 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
1434 for (i = dispatch->ScopeIndex; i < table->Count; i++)
1436 if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1437 dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1439 PTERMINATION_HANDLER handler;
1441 if (table->ScopeRecord[i].JumpTarget) continue;
1443 if (rec->ExceptionFlags & EH_TARGET_UNWIND &&
1444 dispatch->TargetIp >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1445 dispatch->TargetIp < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1447 break;
1450 handler = (PTERMINATION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
1451 dispatch->ScopeIndex = i+1;
1453 TRACE_(seh)( "calling __finally %p frame %p\n", handler, frame );
1454 handler( TRUE, frame );
1457 return ExceptionContinueSearch;
1460 for (i = dispatch->ScopeIndex; i < table->Count; i++)
1462 if (dispatch->ControlPc >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1463 dispatch->ControlPc < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1465 if (!table->ScopeRecord[i].JumpTarget) continue;
1466 if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
1468 EXCEPTION_POINTERS ptrs;
1469 PEXCEPTION_FILTER filter;
1471 filter = (PEXCEPTION_FILTER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
1472 ptrs.ExceptionRecord = rec;
1473 ptrs.ContextRecord = context;
1474 TRACE_(seh)( "calling filter %p ptrs %p frame %p\n", filter, &ptrs, frame );
1475 switch (filter( &ptrs, frame ))
1477 case EXCEPTION_EXECUTE_HANDLER:
1478 break;
1479 case EXCEPTION_CONTINUE_SEARCH:
1480 continue;
1481 case EXCEPTION_CONTINUE_EXECUTION:
1482 return ExceptionContinueExecution;
1485 TRACE( "unwinding to target %p\n", (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
1486 RtlUnwindEx( frame, (char *)dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
1487 rec, 0, dispatch->ContextRecord, dispatch->HistoryTable );
1490 return ExceptionContinueSearch;
1494 /***********************************************************************
1495 * RtlRaiseException (NTDLL.@)
1497 __ASM_GLOBAL_FUNC( RtlRaiseException,
1498 "sub $0x4f8,%rsp\n\t"
1499 __ASM_SEH(".seh_stackalloc 0x4f8\n\t")
1500 __ASM_SEH(".seh_endprologue\n\t")
1501 __ASM_CFI(".cfi_adjust_cfa_offset 0x4f8\n\t")
1502 "movq %rcx,0x500(%rsp)\n\t"
1503 "leaq 0x20(%rsp),%rcx\n\t"
1504 "call " __ASM_NAME("RtlCaptureContext") "\n\t"
1505 "leaq 0x20(%rsp),%rdx\n\t" /* context pointer */
1506 "leaq 0x500(%rsp),%rax\n\t" /* orig stack pointer */
1507 "movq %rax,0x98(%rdx)\n\t" /* context->Rsp */
1508 "movq (%rax),%rcx\n\t" /* original first parameter */
1509 "movq %rcx,0x80(%rdx)\n\t" /* context->Rcx */
1510 "movq 0x4f8(%rsp),%rax\n\t" /* return address */
1511 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
1512 "movq %rax,0x10(%rcx)\n\t" /* rec->ExceptionAddress */
1513 "movl $1,%r8d\n\t"
1514 "movq %gs:(0x30),%rax\n\t" /* Teb */
1515 "movq 0x60(%rax),%rax\n\t" /* Peb */
1516 "cmpb $0,0x02(%rax)\n\t" /* BeingDebugged */
1517 "jne 1f\n\t"
1518 "call " __ASM_NAME("dispatch_exception") "\n"
1519 "1:\tcall " __ASM_NAME("NtRaiseException") "\n\t"
1520 "movq %rax,%rcx\n\t"
1521 "call " __ASM_NAME("RtlRaiseStatus") /* does not return */ );
1524 static inline ULONG hash_pointers( void **ptrs, ULONG count )
1526 /* Based on MurmurHash2, which is in the public domain */
1527 static const ULONG m = 0x5bd1e995;
1528 static const ULONG r = 24;
1529 ULONG hash = count * sizeof(void*);
1530 for (; count > 0; ptrs++, count--)
1532 ULONG_PTR data = (ULONG_PTR)*ptrs;
1533 ULONG k1 = (ULONG)(data & 0xffffffff), k2 = (ULONG)(data >> 32);
1534 k1 *= m;
1535 k1 = (k1 ^ (k1 >> r)) * m;
1536 k2 *= m;
1537 k2 = (k2 ^ (k2 >> r)) * m;
1538 hash = (((hash * m) ^ k1) * m) ^ k2;
1540 hash = (hash ^ (hash >> 13)) * m;
1541 return hash ^ (hash >> 15);
1545 /*************************************************************************
1546 * RtlCaptureStackBackTrace (NTDLL.@)
1548 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
1550 UNWIND_HISTORY_TABLE table;
1551 DISPATCHER_CONTEXT dispatch;
1552 CONTEXT context;
1553 NTSTATUS status;
1554 ULONG i;
1555 USHORT num_entries = 0;
1557 TRACE( "(%lu, %lu, %p, %p)\n", skip, count, buffer, hash );
1559 RtlCaptureContext( &context );
1560 dispatch.TargetIp = 0;
1561 dispatch.ContextRecord = &context;
1562 dispatch.HistoryTable = &table;
1563 if (hash) *hash = 0;
1564 for (i = 0; i < skip + count; i++)
1566 status = virtual_unwind( UNW_FLAG_NHANDLER, &dispatch, &context );
1567 if (status != STATUS_SUCCESS) return i;
1569 if (!dispatch.EstablisherFrame) break;
1571 if ((dispatch.EstablisherFrame & 7) ||
1572 dispatch.EstablisherFrame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
1573 dispatch.EstablisherFrame > (ULONG64)NtCurrentTeb()->Tib.StackBase)
1575 ERR( "invalid frame %p (%p-%p)\n", (void *)dispatch.EstablisherFrame,
1576 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
1577 break;
1580 if (context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
1582 if (i >= skip) buffer[num_entries++] = (void *)context.Rip;
1584 if (hash && num_entries > 0) *hash = hash_pointers( buffer, num_entries );
1585 TRACE( "captured %hu frames\n", num_entries );
1586 return num_entries;
1590 /***********************************************************************
1591 * signal_start_thread
1593 __ASM_GLOBAL_FUNC( signal_start_thread,
1594 "movq %rcx,%rbx\n\t" /* context */
1595 /* clear the thread stack */
1596 "andq $~0xfff,%rcx\n\t" /* round down to page size */
1597 "leaq -0xf0000(%rcx),%rdi\n\t"
1598 "movq %rdi,%rsp\n\t"
1599 "subq %rdi,%rcx\n\t"
1600 "xorl %eax,%eax\n\t"
1601 "shrq $3,%rcx\n\t"
1602 "rep; stosq\n\t"
1603 /* switch to the initial context */
1604 "leaq -32(%rbx),%rsp\n\t"
1605 "movq %rbx,%rcx\n\t"
1606 "movl $1,%edx\n\t"
1607 "call " __ASM_NAME("NtContinue") )
1610 /**********************************************************************
1611 * DbgBreakPoint (NTDLL.@)
1613 __ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret"
1614 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
1615 "\n\tnop; nop; nop; nop; nop; nop" );
1617 /**********************************************************************
1618 * DbgUserBreakPoint (NTDLL.@)
1620 __ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret"
1621 "\n\tnop; nop; nop; nop; nop; nop; nop; nop"
1622 "\n\tnop; nop; nop; nop; nop; nop" );
1624 #endif /* __x86_64__ */