push e9c4c6cdd0babd7b2cb4288f191bb331b756eaf2
[wine/hacks.git] / dlls / ntdll / signal_x86_64.c
blob1748221e63dbdf535bd9dbb66f11e049a3b68c39
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 "config.h"
24 #include "wine/port.h"
26 #include <assert.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38 #ifdef HAVE_SYS_SIGNAL_H
39 # include <sys/signal.h>
40 #endif
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "ntstatus.h"
45 #define WIN32_NO_STATUS
46 #include "windef.h"
47 #include "winternl.h"
48 #include "wine/library.h"
49 #include "wine/exception.h"
50 #include "ntdll_misc.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(seh);
55 struct _DISPATCHER_CONTEXT;
57 typedef LONG (WINAPI *PC_LANGUAGE_EXCEPTION_HANDLER)( EXCEPTION_POINTERS *ptrs, ULONG64 frame );
58 typedef EXCEPTION_DISPOSITION (WINAPI *PEXCEPTION_ROUTINE)( EXCEPTION_RECORD *rec,
59 ULONG64 frame,
60 CONTEXT *context,
61 struct _DISPATCHER_CONTEXT *dispatch );
63 typedef struct _DISPATCHER_CONTEXT
65 ULONG64 ControlPc;
66 ULONG64 ImageBase;
67 PRUNTIME_FUNCTION FunctionEntry;
68 ULONG64 EstablisherFrame;
69 ULONG64 TargetIp;
70 PCONTEXT ContextRecord;
71 PEXCEPTION_ROUTINE LanguageHandler;
72 PVOID HandlerData;
73 PUNWIND_HISTORY_TABLE HistoryTable;
74 ULONG ScopeIndex;
75 } DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
77 typedef struct _SCOPE_TABLE
79 ULONG Count;
80 struct
82 ULONG BeginAddress;
83 ULONG EndAddress;
84 ULONG HandlerAddress;
85 ULONG JumpTarget;
86 } ScopeRecord[1];
87 } SCOPE_TABLE, *PSCOPE_TABLE;
90 /***********************************************************************
91 * signal context platform-specific definitions
93 #ifdef linux
95 #include <asm/prctl.h>
96 extern int arch_prctl(int func, void *ptr);
98 #define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX])
99 #define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
100 #define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX])
101 #define RDX_sig(context) ((context)->uc_mcontext.gregs[REG_RDX])
102 #define RSI_sig(context) ((context)->uc_mcontext.gregs[REG_RSI])
103 #define RDI_sig(context) ((context)->uc_mcontext.gregs[REG_RDI])
104 #define RBP_sig(context) ((context)->uc_mcontext.gregs[REG_RBP])
105 #define R8_sig(context) ((context)->uc_mcontext.gregs[REG_R8])
106 #define R9_sig(context) ((context)->uc_mcontext.gregs[REG_R9])
107 #define R10_sig(context) ((context)->uc_mcontext.gregs[REG_R10])
108 #define R11_sig(context) ((context)->uc_mcontext.gregs[REG_R11])
109 #define R12_sig(context) ((context)->uc_mcontext.gregs[REG_R12])
110 #define R13_sig(context) ((context)->uc_mcontext.gregs[REG_R13])
111 #define R14_sig(context) ((context)->uc_mcontext.gregs[REG_R14])
112 #define R15_sig(context) ((context)->uc_mcontext.gregs[REG_R15])
114 #define CS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 0))
115 #define GS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 1))
116 #define FS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 2))
118 #define RSP_sig(context) ((context)->uc_mcontext.gregs[REG_RSP])
119 #define RIP_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
120 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
121 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
122 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
124 #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs))
126 #endif /* linux */
128 #if defined(__NetBSD__)
129 # include <sys/ucontext.h>
130 # include <sys/types.h>
131 # include <signal.h>
133 #define RAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RAX])
134 #define RBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RBX])
135 #define RCX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RCX])
136 #define RDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RDX])
137 #define RSI_sig(context) ((context)->uc_mcontext.__gregs[_REG_RSI])
138 #define RDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_RDI])
139 #define RBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_RBP])
140 #define R8_sig(context) ((context)->uc_mcontext.__gregs[_REG_R8])
141 #define R9_sig(context) ((context)->uc_mcontext.__gregs[_REG_R9])
142 #define R10_sig(context) ((context)->uc_mcontext.__gregs[_REG_R10])
143 #define R11_sig(context) ((context)->uc_mcontext.__gregs[_REG_R11])
144 #define R12_sig(context) ((context)->uc_mcontext.__gregs[_REG_R12])
145 #define R13_sig(context) ((context)->uc_mcontext.__gregs[_REG_R13])
146 #define R14_sig(context) ((context)->uc_mcontext.__gregs[_REG_R14])
147 #define R15_sig(context) ((context)->uc_mcontext.__gregs[_REG_R15])
149 #define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS])
150 #define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS])
151 #define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES])
152 #define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS])
153 #define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS])
154 #define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS])
156 #define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_RFL])
158 #define RIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.__gregs[_REG_RIP]))
159 #define RSP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.__gregs[_REG_URSP]))
161 #define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
162 #define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
164 #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.__fpregs))
165 #endif /* __NetBSD__ */
167 enum i386_trap_code
169 TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
170 TRAP_x86_DIVIDE = 0, /* Division by zero exception */
171 TRAP_x86_TRCTRAP = 1, /* Single-step exception */
172 TRAP_x86_NMI = 2, /* NMI interrupt */
173 TRAP_x86_BPTFLT = 3, /* Breakpoint exception */
174 TRAP_x86_OFLOW = 4, /* Overflow exception */
175 TRAP_x86_BOUND = 5, /* Bound range exception */
176 TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */
177 TRAP_x86_DNA = 7, /* Device not available exception */
178 TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */
179 TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */
180 TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */
181 TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */
182 TRAP_x86_STKFLT = 12, /* Stack fault */
183 TRAP_x86_PROTFLT = 13, /* General protection fault */
184 TRAP_x86_PAGEFLT = 14, /* Page fault */
185 TRAP_x86_ARITHTRAP = 16, /* Floating point exception */
186 TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */
187 TRAP_x86_MCHK = 18, /* Machine check exception */
188 TRAP_x86_CACHEFLT = 19 /* Cache flush exception */
191 typedef int (*wine_signal_handler)(unsigned int sig);
193 static wine_signal_handler handlers[256];
195 /* definitions for unwind tables */
197 union handler_data
199 RUNTIME_FUNCTION chain;
200 ULONG handler;
203 struct opcode
205 BYTE offset;
206 BYTE code : 4;
207 BYTE info : 4;
210 struct UNWIND_INFO
212 BYTE version : 3;
213 BYTE flags : 5;
214 BYTE prolog;
215 BYTE count;
216 BYTE frame_reg : 4;
217 BYTE frame_offset : 4;
218 struct opcode opcodes[1]; /* info->count entries */
219 /* followed by handler_data */
222 #define UWOP_PUSH_NONVOL 0
223 #define UWOP_ALLOC_LARGE 1
224 #define UWOP_ALLOC_SMALL 2
225 #define UWOP_SET_FPREG 3
226 #define UWOP_SAVE_NONVOL 4
227 #define UWOP_SAVE_NONVOL_FAR 5
228 #define UWOP_SAVE_XMM128 8
229 #define UWOP_SAVE_XMM128_FAR 9
230 #define UWOP_PUSH_MACHFRAME 10
232 static void dump_unwind_info( ULONG64 base, RUNTIME_FUNCTION *function )
234 static const char * const reg_names[16] =
235 { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
236 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
238 union handler_data *handler_data;
239 struct UNWIND_INFO *info;
240 unsigned int i, count;
242 TRACE( "**** func %x-%x\n", function->BeginAddress, function->EndAddress );
243 for (;;)
245 if (function->UnwindData & 1)
247 RUNTIME_FUNCTION *next = (RUNTIME_FUNCTION *)((char *)base + (function->UnwindData & ~1));
248 TRACE( "unwind info for function %p-%p chained to function %p-%p\n",
249 (char *)base + function->BeginAddress, (char *)base + function->EndAddress,
250 (char *)base + next->BeginAddress, (char *)base + next->EndAddress );
251 function = next;
252 continue;
254 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
256 TRACE( "unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
257 info, info->flags, info->prolog,
258 (char *)base + function->BeginAddress, (char *)base + function->EndAddress );
260 if (info->frame_reg)
261 TRACE( " frame register %s offset 0x%x(%%rsp)\n",
262 reg_names[info->frame_reg], info->frame_offset * 16 );
264 for (i = 0; i < info->count; i++)
266 TRACE( " 0x%x: ", info->opcodes[i].offset );
267 switch (info->opcodes[i].code)
269 case UWOP_PUSH_NONVOL:
270 TRACE( "pushq %%%s\n", reg_names[info->opcodes[i].info] );
271 break;
272 case UWOP_ALLOC_LARGE:
273 if (info->opcodes[i].info)
275 count = *(DWORD *)&info->opcodes[i+1];
276 i += 2;
278 else
280 count = *(USHORT *)&info->opcodes[i+1] * 8;
281 i++;
283 TRACE( "subq $0x%x,%%rsp\n", count );
284 break;
285 case UWOP_ALLOC_SMALL:
286 count = (info->opcodes[i].info + 1) * 8;
287 TRACE( "subq $0x%x,%%rsp\n", count );
288 break;
289 case UWOP_SET_FPREG:
290 TRACE( "leaq 0x%x(%%rsp),%s\n",
291 info->frame_offset * 16, reg_names[info->frame_reg] );
292 break;
293 case UWOP_SAVE_NONVOL:
294 count = *(USHORT *)&info->opcodes[i+1] * 8;
295 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
296 i++;
297 break;
298 case UWOP_SAVE_NONVOL_FAR:
299 count = *(DWORD *)&info->opcodes[i+1];
300 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
301 i += 2;
302 break;
303 case UWOP_SAVE_XMM128:
304 count = *(USHORT *)&info->opcodes[i+1] * 16;
305 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
306 i++;
307 break;
308 case UWOP_SAVE_XMM128_FAR:
309 count = *(DWORD *)&info->opcodes[i+1];
310 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
311 i += 2;
312 break;
313 case UWOP_PUSH_MACHFRAME:
314 TRACE( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
315 break;
316 default:
317 FIXME( "unknown code %u\n", info->opcodes[i].code );
318 break;
322 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
323 if (info->flags & UNW_FLAG_CHAININFO)
325 TRACE( " chained to function %p-%p\n",
326 (char *)base + handler_data->chain.BeginAddress,
327 (char *)base + handler_data->chain.EndAddress );
328 function = &handler_data->chain;
329 continue;
331 if (info->flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
332 TRACE( " handler %p data at %p\n",
333 (char *)base + handler_data->handler, &handler_data->handler + 1 );
334 break;
338 static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table )
340 unsigned int i;
342 TRACE( "scope table at %p\n", table );
343 for (i = 0; i < table->Count; i++)
344 TRACE( " %u: %lx-%lx handler %lx target %lx\n", i,
345 base + table->ScopeRecord[i].BeginAddress,
346 base + table->ScopeRecord[i].EndAddress,
347 base + table->ScopeRecord[i].HandlerAddress,
348 base + table->ScopeRecord[i].JumpTarget );
351 /***********************************************************************
352 * dispatch_signal
354 static inline int dispatch_signal(unsigned int sig)
356 if (handlers[sig] == NULL) return 0;
357 return handlers[sig](sig);
360 /***********************************************************************
361 * save_context
363 * Set the register values from a sigcontext.
365 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
367 context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
368 context->Rax = RAX_sig(sigcontext);
369 context->Rcx = RCX_sig(sigcontext);
370 context->Rdx = RDX_sig(sigcontext);
371 context->Rbx = RBX_sig(sigcontext);
372 context->Rsp = RSP_sig(sigcontext);
373 context->Rbp = RBP_sig(sigcontext);
374 context->Rsi = RSI_sig(sigcontext);
375 context->Rdi = RDI_sig(sigcontext);
376 context->R8 = R8_sig(sigcontext);
377 context->R9 = R9_sig(sigcontext);
378 context->R10 = R10_sig(sigcontext);
379 context->R11 = R11_sig(sigcontext);
380 context->R12 = R12_sig(sigcontext);
381 context->R13 = R13_sig(sigcontext);
382 context->R14 = R14_sig(sigcontext);
383 context->R15 = R15_sig(sigcontext);
384 context->Rip = RIP_sig(sigcontext);
385 context->SegCs = CS_sig(sigcontext);
386 context->SegFs = FS_sig(sigcontext);
387 context->SegGs = GS_sig(sigcontext);
388 context->EFlags = EFL_sig(sigcontext);
389 #ifdef DS_sig
390 context->SegDs = DS_sig(sigcontext);
391 #else
392 __asm__("movw %%ds,%0" : "=m" (context->SegDs));
393 #endif
394 #ifdef ES_sig
395 context->SegEs = ES_sig(sigcontext);
396 #else
397 __asm__("movw %%es,%0" : "=m" (context->SegEs));
398 #endif
399 #ifdef SS_sig
400 context->SegSs = SS_sig(sigcontext);
401 #else
402 __asm__("movw %%ss,%0" : "=m" (context->SegSs));
403 #endif
404 context->MxCsr = 0; /* FIXME */
405 if (FPU_sig(sigcontext))
407 context->ContextFlags |= CONTEXT_FLOATING_POINT;
408 context->u.FltSave = *FPU_sig(sigcontext);
413 /***********************************************************************
414 * restore_context
416 * Build a sigcontext from the register values.
418 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
420 RAX_sig(sigcontext) = context->Rax;
421 RCX_sig(sigcontext) = context->Rcx;
422 RDX_sig(sigcontext) = context->Rdx;
423 RBX_sig(sigcontext) = context->Rbx;
424 RSP_sig(sigcontext) = context->Rsp;
425 RBP_sig(sigcontext) = context->Rbp;
426 RSI_sig(sigcontext) = context->Rsi;
427 RDI_sig(sigcontext) = context->Rdi;
428 R8_sig(sigcontext) = context->R8;
429 R9_sig(sigcontext) = context->R9;
430 R10_sig(sigcontext) = context->R10;
431 R11_sig(sigcontext) = context->R11;
432 R12_sig(sigcontext) = context->R12;
433 R13_sig(sigcontext) = context->R13;
434 R14_sig(sigcontext) = context->R14;
435 R15_sig(sigcontext) = context->R15;
436 RIP_sig(sigcontext) = context->Rip;
437 CS_sig(sigcontext) = context->SegCs;
438 FS_sig(sigcontext) = context->SegFs;
439 GS_sig(sigcontext) = context->SegGs;
440 EFL_sig(sigcontext) = context->EFlags;
441 #ifdef DS_sig
442 DS_sig(sigcontext) = context->SegDs;
443 #endif
444 #ifdef ES_sig
445 ES_sig(sigcontext) = context->SegEs;
446 #endif
447 #ifdef SS_sig
448 SS_sig(sigcontext) = context->SegSs;
449 #endif
450 if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave;
454 /***********************************************************************
455 * RtlCaptureContext (NTDLL.@)
457 void WINAPI __regs_RtlCaptureContext( CONTEXT *context, CONTEXT *regs )
459 *context = *regs;
461 DEFINE_REGS_ENTRYPOINT( RtlCaptureContext, 1 )
464 /***********************************************************************
465 * set_cpu_context
467 * Set the new CPU context.
469 void set_cpu_context( const CONTEXT *context )
471 extern void CDECL __wine_restore_regs( const CONTEXT * ) DECLSPEC_NORETURN;
472 __wine_restore_regs( context );
476 /***********************************************************************
477 * copy_context
479 * Copy a register context according to the flags.
481 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
483 flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
484 if (flags & CONTEXT_CONTROL)
486 to->Rbp = from->Rbp;
487 to->Rip = from->Rip;
488 to->Rsp = from->Rsp;
489 to->SegCs = from->SegCs;
490 to->SegSs = from->SegSs;
491 to->EFlags = from->EFlags;
492 to->MxCsr = from->MxCsr;
494 if (flags & CONTEXT_INTEGER)
496 to->Rax = from->Rax;
497 to->Rcx = from->Rcx;
498 to->Rdx = from->Rdx;
499 to->Rbx = from->Rbx;
500 to->Rsi = from->Rsi;
501 to->Rdi = from->Rdi;
502 to->R8 = from->R8;
503 to->R9 = from->R9;
504 to->R10 = from->R10;
505 to->R11 = from->R11;
506 to->R12 = from->R12;
507 to->R13 = from->R13;
508 to->R14 = from->R14;
509 to->R15 = from->R15;
511 if (flags & CONTEXT_SEGMENTS)
513 to->SegDs = from->SegDs;
514 to->SegEs = from->SegEs;
515 to->SegFs = from->SegFs;
516 to->SegGs = from->SegGs;
518 if (flags & CONTEXT_FLOATING_POINT)
520 to->u.FltSave = from->u.FltSave;
522 if (flags & CONTEXT_DEBUG_REGISTERS)
524 to->Dr0 = from->Dr0;
525 to->Dr1 = from->Dr1;
526 to->Dr2 = from->Dr2;
527 to->Dr3 = from->Dr3;
528 to->Dr6 = from->Dr6;
529 to->Dr7 = from->Dr7;
534 /***********************************************************************
535 * context_to_server
537 * Convert a register context to the server format.
539 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
541 DWORD flags = from->ContextFlags & ~CONTEXT_AMD64; /* get rid of CPU id */
543 memset( to, 0, sizeof(*to) );
544 to->cpu = CPU_x86_64;
546 if (flags & CONTEXT_CONTROL)
548 to->flags |= SERVER_CTX_CONTROL;
549 to->ctl.x86_64_regs.rbp = from->Rbp;
550 to->ctl.x86_64_regs.rip = from->Rip;
551 to->ctl.x86_64_regs.rsp = from->Rsp;
552 to->ctl.x86_64_regs.cs = from->SegCs;
553 to->ctl.x86_64_regs.ss = from->SegSs;
554 to->ctl.x86_64_regs.flags = from->EFlags;
555 to->ctl.x86_64_regs.mxcsr = from->MxCsr;
557 if (flags & CONTEXT_INTEGER)
559 to->flags |= SERVER_CTX_INTEGER;
560 to->integer.x86_64_regs.rax = from->Rax;
561 to->integer.x86_64_regs.rcx = from->Rcx;
562 to->integer.x86_64_regs.rdx = from->Rdx;
563 to->integer.x86_64_regs.rbx = from->Rbx;
564 to->integer.x86_64_regs.rsi = from->Rsi;
565 to->integer.x86_64_regs.rdi = from->Rdi;
566 to->integer.x86_64_regs.r8 = from->R8;
567 to->integer.x86_64_regs.r9 = from->R9;
568 to->integer.x86_64_regs.r10 = from->R10;
569 to->integer.x86_64_regs.r11 = from->R11;
570 to->integer.x86_64_regs.r12 = from->R12;
571 to->integer.x86_64_regs.r13 = from->R13;
572 to->integer.x86_64_regs.r14 = from->R14;
573 to->integer.x86_64_regs.r15 = from->R15;
575 if (flags & CONTEXT_SEGMENTS)
577 to->flags |= SERVER_CTX_SEGMENTS;
578 to->seg.x86_64_regs.ds = from->SegDs;
579 to->seg.x86_64_regs.es = from->SegEs;
580 to->seg.x86_64_regs.fs = from->SegFs;
581 to->seg.x86_64_regs.gs = from->SegGs;
583 if (flags & CONTEXT_FLOATING_POINT)
585 to->flags |= SERVER_CTX_FLOATING_POINT;
586 memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
588 if (flags & CONTEXT_DEBUG_REGISTERS)
590 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
591 to->debug.x86_64_regs.dr0 = from->Dr0;
592 to->debug.x86_64_regs.dr1 = from->Dr1;
593 to->debug.x86_64_regs.dr2 = from->Dr2;
594 to->debug.x86_64_regs.dr3 = from->Dr3;
595 to->debug.x86_64_regs.dr6 = from->Dr6;
596 to->debug.x86_64_regs.dr7 = from->Dr7;
598 return STATUS_SUCCESS;
602 /***********************************************************************
603 * context_from_server
605 * Convert a register context from the server format.
607 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
609 if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
611 to->ContextFlags = CONTEXT_AMD64;
612 if (from->flags & SERVER_CTX_CONTROL)
614 to->ContextFlags |= CONTEXT_CONTROL;
615 to->Rbp = from->ctl.x86_64_regs.rbp;
616 to->Rip = from->ctl.x86_64_regs.rip;
617 to->Rsp = from->ctl.x86_64_regs.rsp;
618 to->SegCs = from->ctl.x86_64_regs.cs;
619 to->SegSs = from->ctl.x86_64_regs.ss;
620 to->EFlags = from->ctl.x86_64_regs.flags;
621 to->MxCsr = from->ctl.x86_64_regs.mxcsr;
624 if (from->flags & SERVER_CTX_INTEGER)
626 to->ContextFlags |= CONTEXT_INTEGER;
627 to->Rax = from->integer.x86_64_regs.rax;
628 to->Rcx = from->integer.x86_64_regs.rcx;
629 to->Rdx = from->integer.x86_64_regs.rdx;
630 to->Rbx = from->integer.x86_64_regs.rbx;
631 to->Rsi = from->integer.x86_64_regs.rsi;
632 to->Rdi = from->integer.x86_64_regs.rdi;
633 to->R8 = from->integer.x86_64_regs.r8;
634 to->R9 = from->integer.x86_64_regs.r9;
635 to->R10 = from->integer.x86_64_regs.r10;
636 to->R11 = from->integer.x86_64_regs.r11;
637 to->R12 = from->integer.x86_64_regs.r12;
638 to->R13 = from->integer.x86_64_regs.r13;
639 to->R14 = from->integer.x86_64_regs.r14;
640 to->R15 = from->integer.x86_64_regs.r15;
642 if (from->flags & SERVER_CTX_SEGMENTS)
644 to->ContextFlags |= CONTEXT_SEGMENTS;
645 to->SegDs = from->seg.x86_64_regs.ds;
646 to->SegEs = from->seg.x86_64_regs.es;
647 to->SegFs = from->seg.x86_64_regs.fs;
648 to->SegGs = from->seg.x86_64_regs.gs;
650 if (from->flags & SERVER_CTX_FLOATING_POINT)
652 to->ContextFlags |= CONTEXT_FLOATING_POINT;
653 memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
655 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
657 to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
658 to->Dr0 = from->debug.x86_64_regs.dr0;
659 to->Dr1 = from->debug.x86_64_regs.dr1;
660 to->Dr2 = from->debug.x86_64_regs.dr2;
661 to->Dr3 = from->debug.x86_64_regs.dr3;
662 to->Dr6 = from->debug.x86_64_regs.dr6;
663 to->Dr7 = from->debug.x86_64_regs.dr7;
665 return STATUS_SUCCESS;
669 /**********************************************************************
670 * find_function_info
672 static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
673 RUNTIME_FUNCTION *func, ULONG size )
675 int min = 0;
676 int max = size/sizeof(*func) - 1;
678 while (min <= max)
680 int pos = (min + max) / 2;
681 if ((char *)pc < (char *)module + func[pos].BeginAddress) max = pos - 1;
682 else if ((char *)pc >= (char *)module + func[pos].EndAddress) min = pos + 1;
683 else
685 func += pos;
686 while (func->UnwindData & 1) /* follow chained entry */
687 func = (RUNTIME_FUNCTION *)((char *)module + (func->UnwindData & ~1));
688 return func;
691 return NULL;
694 /**********************************************************************
695 * call_stack_handlers
697 * Call the stack handlers chain.
699 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
701 EXCEPTION_POINTERS ptrs;
702 UNWIND_HISTORY_TABLE table;
703 ULONG64 frame;
704 RUNTIME_FUNCTION *dir, *info;
705 PEXCEPTION_ROUTINE handler;
706 DISPATCHER_CONTEXT dispatch;
707 CONTEXT context, new_context;
708 LDR_MODULE *module;
709 DWORD size;
711 context = *orig_context;
712 for (;;)
714 /* FIXME: should use the history table to make things faster */
716 if (LdrFindEntryForAddress( (void *)context.Rip, &module ))
718 ERR( "no module found for rip %p, can't dispatch exception\n", (void *)context.Rip );
719 break;
721 if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
722 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
724 ERR( "module %s doesn't contain exception data, can't dispatch exception\n",
725 debugstr_w(module->BaseDllName.Buffer) );
726 break;
728 if (!(info = find_function_info( context.Rip, module->BaseAddress, dir, size )))
730 /* leaf function */
731 context.Rip = *(ULONG64 *)context.Rsp;
732 context.Rsp += sizeof(ULONG64);
733 continue;
736 new_context = context;
738 handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)module->BaseAddress, context.Rip,
739 info, &new_context, &dispatch.HandlerData, &frame, NULL );
741 if ((frame & 7) ||
742 frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
743 frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
745 ERR( "invalid frame %lx\n", frame );
746 rec->ExceptionFlags |= EH_STACK_INVALID;
747 break;
750 if (handler)
752 dispatch.ControlPc = context.Rip;
753 dispatch.ImageBase = (ULONG64)module->BaseAddress;
754 dispatch.FunctionEntry = info;
755 dispatch.EstablisherFrame = frame;
756 dispatch.TargetIp = 0; /* FIXME */
757 dispatch.ContextRecord = &context;
758 dispatch.LanguageHandler = handler;
759 dispatch.HistoryTable = &table;
760 dispatch.ScopeIndex = 0; /* FIXME */
762 TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
763 handler, rec, frame, &context, &dispatch );
765 switch( handler( rec, frame, &context, &dispatch ))
767 case ExceptionContinueExecution:
768 if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
769 *orig_context = context;
770 return STATUS_SUCCESS;
771 case ExceptionContinueSearch:
772 break;
773 case ExceptionNestedException:
774 break;
775 default:
776 return STATUS_INVALID_DISPOSITION;
779 context = new_context;
782 /* hack: call unhandled exception filter directly */
783 ptrs.ExceptionRecord = rec;
784 ptrs.ContextRecord = orig_context;
785 unhandled_exception_filter( &ptrs );
786 return STATUS_UNHANDLED_EXCEPTION;
790 /*******************************************************************
791 * raise_exception
793 * Implementation of NtRaiseException.
795 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
797 NTSTATUS status;
799 if (first_chance)
801 DWORD c;
803 TRACE( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n",
804 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
805 context->Rip, GetCurrentThreadId() );
806 for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
807 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
808 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
810 if (rec->ExceptionInformation[1] >> 16)
811 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
812 rec->ExceptionAddress,
813 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
814 else
815 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
816 rec->ExceptionAddress,
817 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
819 else
821 TRACE(" rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
822 context->Rax, context->Rbx, context->Rcx, context->Rdx );
823 TRACE(" rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
824 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
825 TRACE(" r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
826 context->R8, context->R9, context->R10, context->R11 );
827 TRACE(" r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
828 context->R12, context->R13, context->R14, context->R15 );
830 status = send_debug_event( rec, TRUE, context );
831 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
832 return STATUS_SUCCESS;
834 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
835 return STATUS_SUCCESS;
837 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
838 return status;
841 /* last chance exception */
843 status = send_debug_event( rec, FALSE, context );
844 if (status != DBG_CONTINUE)
846 if (rec->ExceptionFlags & EH_STACK_INVALID)
847 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
848 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
849 ERR("Process attempted to continue execution after noncontinuable exception.\n");
850 else
851 ERR("Unhandled exception code %x flags %x addr %p\n",
852 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
853 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
855 return STATUS_SUCCESS;
859 /**********************************************************************
860 * segv_handler
862 * Handler for SIGSEGV and related errors.
864 static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
866 EXCEPTION_RECORD rec;
867 CONTEXT context;
868 NTSTATUS status;
869 ucontext_t *ucontext = sigcontext;
871 save_context( &context, ucontext );
873 rec.ExceptionRecord = NULL;
874 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
875 rec.ExceptionAddress = (LPVOID)context.Rip;
876 rec.NumberParameters = 0;
878 switch(TRAP_sig(ucontext))
880 case TRAP_x86_OFLOW: /* Overflow exception */
881 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
882 break;
883 case TRAP_x86_BOUND: /* Bound range exception */
884 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
885 break;
886 case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */
887 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
888 break;
889 case TRAP_x86_STKFLT: /* Stack fault */
890 rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
891 break;
892 case TRAP_x86_SEGNPFLT: /* Segment not present exception */
893 case TRAP_x86_PROTFLT: /* General protection fault */
894 case TRAP_x86_UNKNOWN: /* Unknown fault code */
895 rec.ExceptionCode = ERROR_sig(ucontext) ? EXCEPTION_ACCESS_VIOLATION
896 : EXCEPTION_PRIV_INSTRUCTION;
897 break;
898 case TRAP_x86_PAGEFLT: /* Page fault */
899 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
900 rec.NumberParameters = 2;
901 rec.ExceptionInformation[0] = (ERROR_sig(ucontext) & 2) != 0;
902 rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
903 if (!(rec.ExceptionCode = virtual_handle_fault( siginfo->si_addr, rec.ExceptionInformation[0] )))
904 goto done;
905 break;
906 case TRAP_x86_ALIGNFLT: /* Alignment check exception */
907 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
908 break;
909 default:
910 ERR( "Got unexpected trap %ld\n", TRAP_sig(ucontext) );
911 /* fall through */
912 case TRAP_x86_NMI: /* NMI interrupt */
913 case TRAP_x86_DNA: /* Device not available exception */
914 case TRAP_x86_DOUBLEFLT: /* Double fault exception */
915 case TRAP_x86_TSSFLT: /* Invalid TSS exception */
916 case TRAP_x86_MCHK: /* Machine check exception */
917 case TRAP_x86_CACHEFLT: /* Cache flush exception */
918 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
919 break;
922 status = raise_exception( &rec, &context, TRUE );
923 if (status) raise_status( status, &rec );
924 done:
925 restore_context( &context, ucontext );
928 /**********************************************************************
929 * trap_handler
931 * Handler for SIGTRAP.
933 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
935 EXCEPTION_RECORD rec;
936 CONTEXT context;
937 NTSTATUS status;
938 ucontext_t *ucontext = sigcontext;
940 save_context( &context, ucontext );
941 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
942 rec.ExceptionRecord = NULL;
943 rec.ExceptionAddress = (LPVOID)context.Rip;
944 rec.NumberParameters = 0;
946 switch (siginfo->si_code)
948 case TRAP_TRACE: /* Single-step exception */
949 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
950 EFL_sig(ucontext) &= ~0x100; /* clear single-step flag */
951 break;
952 case TRAP_BRKPT: /* Breakpoint exception */
953 rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
954 /* fall through */
955 default:
956 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
957 break;
960 status = raise_exception( &rec, &context, TRUE );
961 if (status) raise_status( status, &rec );
962 restore_context( &context, ucontext );
965 /**********************************************************************
966 * fpe_handler
968 * Handler for SIGFPE.
970 static void fpe_handler( int signal, siginfo_t *siginfo, void *ucontext )
972 EXCEPTION_RECORD rec;
973 CONTEXT context;
974 NTSTATUS status;
976 save_context( &context, ucontext );
977 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
978 rec.ExceptionRecord = NULL;
979 rec.ExceptionAddress = (LPVOID)context.Rip;
980 rec.NumberParameters = 0;
982 switch (siginfo->si_code)
984 case FPE_FLTSUB:
985 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
986 break;
987 case FPE_INTDIV:
988 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
989 break;
990 case FPE_INTOVF:
991 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
992 break;
993 case FPE_FLTDIV:
994 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
995 break;
996 case FPE_FLTOVF:
997 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
998 break;
999 case FPE_FLTUND:
1000 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
1001 break;
1002 case FPE_FLTRES:
1003 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
1004 break;
1005 case FPE_FLTINV:
1006 default:
1007 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1008 break;
1011 status = raise_exception( &rec, &context, TRUE );
1012 if (status) raise_status( status, &rec );
1013 restore_context( &context, ucontext );
1016 /**********************************************************************
1017 * int_handler
1019 * Handler for SIGINT.
1021 static void int_handler( int signal, siginfo_t *siginfo, void *ucontext )
1023 if (!dispatch_signal(SIGINT))
1025 EXCEPTION_RECORD rec;
1026 CONTEXT context;
1027 NTSTATUS status;
1029 save_context( &context, ucontext );
1030 rec.ExceptionCode = CONTROL_C_EXIT;
1031 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
1032 rec.ExceptionRecord = NULL;
1033 rec.ExceptionAddress = (LPVOID)context.Rip;
1034 rec.NumberParameters = 0;
1035 status = raise_exception( &rec, &context, TRUE );
1036 if (status) raise_status( status, &rec );
1037 restore_context( &context, ucontext );
1042 /**********************************************************************
1043 * abrt_handler
1045 * Handler for SIGABRT.
1047 static void abrt_handler( int signal, siginfo_t *siginfo, void *ucontext )
1049 EXCEPTION_RECORD rec;
1050 CONTEXT context;
1051 NTSTATUS status;
1053 save_context( &context, ucontext );
1054 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
1055 rec.ExceptionFlags = EH_NONCONTINUABLE;
1056 rec.ExceptionRecord = NULL;
1057 rec.ExceptionAddress = (LPVOID)context.Rip;
1058 rec.NumberParameters = 0;
1059 status = raise_exception( &rec, &context, TRUE );
1060 if (status) raise_status( status, &rec );
1061 restore_context( &context, ucontext );
1065 /**********************************************************************
1066 * quit_handler
1068 * Handler for SIGQUIT.
1070 static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
1072 abort_thread(0);
1076 /**********************************************************************
1077 * usr1_handler
1079 * Handler for SIGUSR1, used to signal a thread that it got suspended.
1081 static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
1083 CONTEXT context;
1085 save_context( &context, ucontext );
1086 wait_suspend( &context );
1087 restore_context( &context, ucontext );
1091 /**********************************************************************
1092 * get_signal_stack_total_size
1094 * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
1095 * Must be a power of two.
1097 size_t get_signal_stack_total_size(void)
1099 assert( sizeof(TEB) <= 2*getpagesize() );
1100 return 2*getpagesize(); /* this is just for the TEB, we don't need a signal stack */
1104 /***********************************************************************
1105 * __wine_set_signal_handler (NTDLL.@)
1107 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
1109 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
1110 if (handlers[sig] != NULL) return -2;
1111 handlers[sig] = wsh;
1112 return 0;
1116 /**********************************************************************
1117 * signal_init_thread
1119 void signal_init_thread( TEB *teb )
1121 #ifdef __linux__
1122 arch_prctl( ARCH_SET_GS, teb );
1123 #else
1124 # error Please define setting %gs for your architecture
1125 #endif
1128 /**********************************************************************
1129 * signal_init_process
1131 void signal_init_process(void)
1133 struct sigaction sig_act;
1135 sig_act.sa_mask = server_block_set;
1136 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
1138 sig_act.sa_sigaction = int_handler;
1139 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
1140 sig_act.sa_sigaction = fpe_handler;
1141 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
1142 sig_act.sa_sigaction = abrt_handler;
1143 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
1144 sig_act.sa_sigaction = quit_handler;
1145 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
1146 sig_act.sa_sigaction = usr1_handler;
1147 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
1149 sig_act.sa_sigaction = segv_handler;
1150 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
1151 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
1152 #ifdef SIGBUS
1153 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
1154 #endif
1156 #ifdef SIGTRAP
1157 sig_act.sa_sigaction = trap_handler;
1158 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1159 #endif
1160 return;
1162 error:
1163 perror("sigaction");
1164 exit(1);
1168 /**********************************************************************
1169 * RtlLookupFunctionEntry (NTDLL.@)
1171 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWIND_HISTORY_TABLE *table )
1173 LDR_MODULE *module;
1174 RUNTIME_FUNCTION *func;
1175 ULONG size;
1177 /* FIXME: should use the history table to make things faster */
1179 if (LdrFindEntryForAddress( (void *)pc, &module ))
1181 WARN( "module not found for %lx\n", pc );
1182 return NULL;
1184 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1185 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1187 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1188 return NULL;
1190 func = find_function_info( pc, module->BaseAddress, func, size );
1191 if (func) *base = (ULONG64)module->BaseAddress;
1192 return func;
1195 static ULONG64 get_int_reg( CONTEXT *context, int reg )
1197 return *(&context->Rax + reg);
1200 static void set_int_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, ULONG64 val )
1202 *(&context->Rax + reg) = val;
1203 if (ctx_ptr) ctx_ptr->u2.IntegerContext[reg] = &context->Rax + reg;
1206 static void set_float_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, M128A val )
1208 *(&context->u.s.Xmm0 + reg) = val;
1209 if (ctx_ptr) ctx_ptr->u1.FloatingContext[reg] = &context->u.s.Xmm0 + reg;
1212 static int get_opcode_size( struct opcode op )
1214 switch (op.code)
1216 case UWOP_ALLOC_LARGE:
1217 return 2 + (op.info != 0);
1218 case UWOP_SAVE_NONVOL:
1219 case UWOP_SAVE_XMM128:
1220 return 2;
1221 case UWOP_SAVE_NONVOL_FAR:
1222 case UWOP_SAVE_XMM128_FAR:
1223 return 3;
1224 default:
1225 return 1;
1229 static BOOL is_inside_epilog( BYTE *pc )
1231 /* add or lea must be the first instruction, and it must have a rex.W prefix */
1232 if ((pc[0] & 0xf8) == 0x48)
1234 switch (pc[1])
1236 case 0x81: /* add $nnnn,%rsp */
1237 if (pc[0] == 0x48 && pc[2] == 0xc4)
1239 pc += 7;
1240 break;
1242 return FALSE;
1243 case 0x83: /* add $n,%rsp */
1244 if (pc[0] == 0x48 && pc[2] == 0xc4)
1246 pc += 4;
1247 break;
1249 return FALSE;
1250 case 0x8d: /* lea n(reg),%rsp */
1251 if (pc[0] & 0x06) return FALSE; /* rex.RX must be cleared */
1252 if (((pc[2] >> 3) & 7) != 4) return FALSE; /* dest reg mus be %rsp */
1253 if ((pc[2] & 7) == 4) return FALSE; /* no SIB byte allowed */
1254 if ((pc[2] >> 6) == 1) /* 8-bit offset */
1256 pc += 4;
1257 break;
1259 if ((pc[2] >> 6) == 2) /* 32-bit offset */
1261 pc += 7;
1262 break;
1264 return FALSE;
1268 /* now check for various pop instructions */
1270 for (;;)
1272 BYTE rex = 0;
1274 if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f; /* rex prefix */
1276 switch (*pc)
1278 case 0x58: /* pop %rax/%r8 */
1279 case 0x59: /* pop %rcx/%r9 */
1280 case 0x5a: /* pop %rdx/%r10 */
1281 case 0x5b: /* pop %rbx/%r11 */
1282 case 0x5c: /* pop %rsp/%r12 */
1283 case 0x5d: /* pop %rbp/%r13 */
1284 case 0x5e: /* pop %rsi/%r14 */
1285 case 0x5f: /* pop %rdi/%r15 */
1286 pc++;
1287 continue;
1288 case 0xc2: /* ret $nn */
1289 case 0xc3: /* ret */
1290 return TRUE;
1291 /* FIXME: add various jump instructions */
1293 return FALSE;
1297 /* execute a function epilog, which must have been validated with is_inside_epilog() */
1298 static void interpret_epilog( BYTE *pc, CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
1300 for (;;)
1302 BYTE rex = 0;
1304 if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f; /* rex prefix */
1306 switch (*pc)
1308 case 0x58: /* pop %rax/r8 */
1309 case 0x59: /* pop %rcx/r9 */
1310 case 0x5a: /* pop %rdx/r10 */
1311 case 0x5b: /* pop %rbx/r11 */
1312 case 0x5c: /* pop %rsp/r12 */
1313 case 0x5d: /* pop %rbp/r13 */
1314 case 0x5e: /* pop %rsi/r14 */
1315 case 0x5f: /* pop %rdi/r15 */
1316 set_int_reg( context, ctx_ptr, *pc - 0x58 + (rex & 1) * 8, *(ULONG64 *)context->Rsp );
1317 context->Rsp += sizeof(ULONG64);
1318 pc++;
1319 continue;
1320 case 0x81: /* add $nnnn,%rsp */
1321 context->Rsp += *(LONG *)(pc + 2);
1322 pc += 2 + sizeof(LONG);
1323 continue;
1324 case 0x83: /* add $n,%rsp */
1325 context->Rsp += (signed char)pc[2];
1326 pc += 3;
1327 continue;
1328 case 0x8d:
1329 if ((pc[1] >> 6) == 1) /* lea n(reg),%rsp */
1331 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + (signed char)pc[2];
1332 pc += 3;
1334 else /* lea nnnn(reg),%rsp */
1336 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + *(LONG *)(pc + 2);
1337 pc += 2 + sizeof(LONG);
1339 continue;
1340 case 0xc2: /* ret $nn */
1341 context->Rip = *(ULONG64 *)context->Rsp;
1342 context->Rsp += sizeof(ULONG64) + *(WORD *)(pc + 1);
1343 return;
1344 case 0xc3: /* ret */
1345 context->Rip = *(ULONG64 *)context->Rsp;
1346 context->Rsp += sizeof(ULONG64);
1347 return;
1348 /* FIXME: add various jump instructions */
1350 return;
1354 /**********************************************************************
1355 * RtlVirtualUnwind (NTDLL.@)
1357 PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
1358 RUNTIME_FUNCTION *function, CONTEXT *context,
1359 PVOID *data, ULONG64 *frame_ret,
1360 KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
1362 union handler_data *handler_data;
1363 ULONG64 frame, off;
1364 struct UNWIND_INFO *info;
1365 unsigned int i, prolog_offset;
1367 TRACE( "type %x rip %lx rsp %lx\n", type, pc, context->Rsp );
1368 if (TRACE_ON(seh)) dump_unwind_info( base, function );
1370 frame = *frame_ret = context->Rsp;
1371 for (;;)
1373 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
1374 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
1376 if (info->version != 1)
1378 FIXME( "unknown unwind info version %u at %p\n", info->version, info );
1379 return NULL;
1382 if (info->frame_reg)
1383 frame = get_int_reg( context, info->frame_reg ) - info->frame_offset * 16;
1385 /* check if in prolog */
1386 if (pc >= base + function->BeginAddress && pc < base + function->BeginAddress + info->prolog)
1388 prolog_offset = pc - base - function->BeginAddress;
1390 else
1392 prolog_offset = ~0;
1393 if (is_inside_epilog( (BYTE *)pc ))
1395 interpret_epilog( (BYTE *)pc, context, ctx_ptr );
1396 *frame_ret = frame;
1397 return NULL;
1401 for (i = 0; i < info->count; i += get_opcode_size(info->opcodes[i]))
1403 if (prolog_offset < info->opcodes[i].offset) continue; /* skip it */
1405 switch (info->opcodes[i].code)
1407 case UWOP_PUSH_NONVOL: /* pushq %reg */
1408 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)context->Rsp );
1409 context->Rsp += sizeof(ULONG64);
1410 break;
1411 case UWOP_ALLOC_LARGE: /* subq $nn,%rsp */
1412 if (info->opcodes[i].info) context->Rsp += *(DWORD *)&info->opcodes[i+1];
1413 else context->Rsp += *(USHORT *)&info->opcodes[i+1] * 8;
1414 break;
1415 case UWOP_ALLOC_SMALL: /* subq $n,%rsp */
1416 context->Rsp += (info->opcodes[i].info + 1) * 8;
1417 break;
1418 case UWOP_SET_FPREG: /* leaq nn(%rsp),%framereg */
1419 context->Rsp = *frame_ret = frame;
1420 break;
1421 case UWOP_SAVE_NONVOL: /* movq %reg,n(%rsp) */
1422 off = frame + *(USHORT *)&info->opcodes[i+1] * 8;
1423 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)off );
1424 break;
1425 case UWOP_SAVE_NONVOL_FAR: /* movq %reg,nn(%rsp) */
1426 off = frame + *(DWORD *)&info->opcodes[i+1];
1427 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)off );
1428 break;
1429 case UWOP_SAVE_XMM128: /* movaps %xmmreg,n(%rsp) */
1430 off = frame + *(USHORT *)&info->opcodes[i+1] * 16;
1431 set_float_reg( context, ctx_ptr, info->opcodes[i].info, *(M128A *)off );
1432 break;
1433 case UWOP_SAVE_XMM128_FAR: /* movaps %xmmreg,nn(%rsp) */
1434 off = frame + *(DWORD *)&info->opcodes[i+1];
1435 set_float_reg( context, ctx_ptr, info->opcodes[i].info, *(M128A *)off );
1436 break;
1437 case UWOP_PUSH_MACHFRAME:
1438 FIXME( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
1439 break;
1440 default:
1441 FIXME( "unknown code %u\n", info->opcodes[i].code );
1442 break;
1446 if (!(info->flags & UNW_FLAG_CHAININFO)) break;
1447 function = &handler_data->chain; /* restart with the chained info */
1450 /* now pop return address */
1451 context->Rip = *(ULONG64 *)context->Rsp;
1452 context->Rsp += sizeof(ULONG64);
1454 if (!(info->flags & type)) return NULL; /* no matching handler */
1455 if (prolog_offset != ~0) return NULL; /* inside prolog */
1457 *data = &handler_data->handler + 1;
1458 return (char *)base + handler_data->handler;
1462 /*******************************************************************
1463 * RtlUnwindEx (NTDLL.@)
1465 void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1466 ULONG64 retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
1468 EXCEPTION_RECORD record;
1469 ULONG64 frame;
1470 RUNTIME_FUNCTION *dir, *info;
1471 PEXCEPTION_ROUTINE handler;
1472 DISPATCHER_CONTEXT dispatch;
1473 CONTEXT new_context;
1474 LDR_MODULE *module;
1475 DWORD size;
1477 /* build an exception record, if we do not have one */
1478 if (!rec)
1480 record.ExceptionCode = STATUS_UNWIND;
1481 record.ExceptionFlags = 0;
1482 record.ExceptionRecord = NULL;
1483 record.ExceptionAddress = (void *)context->Rip;
1484 record.NumberParameters = 0;
1485 rec = &record;
1488 rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND);
1490 FIXME( "code=%x flags=%x end_frame=%lx target_ip=%lx\n",
1491 rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip );
1493 frame = context->Rsp;
1494 while (frame != end_frame)
1496 /* FIXME: should use the history table to make things faster */
1498 if (LdrFindEntryForAddress( (void *)context->Rip, &module ))
1500 ERR( "no module found for rip %p, can't unwind exception\n", (void *)context->Rip );
1501 raise_status( STATUS_BAD_FUNCTION_TABLE, rec );
1503 if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1504 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1506 ERR( "module %s doesn't contain exception data, can't unwind exception\n",
1507 debugstr_w(module->BaseDllName.Buffer) );
1508 raise_status( STATUS_BAD_FUNCTION_TABLE, rec );
1510 if (!(info = find_function_info( context->Rip, module->BaseAddress, dir, size )))
1512 /* leaf function */
1513 context->Rip = *(ULONG64 *)context->Rsp;
1514 context->Rsp += sizeof(ULONG64);
1515 continue;
1518 new_context = *context;
1520 handler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, (ULONG64)module->BaseAddress, context->Rip,
1521 info, &new_context, &dispatch.HandlerData, &frame, NULL );
1523 if ((frame & 7) ||
1524 frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
1525 frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
1527 ERR( "invalid frame %lx\n", frame );
1528 raise_status( STATUS_BAD_STACK, rec );
1531 if (end_frame && (frame > end_frame))
1533 ERR( "invalid frame %lx/%lx\n", frame, end_frame );
1534 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1537 if (handler)
1539 dispatch.ControlPc = context->Rip;
1540 dispatch.ImageBase = (ULONG64)module->BaseAddress;
1541 dispatch.FunctionEntry = info;
1542 dispatch.EstablisherFrame = frame;
1543 dispatch.TargetIp = target_ip;
1544 dispatch.ContextRecord = context;
1545 dispatch.LanguageHandler = handler;
1546 dispatch.HistoryTable = table;
1547 dispatch.ScopeIndex = 0; /* FIXME */
1549 TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
1550 handler, rec, frame, context, &dispatch );
1552 switch( handler( rec, frame, context, &dispatch ))
1554 case ExceptionContinueSearch:
1555 break;
1556 case ExceptionCollidedUnwind:
1557 FIXME( "ExceptionCollidedUnwind not supported yet\n" );
1558 break;
1559 default:
1560 raise_status( STATUS_INVALID_DISPOSITION, rec );
1561 break;
1564 *context = new_context;
1566 context->Rax = retval;
1567 context->Rip = target_ip;
1568 TRACE( "returning to %lx stack %lx\n", context->Rip, context->Rsp );
1569 set_cpu_context( context );
1573 /*******************************************************************
1574 * RtlUnwind (NTDLL.@)
1576 void WINAPI __regs_RtlUnwind( ULONG64 frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1577 ULONG64 retval, CONTEXT *context )
1579 RtlUnwindEx( frame, target_ip, rec, retval, context, NULL );
1581 DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
1584 /*******************************************************************
1585 * __C_specific_handler (NTDLL.@)
1587 EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
1588 ULONG64 frame,
1589 CONTEXT *context,
1590 struct _DISPATCHER_CONTEXT *dispatch )
1592 SCOPE_TABLE *table = dispatch->HandlerData;
1593 ULONG i;
1595 TRACE( "%p %lx %p %p\n", rec, frame, context, dispatch );
1596 if (TRACE_ON(seh)) dump_scope_table( dispatch->ImageBase, table );
1598 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) /* FIXME */
1599 return ExceptionContinueSearch;
1601 for (i = 0; i < table->Count; i++)
1603 if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1604 context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1606 if (!table->ScopeRecord[i].JumpTarget) continue;
1607 if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
1609 EXCEPTION_POINTERS ptrs;
1610 PC_LANGUAGE_EXCEPTION_HANDLER filter;
1612 filter = (PC_LANGUAGE_EXCEPTION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
1613 ptrs.ExceptionRecord = rec;
1614 ptrs.ContextRecord = context;
1615 TRACE( "calling filter %p ptrs %p frame %lx\n", filter, &ptrs, frame );
1616 switch (filter( &ptrs, frame ))
1618 case EXCEPTION_EXECUTE_HANDLER:
1619 break;
1620 case EXCEPTION_CONTINUE_SEARCH:
1621 continue;
1622 case EXCEPTION_CONTINUE_EXECUTION:
1623 return ExceptionContinueExecution;
1626 TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
1627 RtlUnwindEx( frame, dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
1628 rec, 0, context, dispatch->HistoryTable );
1631 return ExceptionContinueSearch;
1635 /*******************************************************************
1636 * NtRaiseException (NTDLL.@)
1638 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1640 NTSTATUS status = raise_exception( rec, context, first_chance );
1641 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1642 return status;
1646 /***********************************************************************
1647 * RtlRaiseException (NTDLL.@)
1649 void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
1651 NTSTATUS status;
1653 rec->ExceptionAddress = (void *)context->Rip;
1654 status = raise_exception( rec, context, TRUE );
1655 if (status != STATUS_SUCCESS) raise_status( status, rec );
1657 DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
1660 /**********************************************************************
1661 * __wine_enter_vm86 (NTDLL.@)
1663 void __wine_enter_vm86( CONTEXT *context )
1665 MESSAGE("vm86 mode not supported on this platform\n");
1668 /**********************************************************************
1669 * DbgBreakPoint (NTDLL.@)
1671 __ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret")
1673 /**********************************************************************
1674 * DbgUserBreakPoint (NTDLL.@)
1676 __ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret")
1678 #endif /* __x86_64__ */