ntdll: Add appropriate stdcall decorations to assembly functions.
[wine] / dlls / ntdll / signal_x86_64.c
1 /*
2  * x86-64 signal handling routines
3  *
4  * Copyright 1999, 2005 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #ifdef __x86_64__
22
23 #include "config.h"
24 #include "wine/port.h"
25
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
34
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
41
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"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(seh);
54
55 struct _DISPATCHER_CONTEXT;
56
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 );
62
63 typedef struct _DISPATCHER_CONTEXT
64 {
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;
76
77 typedef struct _SCOPE_TABLE
78 {
79     ULONG Count;
80     struct
81     {
82         ULONG BeginAddress;
83         ULONG EndAddress;
84         ULONG HandlerAddress;
85         ULONG JumpTarget;
86     } ScopeRecord[1];
87 } SCOPE_TABLE, *PSCOPE_TABLE;
88
89
90 /***********************************************************************
91  * signal context platform-specific definitions
92  */
93 #ifdef linux
94
95 #include <asm/prctl.h>
96 extern int arch_prctl(int func, void *ptr);
97
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])
113
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))
117
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])
123
124 #define FPU_sig(context)     ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs))
125
126 #endif /* linux */
127
128 #if defined(__NetBSD__)
129 # include <sys/ucontext.h>
130 # include <sys/types.h>
131 # include <signal.h>
132
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])
148
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])
155
156 #define EFL_sig(context)    ((context)->uc_mcontext.__gregs[_REG_RFL])
157
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]))
160
161 #define TRAP_sig(context)   ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
162 #define ERROR_sig(context)  ((context)->uc_mcontext.__gregs[_REG_ERR])
163
164 #define FPU_sig(context)   ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.__fpregs))
165 #endif /* __NetBSD__ */
166
167 enum i386_trap_code
168 {
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 */
189 };
190
191 typedef int (*wine_signal_handler)(unsigned int sig);
192
193 static wine_signal_handler handlers[256];
194
195 /* definitions for unwind tables */
196
197 union handler_data
198 {
199     RUNTIME_FUNCTION chain;
200     ULONG handler;
201 };
202
203 struct opcode
204 {
205     BYTE offset;
206     BYTE code : 4;
207     BYTE info : 4;
208 };
209
210 struct UNWIND_INFO
211 {
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 */
220 };
221
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
231
232 static void dump_unwind_info( ULONG64 base, RUNTIME_FUNCTION *function )
233 {
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" };
237
238     union handler_data *handler_data;
239     struct UNWIND_INFO *info;
240     unsigned int i, count;
241
242     TRACE( "**** func %x-%x\n", function->BeginAddress, function->EndAddress );
243     for (;;)
244     {
245         if (function->UnwindData & 1)
246         {
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;
253         }
254         info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
255
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 );
259
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 );
263
264         for (i = 0; i < info->count; i++)
265         {
266             TRACE( "    0x%x: ", info->opcodes[i].offset );
267             switch (info->opcodes[i].code)
268             {
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)
274                 {
275                     count = *(DWORD *)&info->opcodes[i+1];
276                     i += 2;
277                 }
278                 else
279                 {
280                     count = *(USHORT *)&info->opcodes[i+1] * 8;
281                     i++;
282                 }
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;
319             }
320         }
321
322         handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
323         if (info->flags & UNW_FLAG_CHAININFO)
324         {
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;
330         }
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;
335     }
336 }
337
338 static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table )
339 {
340     unsigned int i;
341
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 );
349 }
350
351 /***********************************************************************
352  *           dispatch_signal
353  */
354 static inline int dispatch_signal(unsigned int sig)
355 {
356     if (handlers[sig] == NULL) return 0;
357     return handlers[sig](sig);
358 }
359
360 /***********************************************************************
361  *           save_context
362  *
363  * Set the register values from a sigcontext.
364  */
365 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
366 {
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))
406     {
407         context->ContextFlags |= CONTEXT_FLOATING_POINT;
408         context->u.FltSave = *FPU_sig(sigcontext);
409     }
410 }
411
412
413 /***********************************************************************
414  *           restore_context
415  *
416  * Build a sigcontext from the register values.
417  */
418 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
419 {
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;
451 }
452
453
454 /***********************************************************************
455  *              RtlCaptureContext (NTDLL.@)
456  */
457 void WINAPI __regs_RtlCaptureContext( CONTEXT *context, CONTEXT *regs )
458 {
459     *context = *regs;
460 }
461 DEFINE_REGS_ENTRYPOINT( RtlCaptureContext, 1 )
462
463
464 /***********************************************************************
465  *           set_cpu_context
466  *
467  * Set the new CPU context.
468  */
469 void set_cpu_context( const CONTEXT *context )
470 {
471     extern void CDECL __wine_restore_regs( const CONTEXT * ) DECLSPEC_NORETURN;
472     __wine_restore_regs( context );
473 }
474
475
476 /***********************************************************************
477  *           copy_context
478  *
479  * Copy a register context according to the flags.
480  */
481 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
482 {
483     flags &= ~CONTEXT_AMD64;  /* get rid of CPU id */
484     if (flags & CONTEXT_CONTROL)
485     {
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;
493     }
494     if (flags & CONTEXT_INTEGER)
495     {
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;
510     }
511     if (flags & CONTEXT_SEGMENTS)
512     {
513         to->SegDs = from->SegDs;
514         to->SegEs = from->SegEs;
515         to->SegFs = from->SegFs;
516         to->SegGs = from->SegGs;
517     }
518     if (flags & CONTEXT_FLOATING_POINT)
519     {
520         to->u.FltSave = from->u.FltSave;
521     }
522     if (flags & CONTEXT_DEBUG_REGISTERS)
523     {
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;
530     }
531 }
532
533
534 /***********************************************************************
535  *           context_to_server
536  *
537  * Convert a register context to the server format.
538  */
539 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
540 {
541     DWORD flags = from->ContextFlags & ~CONTEXT_AMD64;  /* get rid of CPU id */
542
543     memset( to, 0, sizeof(*to) );
544     to->cpu = CPU_x86_64;
545
546     if (flags & CONTEXT_CONTROL)
547     {
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;
556     }
557     if (flags & CONTEXT_INTEGER)
558     {
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;
574     }
575     if (flags & CONTEXT_SEGMENTS)
576     {
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;
582     }
583     if (flags & CONTEXT_FLOATING_POINT)
584     {
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) );
587     }
588     if (flags & CONTEXT_DEBUG_REGISTERS)
589     {
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;
597     }
598     return STATUS_SUCCESS;
599 }
600
601
602 /***********************************************************************
603  *           context_from_server
604  *
605  * Convert a register context from the server format.
606  */
607 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
608 {
609     if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
610
611     to->ContextFlags = CONTEXT_AMD64;
612     if (from->flags & SERVER_CTX_CONTROL)
613     {
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;
622     }
623
624     if (from->flags & SERVER_CTX_INTEGER)
625     {
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;
641     }
642     if (from->flags & SERVER_CTX_SEGMENTS)
643     {
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;
649     }
650     if (from->flags & SERVER_CTX_FLOATING_POINT)
651     {
652         to->ContextFlags |= CONTEXT_FLOATING_POINT;
653         memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
654     }
655     if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
656     {
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;
664     }
665     return STATUS_SUCCESS;
666 }
667
668
669 /**********************************************************************
670  *           find_function_info
671  */
672 static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
673                                              RUNTIME_FUNCTION *func, ULONG size )
674 {
675     int min = 0;
676     int max = size/sizeof(*func) - 1;
677
678     while (min <= max)
679     {
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
684         {
685             func += pos;
686             while (func->UnwindData & 1)  /* follow chained entry */
687                 func = (RUNTIME_FUNCTION *)((char *)module + (func->UnwindData & ~1));
688             return func;
689         }
690     }
691     return NULL;
692 }
693
694 /**********************************************************************
695  *           call_stack_handlers
696  *
697  * Call the stack handlers chain.
698  */
699 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
700 {
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;
710
711     context = *orig_context;
712     for (;;)
713     {
714         /* FIXME: should use the history table to make things faster */
715
716         if (LdrFindEntryForAddress( (void *)context.Rip, &module ))
717         {
718             ERR( "no module found for rip %p, can't dispatch exception\n", (void *)context.Rip );
719             break;
720         }
721         if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
722                                                   IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
723         {
724             ERR( "module %s doesn't contain exception data, can't dispatch exception\n",
725                  debugstr_w(module->BaseDllName.Buffer) );
726             break;
727         }
728         if (!(info = find_function_info( context.Rip, module->BaseAddress, dir, size )))
729         {
730             /* leaf function */
731             context.Rip = *(ULONG64 *)context.Rsp;
732             context.Rsp += sizeof(ULONG64);
733             continue;
734         }
735
736         new_context = context;
737
738         handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)module->BaseAddress, context.Rip,
739                                     info, &new_context, &dispatch.HandlerData, &frame, NULL );
740
741         if ((frame & 7) ||
742             frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
743             frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
744         {
745             ERR( "invalid frame %lx\n", frame );
746             rec->ExceptionFlags |= EH_STACK_INVALID;
747             break;
748         }
749
750         if (handler)
751         {
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 */
761
762             TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
763                    handler, rec, frame, &context, &dispatch );
764
765             switch( handler( rec, frame, &context, &dispatch ))
766             {
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;
777             }
778         }
779         context = new_context;
780     }
781
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;
787 }
788
789
790 /*******************************************************************
791  *              raise_exception
792  *
793  * Implementation of NtRaiseException.
794  */
795 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
796 {
797     NTSTATUS status;
798
799     if (first_chance)
800     {
801         DWORD c;
802
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)
809         {
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] );
818         }
819         else
820         {
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 );
829         }
830         status = send_debug_event( rec, TRUE, context );
831         if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
832             return STATUS_SUCCESS;
833
834         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
835             return STATUS_SUCCESS;
836
837         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
838             return status;
839     }
840
841     /* last chance exception */
842
843     status = send_debug_event( rec, FALSE, context );
844     if (status != DBG_CONTINUE)
845     {
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 );
854     }
855     return STATUS_SUCCESS;
856 }
857
858
859 /**********************************************************************
860  *              segv_handler
861  *
862  * Handler for SIGSEGV and related errors.
863  */
864 static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
865 {
866     EXCEPTION_RECORD rec;
867     CONTEXT context;
868     NTSTATUS status;
869     ucontext_t *ucontext = sigcontext;
870
871     save_context( &context, ucontext );
872
873     rec.ExceptionRecord  = NULL;
874     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
875     rec.ExceptionAddress = (LPVOID)context.Rip;
876     rec.NumberParameters = 0;
877
878     switch(TRAP_sig(ucontext))
879     {
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;
920     }
921
922     status = raise_exception( &rec, &context, TRUE );
923     if (status) raise_status( status, &rec );
924 done:
925     restore_context( &context, ucontext );
926 }
927
928 /**********************************************************************
929  *              trap_handler
930  *
931  * Handler for SIGTRAP.
932  */
933 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
934 {
935     EXCEPTION_RECORD rec;
936     CONTEXT context;
937     NTSTATUS status;
938     ucontext_t *ucontext = sigcontext;
939
940     save_context( &context, ucontext );
941     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
942     rec.ExceptionRecord  = NULL;
943     rec.ExceptionAddress = (LPVOID)context.Rip;
944     rec.NumberParameters = 0;
945
946     switch (siginfo->si_code)
947     {
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;
958     }
959
960     status = raise_exception( &rec, &context, TRUE );
961     if (status) raise_status( status, &rec );
962     restore_context( &context, ucontext );
963 }
964
965 /**********************************************************************
966  *              fpe_handler
967  *
968  * Handler for SIGFPE.
969  */
970 static void fpe_handler( int signal, siginfo_t *siginfo, void *ucontext )
971 {
972     EXCEPTION_RECORD rec;
973     CONTEXT context;
974     NTSTATUS status;
975
976     save_context( &context, ucontext );
977     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
978     rec.ExceptionRecord  = NULL;
979     rec.ExceptionAddress = (LPVOID)context.Rip;
980     rec.NumberParameters = 0;
981
982     switch (siginfo->si_code)
983     {
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;
1009     }
1010
1011     status = raise_exception( &rec, &context, TRUE );
1012     if (status) raise_status( status, &rec );
1013     restore_context( &context, ucontext );
1014 }
1015
1016 /**********************************************************************
1017  *              int_handler
1018  *
1019  * Handler for SIGINT.
1020  */
1021 static void int_handler( int signal, siginfo_t *siginfo, void *ucontext )
1022 {
1023     if (!dispatch_signal(SIGINT))
1024     {
1025         EXCEPTION_RECORD rec;
1026         CONTEXT context;
1027         NTSTATUS status;
1028
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 );
1038     }
1039 }
1040
1041
1042 /**********************************************************************
1043  *              abrt_handler
1044  *
1045  * Handler for SIGABRT.
1046  */
1047 static void abrt_handler( int signal, siginfo_t *siginfo, void *ucontext )
1048 {
1049     EXCEPTION_RECORD rec;
1050     CONTEXT context;
1051     NTSTATUS status;
1052
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 );
1062 }
1063
1064
1065 /**********************************************************************
1066  *              quit_handler
1067  *
1068  * Handler for SIGQUIT.
1069  */
1070 static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
1071 {
1072     abort_thread(0);
1073 }
1074
1075
1076 /**********************************************************************
1077  *              usr1_handler
1078  *
1079  * Handler for SIGUSR1, used to signal a thread that it got suspended.
1080  */
1081 static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
1082 {
1083     CONTEXT context;
1084
1085     save_context( &context, ucontext );
1086     wait_suspend( &context );
1087     restore_context( &context, ucontext );
1088 }
1089
1090
1091 /**********************************************************************
1092  *              get_signal_stack_total_size
1093  *
1094  * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
1095  * Must be a power of two.
1096  */
1097 size_t get_signal_stack_total_size(void)
1098 {
1099     assert( sizeof(TEB) <= 2*getpagesize() );
1100     return 2*getpagesize();  /* this is just for the TEB, we don't need a signal stack */
1101 }
1102
1103
1104 /***********************************************************************
1105  *           __wine_set_signal_handler   (NTDLL.@)
1106  */
1107 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
1108 {
1109     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
1110     if (handlers[sig] != NULL) return -2;
1111     handlers[sig] = wsh;
1112     return 0;
1113 }
1114
1115
1116 /**********************************************************************
1117  *              signal_init_thread
1118  */
1119 void signal_init_thread( TEB *teb )
1120 {
1121 #ifdef __linux__
1122     arch_prctl( ARCH_SET_GS, teb );
1123 #else
1124 # error Please define setting %gs for your architecture
1125 #endif
1126 }
1127
1128 /**********************************************************************
1129  *              signal_init_process
1130  */
1131 void signal_init_process(void)
1132 {
1133     struct sigaction sig_act;
1134
1135     sig_act.sa_mask = server_block_set;
1136     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
1137
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;
1148
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
1155
1156 #ifdef SIGTRAP
1157     sig_act.sa_sigaction = trap_handler;
1158     if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1159 #endif
1160     return;
1161
1162  error:
1163     perror("sigaction");
1164     exit(1);
1165 }
1166
1167
1168 /**********************************************************************
1169  *              RtlLookupFunctionEntry   (NTDLL.@)
1170  */
1171 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWIND_HISTORY_TABLE *table )
1172 {
1173     LDR_MODULE *module;
1174     RUNTIME_FUNCTION *func;
1175     ULONG size;
1176
1177     /* FIXME: should use the history table to make things faster */
1178
1179     if (LdrFindEntryForAddress( (void *)pc, &module ))
1180     {
1181         WARN( "module not found for %lx\n", pc );
1182         return NULL;
1183     }
1184     if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1185                                                IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1186     {
1187         WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1188         return NULL;
1189     }
1190     func = find_function_info( pc, module->BaseAddress, func, size );
1191     if (func) *base = (ULONG64)module->BaseAddress;
1192     return func;
1193 }
1194
1195 static ULONG64 get_int_reg( CONTEXT *context, int reg )
1196 {
1197     return *(&context->Rax + reg);
1198 }
1199
1200 static void set_int_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, ULONG64 val )
1201 {
1202     *(&context->Rax + reg) = val;
1203     if (ctx_ptr) ctx_ptr->u2.IntegerContext[reg] = &context->Rax + reg;
1204 }
1205
1206 static void set_float_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, M128A val )
1207 {
1208     *(&context->u.s.Xmm0 + reg) = val;
1209     if (ctx_ptr) ctx_ptr->u1.FloatingContext[reg] = &context->u.s.Xmm0 + reg;
1210 }
1211
1212 static int get_opcode_size( struct opcode op )
1213 {
1214     switch (op.code)
1215     {
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;
1226     }
1227 }
1228
1229 static BOOL is_inside_epilog( BYTE *pc )
1230 {
1231     /* add or lea must be the first instruction, and it must have a rex.W prefix */
1232     if ((pc[0] & 0xf8) == 0x48)
1233     {
1234         switch (pc[1])
1235         {
1236         case 0x81: /* add $nnnn,%rsp */
1237             if (pc[0] == 0x48 && pc[2] == 0xc4)
1238             {
1239                 pc += 7;
1240                 break;
1241             }
1242             return FALSE;
1243         case 0x83: /* add $n,%rsp */
1244             if (pc[0] == 0x48 && pc[2] == 0xc4)
1245             {
1246                 pc += 4;
1247                 break;
1248             }
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 */
1255             {
1256                 pc += 4;
1257                 break;
1258             }
1259             if ((pc[2] >> 6) == 2)  /* 32-bit offset */
1260             {
1261                 pc += 7;
1262                 break;
1263             }
1264             return FALSE;
1265         }
1266     }
1267
1268     /* now check for various pop instructions */
1269
1270     for (;;)
1271     {
1272         BYTE rex = 0;
1273
1274         if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f;  /* rex prefix */
1275
1276         switch (*pc)
1277         {
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 */
1292         }
1293         return FALSE;
1294     }
1295 }
1296
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 )
1299 {
1300     for (;;)
1301     {
1302         BYTE rex = 0;
1303
1304         if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f;  /* rex prefix */
1305
1306         switch (*pc)
1307         {
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 */
1330             {
1331                 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + (signed char)pc[2];
1332                 pc += 3;
1333             }
1334             else  /* lea nnnn(reg),%rsp */
1335             {
1336                 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + *(LONG *)(pc + 2);
1337                 pc += 2 + sizeof(LONG);
1338             }
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 */
1349         }
1350         return;
1351     }
1352 }
1353
1354 /**********************************************************************
1355  *              RtlVirtualUnwind   (NTDLL.@)
1356  */
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 )
1361 {
1362     union handler_data *handler_data;
1363     ULONG64 frame, off;
1364     struct UNWIND_INFO *info;
1365     unsigned int i, prolog_offset;
1366
1367     TRACE( "type %x rip %lx rsp %lx\n", type, pc, context->Rsp );
1368     if (TRACE_ON(seh)) dump_unwind_info( base, function );
1369
1370     frame = *frame_ret = context->Rsp;
1371     for (;;)
1372     {
1373         info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
1374         handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
1375
1376         if (info->version != 1)
1377         {
1378             FIXME( "unknown unwind info version %u at %p\n", info->version, info );
1379             return NULL;
1380         }
1381
1382         if (info->frame_reg)
1383             frame = get_int_reg( context, info->frame_reg ) - info->frame_offset * 16;
1384
1385         /* check if in prolog */
1386         if (pc >= base + function->BeginAddress && pc < base + function->BeginAddress + info->prolog)
1387         {
1388             prolog_offset = pc - base - function->BeginAddress;
1389         }
1390         else
1391         {
1392             prolog_offset = ~0;
1393             if (is_inside_epilog( (BYTE *)pc ))
1394             {
1395                 interpret_epilog( (BYTE *)pc, context, ctx_ptr );
1396                 *frame_ret = frame;
1397                 return NULL;
1398             }
1399         }
1400
1401         for (i = 0; i < info->count; i += get_opcode_size(info->opcodes[i]))
1402         {
1403             if (prolog_offset < info->opcodes[i].offset) continue; /* skip it */
1404
1405             switch (info->opcodes[i].code)
1406             {
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;
1443             }
1444         }
1445
1446         if (!(info->flags & UNW_FLAG_CHAININFO)) break;
1447         function = &handler_data->chain;  /* restart with the chained info */
1448     }
1449
1450     /* now pop return address */
1451     context->Rip = *(ULONG64 *)context->Rsp;
1452     context->Rsp += sizeof(ULONG64);
1453
1454     if (!(info->flags & type)) return NULL;  /* no matching handler */
1455     if (prolog_offset != ~0) return NULL;  /* inside prolog */
1456
1457     *data = &handler_data->handler + 1;
1458     return (char *)base + handler_data->handler;
1459 }
1460
1461
1462 /*******************************************************************
1463  *              RtlUnwindEx (NTDLL.@)
1464  */
1465 void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1466                          ULONG64 retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
1467 {
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;
1476
1477     /* build an exception record, if we do not have one */
1478     if (!rec)
1479     {
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;
1486     }
1487
1488     rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND);
1489
1490     FIXME( "code=%x flags=%x end_frame=%lx target_ip=%lx\n",
1491            rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip );
1492
1493     frame = context->Rsp;
1494     while (frame != end_frame)
1495     {
1496         /* FIXME: should use the history table to make things faster */
1497
1498         if (LdrFindEntryForAddress( (void *)context->Rip, &module ))
1499         {
1500             ERR( "no module found for rip %p, can't unwind exception\n", (void *)context->Rip );
1501             raise_status( STATUS_BAD_FUNCTION_TABLE, rec );
1502         }
1503         if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1504                                                   IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1505         {
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 );
1509         }
1510         if (!(info = find_function_info( context->Rip, module->BaseAddress, dir, size )))
1511         {
1512             /* leaf function */
1513             context->Rip = *(ULONG64 *)context->Rsp;
1514             context->Rsp += sizeof(ULONG64);
1515             continue;
1516         }
1517
1518         new_context = *context;
1519
1520         handler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, (ULONG64)module->BaseAddress, context->Rip,
1521                                     info, &new_context, &dispatch.HandlerData, &frame, NULL );
1522
1523         if ((frame & 7) ||
1524             frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
1525             frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
1526         {
1527             ERR( "invalid frame %lx\n", frame );
1528             raise_status( STATUS_BAD_STACK, rec );
1529         }
1530
1531         if (end_frame && (frame > end_frame))
1532         {
1533             ERR( "invalid frame %lx/%lx\n", frame, end_frame );
1534             raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1535         }
1536
1537         if (handler)
1538         {
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 */
1548
1549             TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
1550                    handler, rec, frame, context, &dispatch );
1551
1552             switch( handler( rec, frame, context, &dispatch ))
1553             {
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;
1562             }
1563         }
1564         *context = new_context;
1565     }
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 );
1570 }
1571
1572
1573 /*******************************************************************
1574  *              RtlUnwind (NTDLL.@)
1575  */
1576 void WINAPI __regs_RtlUnwind( ULONG64 frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1577                               ULONG64 retval, CONTEXT *context )
1578 {
1579     RtlUnwindEx( frame, target_ip, rec, retval, context, NULL );
1580 }
1581 DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
1582
1583
1584 /*******************************************************************
1585  *              __C_specific_handler (NTDLL.@)
1586  */
1587 EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
1588                                                    ULONG64 frame,
1589                                                    CONTEXT *context,
1590                                                    struct _DISPATCHER_CONTEXT *dispatch )
1591 {
1592     SCOPE_TABLE *table = dispatch->HandlerData;
1593     ULONG i;
1594
1595     TRACE( "%p %lx %p %p\n", rec, frame, context, dispatch );
1596     if (TRACE_ON(seh)) dump_scope_table( dispatch->ImageBase, table );
1597
1598     if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))  /* FIXME */
1599         return ExceptionContinueSearch;
1600
1601     for (i = 0; i < table->Count; i++)
1602     {
1603         if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1604             context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1605         {
1606             if (!table->ScopeRecord[i].JumpTarget) continue;
1607             if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
1608             {
1609                 EXCEPTION_POINTERS ptrs;
1610                 PC_LANGUAGE_EXCEPTION_HANDLER filter;
1611
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 ))
1617                 {
1618                 case EXCEPTION_EXECUTE_HANDLER:
1619                     break;
1620                 case EXCEPTION_CONTINUE_SEARCH:
1621                     continue;
1622                 case EXCEPTION_CONTINUE_EXECUTION:
1623                     return ExceptionContinueExecution;
1624                 }
1625             }
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 );
1629         }
1630     }
1631     return ExceptionContinueSearch;
1632 }
1633
1634
1635 /*******************************************************************
1636  *              NtRaiseException (NTDLL.@)
1637  */
1638 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1639 {
1640     NTSTATUS status = raise_exception( rec, context, first_chance );
1641     if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1642     return status;
1643 }
1644
1645
1646 /***********************************************************************
1647  *              RtlRaiseException (NTDLL.@)
1648  */
1649 void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
1650 {
1651     NTSTATUS status;
1652
1653     rec->ExceptionAddress = (void *)context->Rip;
1654     status = raise_exception( rec, context, TRUE );
1655     if (status != STATUS_SUCCESS) raise_status( status, rec );
1656 }
1657 DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
1658
1659
1660 /**********************************************************************
1661  *              __wine_enter_vm86   (NTDLL.@)
1662  */
1663 void __wine_enter_vm86( CONTEXT *context )
1664 {
1665     MESSAGE("vm86 mode not supported on this platform\n");
1666 }
1667
1668 /**********************************************************************
1669  *              DbgBreakPoint   (NTDLL.@)
1670  */
1671 __ASM_STDCALL_FUNC( DbgBreakPoint, 0, "int $3; ret")
1672
1673 /**********************************************************************
1674  *              DbgUserBreakPoint   (NTDLL.@)
1675  */
1676 __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "int $3; ret")
1677
1678 #endif  /* __x86_64__ */