wined3d: Add modifier support to tex and friends.
[wine/wine-gecko.git] / dlls / ntdll / signal_x86_64.c
blob5a207aa2088d6a1659c2f2215fdb605233c73d3c
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 static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
192 static size_t signal_stack_size;
194 typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
195 typedef int (*wine_signal_handler)(unsigned int sig);
197 static wine_signal_handler handlers[256];
199 /* definitions for unwind tables */
201 union handler_data
203 RUNTIME_FUNCTION chain;
204 ULONG handler;
207 struct opcode
209 BYTE offset;
210 BYTE code : 4;
211 BYTE info : 4;
214 struct UNWIND_INFO
216 BYTE version : 3;
217 BYTE flags : 5;
218 BYTE prolog;
219 BYTE count;
220 BYTE frame_reg : 4;
221 BYTE frame_offset : 4;
222 struct opcode opcodes[1]; /* info->count entries */
223 /* followed by handler_data */
226 #define UWOP_PUSH_NONVOL 0
227 #define UWOP_ALLOC_LARGE 1
228 #define UWOP_ALLOC_SMALL 2
229 #define UWOP_SET_FPREG 3
230 #define UWOP_SAVE_NONVOL 4
231 #define UWOP_SAVE_NONVOL_FAR 5
232 #define UWOP_SAVE_XMM128 8
233 #define UWOP_SAVE_XMM128_FAR 9
234 #define UWOP_PUSH_MACHFRAME 10
236 static void dump_unwind_info( ULONG64 base, RUNTIME_FUNCTION *function )
238 static const char * const reg_names[16] =
239 { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
240 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
242 union handler_data *handler_data;
243 struct UNWIND_INFO *info;
244 unsigned int i, count;
246 TRACE( "**** func %x-%x\n", function->BeginAddress, function->EndAddress );
247 for (;;)
249 if (function->UnwindData & 1)
251 RUNTIME_FUNCTION *next = (RUNTIME_FUNCTION *)((char *)base + (function->UnwindData & ~1));
252 TRACE( "unwind info for function %p-%p chained to function %p-%p\n",
253 (char *)base + function->BeginAddress, (char *)base + function->EndAddress,
254 (char *)base + next->BeginAddress, (char *)base + next->EndAddress );
255 function = next;
256 continue;
258 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
260 TRACE( "unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
261 info, info->flags, info->prolog,
262 (char *)base + function->BeginAddress, (char *)base + function->EndAddress );
264 if (info->frame_reg)
265 TRACE( " frame register %s offset 0x%x(%%rsp)\n",
266 reg_names[info->frame_reg], info->frame_offset * 16 );
268 for (i = 0; i < info->count; i++)
270 TRACE( " 0x%x: ", info->opcodes[i].offset );
271 switch (info->opcodes[i].code)
273 case UWOP_PUSH_NONVOL:
274 TRACE( "pushq %%%s\n", reg_names[info->opcodes[i].info] );
275 break;
276 case UWOP_ALLOC_LARGE:
277 if (info->opcodes[i].info)
279 count = *(DWORD *)&info->opcodes[i+1];
280 i += 2;
282 else
284 count = *(USHORT *)&info->opcodes[i+1] * 8;
285 i++;
287 TRACE( "subq $0x%x,%%rsp\n", count );
288 break;
289 case UWOP_ALLOC_SMALL:
290 count = (info->opcodes[i].info + 1) * 8;
291 TRACE( "subq $0x%x,%%rsp\n", count );
292 break;
293 case UWOP_SET_FPREG:
294 TRACE( "leaq 0x%x(%%rsp),%s\n",
295 info->frame_offset * 16, reg_names[info->frame_reg] );
296 break;
297 case UWOP_SAVE_NONVOL:
298 count = *(USHORT *)&info->opcodes[i+1] * 8;
299 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
300 i++;
301 break;
302 case UWOP_SAVE_NONVOL_FAR:
303 count = *(DWORD *)&info->opcodes[i+1];
304 TRACE( "movq %%%s,0x%x(%%rsp)\n", reg_names[info->opcodes[i].info], count );
305 i += 2;
306 break;
307 case UWOP_SAVE_XMM128:
308 count = *(USHORT *)&info->opcodes[i+1] * 16;
309 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
310 i++;
311 break;
312 case UWOP_SAVE_XMM128_FAR:
313 count = *(DWORD *)&info->opcodes[i+1];
314 TRACE( "movaps %%xmm%u,0x%x(%%rsp)\n", info->opcodes[i].info, count );
315 i += 2;
316 break;
317 case UWOP_PUSH_MACHFRAME:
318 TRACE( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
319 break;
320 default:
321 FIXME( "unknown code %u\n", info->opcodes[i].code );
322 break;
326 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
327 if (info->flags & UNW_FLAG_CHAININFO)
329 TRACE( " chained to function %p-%p\n",
330 (char *)base + handler_data->chain.BeginAddress,
331 (char *)base + handler_data->chain.EndAddress );
332 function = &handler_data->chain;
333 continue;
335 if (info->flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
336 TRACE( " handler %p data at %p\n",
337 (char *)base + handler_data->handler, &handler_data->handler + 1 );
338 break;
342 static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table )
344 unsigned int i;
346 TRACE( "scope table at %p\n", table );
347 for (i = 0; i < table->Count; i++)
348 TRACE( " %u: %lx-%lx handler %lx target %lx\n", i,
349 base + table->ScopeRecord[i].BeginAddress,
350 base + table->ScopeRecord[i].EndAddress,
351 base + table->ScopeRecord[i].HandlerAddress,
352 base + table->ScopeRecord[i].JumpTarget );
355 /***********************************************************************
356 * dispatch_signal
358 static inline int dispatch_signal(unsigned int sig)
360 if (handlers[sig] == NULL) return 0;
361 return handlers[sig](sig);
364 /***********************************************************************
365 * get_signal_stack
367 * Get the base of the signal stack for the current thread.
369 static inline void *get_signal_stack(void)
371 return (char *)NtCurrentTeb() + teb_size;
374 /***********************************************************************
375 * save_context
377 * Set the register values from a sigcontext.
379 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
381 context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
382 context->Rax = RAX_sig(sigcontext);
383 context->Rcx = RCX_sig(sigcontext);
384 context->Rdx = RDX_sig(sigcontext);
385 context->Rbx = RBX_sig(sigcontext);
386 context->Rsp = RSP_sig(sigcontext);
387 context->Rbp = RBP_sig(sigcontext);
388 context->Rsi = RSI_sig(sigcontext);
389 context->Rdi = RDI_sig(sigcontext);
390 context->R8 = R8_sig(sigcontext);
391 context->R9 = R9_sig(sigcontext);
392 context->R10 = R10_sig(sigcontext);
393 context->R11 = R11_sig(sigcontext);
394 context->R12 = R12_sig(sigcontext);
395 context->R13 = R13_sig(sigcontext);
396 context->R14 = R14_sig(sigcontext);
397 context->R15 = R15_sig(sigcontext);
398 context->Rip = RIP_sig(sigcontext);
399 context->SegCs = CS_sig(sigcontext);
400 context->SegFs = FS_sig(sigcontext);
401 context->SegGs = GS_sig(sigcontext);
402 context->EFlags = EFL_sig(sigcontext);
403 #ifdef DS_sig
404 context->SegDs = DS_sig(sigcontext);
405 #else
406 __asm__("movw %%ds,%0" : "=m" (context->SegDs));
407 #endif
408 #ifdef ES_sig
409 context->SegEs = ES_sig(sigcontext);
410 #else
411 __asm__("movw %%es,%0" : "=m" (context->SegEs));
412 #endif
413 #ifdef SS_sig
414 context->SegSs = SS_sig(sigcontext);
415 #else
416 __asm__("movw %%ss,%0" : "=m" (context->SegSs));
417 #endif
418 context->MxCsr = 0; /* FIXME */
419 if (FPU_sig(sigcontext))
421 context->ContextFlags |= CONTEXT_FLOATING_POINT;
422 context->u.FltSave = *FPU_sig(sigcontext);
427 /***********************************************************************
428 * restore_context
430 * Build a sigcontext from the register values.
432 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
434 RAX_sig(sigcontext) = context->Rax;
435 RCX_sig(sigcontext) = context->Rcx;
436 RDX_sig(sigcontext) = context->Rdx;
437 RBX_sig(sigcontext) = context->Rbx;
438 RSP_sig(sigcontext) = context->Rsp;
439 RBP_sig(sigcontext) = context->Rbp;
440 RSI_sig(sigcontext) = context->Rsi;
441 RDI_sig(sigcontext) = context->Rdi;
442 R8_sig(sigcontext) = context->R8;
443 R9_sig(sigcontext) = context->R9;
444 R10_sig(sigcontext) = context->R10;
445 R11_sig(sigcontext) = context->R11;
446 R12_sig(sigcontext) = context->R12;
447 R13_sig(sigcontext) = context->R13;
448 R14_sig(sigcontext) = context->R14;
449 R15_sig(sigcontext) = context->R15;
450 RIP_sig(sigcontext) = context->Rip;
451 CS_sig(sigcontext) = context->SegCs;
452 FS_sig(sigcontext) = context->SegFs;
453 GS_sig(sigcontext) = context->SegGs;
454 EFL_sig(sigcontext) = context->EFlags;
455 #ifdef DS_sig
456 DS_sig(sigcontext) = context->SegDs;
457 #endif
458 #ifdef ES_sig
459 ES_sig(sigcontext) = context->SegEs;
460 #endif
461 #ifdef SS_sig
462 SS_sig(sigcontext) = context->SegSs;
463 #endif
464 if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave;
468 /***********************************************************************
469 * RtlCaptureContext (NTDLL.@)
471 void WINAPI __regs_RtlCaptureContext( CONTEXT *context, CONTEXT *regs )
473 *context = *regs;
475 DEFINE_REGS_ENTRYPOINT( RtlCaptureContext, 1 )
478 /***********************************************************************
479 * set_cpu_context
481 * Set the new CPU context.
483 void set_cpu_context( const CONTEXT *context )
485 extern void CDECL __wine_restore_regs( const CONTEXT * ) DECLSPEC_NORETURN;
486 __wine_restore_regs( context );
490 /***********************************************************************
491 * copy_context
493 * Copy a register context according to the flags.
495 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
497 flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
498 if (flags & CONTEXT_CONTROL)
500 to->Rbp = from->Rbp;
501 to->Rip = from->Rip;
502 to->Rsp = from->Rsp;
503 to->SegCs = from->SegCs;
504 to->SegSs = from->SegSs;
505 to->EFlags = from->EFlags;
506 to->MxCsr = from->MxCsr;
508 if (flags & CONTEXT_INTEGER)
510 to->Rax = from->Rax;
511 to->Rcx = from->Rcx;
512 to->Rdx = from->Rdx;
513 to->Rbx = from->Rbx;
514 to->Rsi = from->Rsi;
515 to->Rdi = from->Rdi;
516 to->R8 = from->R8;
517 to->R9 = from->R9;
518 to->R10 = from->R10;
519 to->R11 = from->R11;
520 to->R12 = from->R12;
521 to->R13 = from->R13;
522 to->R14 = from->R14;
523 to->R15 = from->R15;
525 if (flags & CONTEXT_SEGMENTS)
527 to->SegDs = from->SegDs;
528 to->SegEs = from->SegEs;
529 to->SegFs = from->SegFs;
530 to->SegGs = from->SegGs;
532 if (flags & CONTEXT_FLOATING_POINT)
534 to->u.FltSave = from->u.FltSave;
536 if (flags & CONTEXT_DEBUG_REGISTERS)
538 to->Dr0 = from->Dr0;
539 to->Dr1 = from->Dr1;
540 to->Dr2 = from->Dr2;
541 to->Dr3 = from->Dr3;
542 to->Dr6 = from->Dr6;
543 to->Dr7 = from->Dr7;
548 /***********************************************************************
549 * context_to_server
551 * Convert a register context to the server format.
553 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
555 DWORD flags = from->ContextFlags & ~CONTEXT_AMD64; /* get rid of CPU id */
557 memset( to, 0, sizeof(*to) );
558 to->cpu = CPU_x86_64;
560 if (flags & CONTEXT_CONTROL)
562 to->flags |= SERVER_CTX_CONTROL;
563 to->ctl.x86_64_regs.rbp = from->Rbp;
564 to->ctl.x86_64_regs.rip = from->Rip;
565 to->ctl.x86_64_regs.rsp = from->Rsp;
566 to->ctl.x86_64_regs.cs = from->SegCs;
567 to->ctl.x86_64_regs.ss = from->SegSs;
568 to->ctl.x86_64_regs.flags = from->EFlags;
569 to->ctl.x86_64_regs.mxcsr = from->MxCsr;
571 if (flags & CONTEXT_INTEGER)
573 to->flags |= SERVER_CTX_INTEGER;
574 to->integer.x86_64_regs.rax = from->Rax;
575 to->integer.x86_64_regs.rcx = from->Rcx;
576 to->integer.x86_64_regs.rdx = from->Rdx;
577 to->integer.x86_64_regs.rbx = from->Rbx;
578 to->integer.x86_64_regs.rsi = from->Rsi;
579 to->integer.x86_64_regs.rdi = from->Rdi;
580 to->integer.x86_64_regs.r8 = from->R8;
581 to->integer.x86_64_regs.r9 = from->R9;
582 to->integer.x86_64_regs.r10 = from->R10;
583 to->integer.x86_64_regs.r11 = from->R11;
584 to->integer.x86_64_regs.r12 = from->R12;
585 to->integer.x86_64_regs.r13 = from->R13;
586 to->integer.x86_64_regs.r14 = from->R14;
587 to->integer.x86_64_regs.r15 = from->R15;
589 if (flags & CONTEXT_SEGMENTS)
591 to->flags |= SERVER_CTX_SEGMENTS;
592 to->seg.x86_64_regs.ds = from->SegDs;
593 to->seg.x86_64_regs.es = from->SegEs;
594 to->seg.x86_64_regs.fs = from->SegFs;
595 to->seg.x86_64_regs.gs = from->SegGs;
597 if (flags & CONTEXT_FLOATING_POINT)
599 to->flags |= SERVER_CTX_FLOATING_POINT;
600 memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
602 if (flags & CONTEXT_DEBUG_REGISTERS)
604 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
605 to->debug.x86_64_regs.dr0 = from->Dr0;
606 to->debug.x86_64_regs.dr1 = from->Dr1;
607 to->debug.x86_64_regs.dr2 = from->Dr2;
608 to->debug.x86_64_regs.dr3 = from->Dr3;
609 to->debug.x86_64_regs.dr6 = from->Dr6;
610 to->debug.x86_64_regs.dr7 = from->Dr7;
612 return STATUS_SUCCESS;
616 /***********************************************************************
617 * context_from_server
619 * Convert a register context from the server format.
621 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
623 if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
625 to->ContextFlags = CONTEXT_AMD64;
626 if (from->flags & SERVER_CTX_CONTROL)
628 to->ContextFlags |= CONTEXT_CONTROL;
629 to->Rbp = from->ctl.x86_64_regs.rbp;
630 to->Rip = from->ctl.x86_64_regs.rip;
631 to->Rsp = from->ctl.x86_64_regs.rsp;
632 to->SegCs = from->ctl.x86_64_regs.cs;
633 to->SegSs = from->ctl.x86_64_regs.ss;
634 to->EFlags = from->ctl.x86_64_regs.flags;
635 to->MxCsr = from->ctl.x86_64_regs.mxcsr;
638 if (from->flags & SERVER_CTX_INTEGER)
640 to->ContextFlags |= CONTEXT_INTEGER;
641 to->Rax = from->integer.x86_64_regs.rax;
642 to->Rcx = from->integer.x86_64_regs.rcx;
643 to->Rdx = from->integer.x86_64_regs.rdx;
644 to->Rbx = from->integer.x86_64_regs.rbx;
645 to->Rsi = from->integer.x86_64_regs.rsi;
646 to->Rdi = from->integer.x86_64_regs.rdi;
647 to->R8 = from->integer.x86_64_regs.r8;
648 to->R9 = from->integer.x86_64_regs.r9;
649 to->R10 = from->integer.x86_64_regs.r10;
650 to->R11 = from->integer.x86_64_regs.r11;
651 to->R12 = from->integer.x86_64_regs.r12;
652 to->R13 = from->integer.x86_64_regs.r13;
653 to->R14 = from->integer.x86_64_regs.r14;
654 to->R15 = from->integer.x86_64_regs.r15;
656 if (from->flags & SERVER_CTX_SEGMENTS)
658 to->ContextFlags |= CONTEXT_SEGMENTS;
659 to->SegDs = from->seg.x86_64_regs.ds;
660 to->SegEs = from->seg.x86_64_regs.es;
661 to->SegFs = from->seg.x86_64_regs.fs;
662 to->SegGs = from->seg.x86_64_regs.gs;
664 if (from->flags & SERVER_CTX_FLOATING_POINT)
666 to->ContextFlags |= CONTEXT_FLOATING_POINT;
667 memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
669 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
671 to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
672 to->Dr0 = from->debug.x86_64_regs.dr0;
673 to->Dr1 = from->debug.x86_64_regs.dr1;
674 to->Dr2 = from->debug.x86_64_regs.dr2;
675 to->Dr3 = from->debug.x86_64_regs.dr3;
676 to->Dr6 = from->debug.x86_64_regs.dr6;
677 to->Dr7 = from->debug.x86_64_regs.dr7;
679 return STATUS_SUCCESS;
683 extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
684 __ASM_GLOBAL_FUNC( raise_func_trampoline,
685 ".cfi_signal_frame\n\t"
686 ".cfi_def_cfa %rbp,144\n\t" /* red zone + rip + rbp */
687 ".cfi_rel_offset %rip,8\n\t"
688 ".cfi_rel_offset %rbp,0\n\t"
689 "call *%rdx\n\t"
690 "int $3")
692 /***********************************************************************
693 * setup_exception
695 * Setup a proper stack frame for the raise function, and modify the
696 * sigcontext so that the return from the signal handler will call
697 * the raise function.
699 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
701 struct stack_layout
703 CONTEXT context;
704 EXCEPTION_RECORD rec;
705 ULONG64 rbp;
706 ULONG64 rip;
707 ULONG64 red_zone[16];
708 } *stack;
709 ULONG64 *rsp_ptr;
710 DWORD exception_code = 0;
712 stack = (struct stack_layout *)(RSP_sig(sigcontext) & ~15);
714 /* stack sanity checks */
716 if ((char *)stack >= (char *)get_signal_stack() &&
717 (char *)stack < (char *)get_signal_stack() + signal_stack_size)
719 ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n",
720 GetCurrentThreadId(), RIP_sig(sigcontext), RSP_sig(sigcontext),
721 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
722 abort_thread(1);
725 if (stack - 1 > stack || /* check for overflow in subtraction */
726 (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
727 (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
729 WARN( "exception outside of stack limits in thread %04x eip %016lx esp %016lx stack %p-%p\n",
730 GetCurrentThreadId(), RIP_sig(sigcontext), RSP_sig(sigcontext),
731 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
733 else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096)
735 /* stack overflow on last page, unrecoverable */
736 UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1);
737 ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
738 diff, GetCurrentThreadId(), RIP_sig(sigcontext),
739 RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
740 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
741 abort_thread(1);
743 else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
745 /* stack access below stack limit, may be recoverable */
746 if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
747 else
749 UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
750 ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
751 diff, GetCurrentThreadId(), RIP_sig(sigcontext),
752 RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
753 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
754 abort_thread(1);
758 stack--; /* push the stack_layout structure */
759 stack->rec.ExceptionRecord = NULL;
760 stack->rec.ExceptionCode = exception_code;
761 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
762 stack->rec.ExceptionAddress = (void *)RIP_sig(sigcontext);
763 stack->rec.NumberParameters = 0;
764 save_context( &stack->context, sigcontext );
766 /* store return address and %rbp without aligning, so that the offset is fixed */
767 rsp_ptr = (ULONG64 *)RSP_sig(sigcontext) - 16;
768 *(--rsp_ptr) = RIP_sig(sigcontext);
769 *(--rsp_ptr) = RBP_sig(sigcontext);
771 /* now modify the sigcontext to return to the raise function */
772 RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline;
773 RDI_sig(sigcontext) = (ULONG_PTR)&stack->rec;
774 RSI_sig(sigcontext) = (ULONG_PTR)&stack->context;
775 RDX_sig(sigcontext) = (ULONG_PTR)func;
776 RBP_sig(sigcontext) = (ULONG_PTR)rsp_ptr;
777 RSP_sig(sigcontext) = (ULONG_PTR)stack;
778 /* clear single-step, direction, and align check flag */
779 EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000);
781 return &stack->rec;
785 /**********************************************************************
786 * find_function_info
788 static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
789 RUNTIME_FUNCTION *func, ULONG size )
791 int min = 0;
792 int max = size/sizeof(*func) - 1;
794 while (min <= max)
796 int pos = (min + max) / 2;
797 if ((char *)pc < (char *)module + func[pos].BeginAddress) max = pos - 1;
798 else if ((char *)pc >= (char *)module + func[pos].EndAddress) min = pos + 1;
799 else
801 func += pos;
802 while (func->UnwindData & 1) /* follow chained entry */
803 func = (RUNTIME_FUNCTION *)((char *)module + (func->UnwindData & ~1));
804 return func;
807 return NULL;
810 /**********************************************************************
811 * call_stack_handlers
813 * Call the stack handlers chain.
815 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
817 EXCEPTION_POINTERS ptrs;
818 UNWIND_HISTORY_TABLE table;
819 ULONG64 frame;
820 RUNTIME_FUNCTION *dir, *info;
821 PEXCEPTION_ROUTINE handler;
822 DISPATCHER_CONTEXT dispatch;
823 CONTEXT context, new_context;
824 LDR_MODULE *module;
825 DWORD size;
827 context = *orig_context;
828 for (;;)
830 /* FIXME: should use the history table to make things faster */
832 if (LdrFindEntryForAddress( (void *)context.Rip, &module ))
834 ERR( "no module found for rip %p, can't dispatch exception\n", (void *)context.Rip );
835 break;
837 if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
838 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
840 ERR( "module %s doesn't contain exception data, can't dispatch exception\n",
841 debugstr_w(module->BaseDllName.Buffer) );
842 break;
844 if (!(info = find_function_info( context.Rip, module->BaseAddress, dir, size )))
846 /* leaf function */
847 context.Rip = *(ULONG64 *)context.Rsp;
848 context.Rsp += sizeof(ULONG64);
849 continue;
852 new_context = context;
854 handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)module->BaseAddress, context.Rip,
855 info, &new_context, &dispatch.HandlerData, &frame, NULL );
857 if ((frame & 7) ||
858 frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
859 frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
861 ERR( "invalid frame %lx\n", frame );
862 rec->ExceptionFlags |= EH_STACK_INVALID;
863 break;
866 if (handler)
868 dispatch.ControlPc = context.Rip;
869 dispatch.ImageBase = (ULONG64)module->BaseAddress;
870 dispatch.FunctionEntry = info;
871 dispatch.EstablisherFrame = frame;
872 dispatch.TargetIp = 0; /* FIXME */
873 dispatch.ContextRecord = &context;
874 dispatch.LanguageHandler = handler;
875 dispatch.HistoryTable = &table;
876 dispatch.ScopeIndex = 0; /* FIXME */
878 TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
879 handler, rec, frame, &context, &dispatch );
881 switch( handler( rec, frame, &context, &dispatch ))
883 case ExceptionContinueExecution:
884 if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
885 *orig_context = context;
886 return STATUS_SUCCESS;
887 case ExceptionContinueSearch:
888 break;
889 case ExceptionNestedException:
890 break;
891 default:
892 return STATUS_INVALID_DISPOSITION;
895 context = new_context;
898 /* hack: call unhandled exception filter directly */
899 ptrs.ExceptionRecord = rec;
900 ptrs.ContextRecord = orig_context;
901 unhandled_exception_filter( &ptrs );
902 return STATUS_UNHANDLED_EXCEPTION;
906 /*******************************************************************
907 * raise_exception
909 * Implementation of NtRaiseException.
911 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
913 NTSTATUS status;
915 if (first_chance)
917 DWORD c;
919 TRACE( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n",
920 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
921 context->Rip, GetCurrentThreadId() );
922 for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
923 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
924 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
926 if (rec->ExceptionInformation[1] >> 16)
927 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
928 rec->ExceptionAddress,
929 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
930 else
931 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
932 rec->ExceptionAddress,
933 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
935 else
937 TRACE(" rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
938 context->Rax, context->Rbx, context->Rcx, context->Rdx );
939 TRACE(" rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
940 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
941 TRACE(" r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
942 context->R8, context->R9, context->R10, context->R11 );
943 TRACE(" r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
944 context->R12, context->R13, context->R14, context->R15 );
946 status = send_debug_event( rec, TRUE, context );
947 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
948 return STATUS_SUCCESS;
950 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
951 return STATUS_SUCCESS;
953 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
954 return status;
957 /* last chance exception */
959 status = send_debug_event( rec, FALSE, context );
960 if (status != DBG_CONTINUE)
962 if (rec->ExceptionFlags & EH_STACK_INVALID)
963 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
964 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
965 ERR("Process attempted to continue execution after noncontinuable exception.\n");
966 else
967 ERR("Unhandled exception code %x flags %x addr %p\n",
968 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
969 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
971 return STATUS_SUCCESS;
975 /**********************************************************************
976 * raise_segv_exception
978 static void raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
980 NTSTATUS status;
982 switch(rec->ExceptionCode)
984 case EXCEPTION_ACCESS_VIOLATION:
985 if (rec->NumberParameters == 2)
987 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
988 rec->ExceptionInformation[0] )))
989 set_cpu_context( context );
991 break;
993 status = raise_exception( rec, context, TRUE );
994 if (status) raise_status( status, rec );
998 /**********************************************************************
999 * raise_generic_exception
1001 * Generic raise function for exceptions that don't need special treatment.
1003 static void raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
1005 NTSTATUS status = raise_exception( rec, context, TRUE );
1006 if (status) raise_status( status, rec );
1010 /**********************************************************************
1011 * segv_handler
1013 * Handler for SIGSEGV and related errors.
1015 static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1017 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_segv_exception );
1018 ucontext_t *ucontext = sigcontext;
1020 switch(TRAP_sig(ucontext))
1022 case TRAP_x86_OFLOW: /* Overflow exception */
1023 rec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
1024 break;
1025 case TRAP_x86_BOUND: /* Bound range exception */
1026 rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1027 break;
1028 case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */
1029 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1030 break;
1031 case TRAP_x86_STKFLT: /* Stack fault */
1032 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1033 break;
1034 case TRAP_x86_SEGNPFLT: /* Segment not present exception */
1035 case TRAP_x86_PROTFLT: /* General protection fault */
1036 case TRAP_x86_UNKNOWN: /* Unknown fault code */
1037 rec->ExceptionCode = ERROR_sig(ucontext) ? EXCEPTION_ACCESS_VIOLATION : EXCEPTION_PRIV_INSTRUCTION;
1038 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1039 break;
1040 case TRAP_x86_PAGEFLT: /* Page fault */
1041 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1042 rec->NumberParameters = 2;
1043 rec->ExceptionInformation[0] = (ERROR_sig(ucontext) & 2) != 0;
1044 rec->ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
1045 break;
1046 case TRAP_x86_ALIGNFLT: /* Alignment check exception */
1047 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
1048 break;
1049 default:
1050 ERR( "Got unexpected trap %ld\n", TRAP_sig(ucontext) );
1051 /* fall through */
1052 case TRAP_x86_NMI: /* NMI interrupt */
1053 case TRAP_x86_DNA: /* Device not available exception */
1054 case TRAP_x86_DOUBLEFLT: /* Double fault exception */
1055 case TRAP_x86_TSSFLT: /* Invalid TSS exception */
1056 case TRAP_x86_MCHK: /* Machine check exception */
1057 case TRAP_x86_CACHEFLT: /* Cache flush exception */
1058 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1059 break;
1063 /**********************************************************************
1064 * trap_handler
1066 * Handler for SIGTRAP.
1068 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1070 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
1072 switch (siginfo->si_code)
1074 case TRAP_TRACE: /* Single-step exception */
1075 rec->ExceptionCode = EXCEPTION_SINGLE_STEP;
1076 break;
1077 case TRAP_BRKPT: /* Breakpoint exception */
1078 rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1; /* back up over the int3 instruction */
1079 /* fall through */
1080 default:
1081 rec->ExceptionCode = EXCEPTION_BREAKPOINT;
1082 break;
1086 /**********************************************************************
1087 * fpe_handler
1089 * Handler for SIGFPE.
1091 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1093 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
1095 switch (siginfo->si_code)
1097 case FPE_FLTSUB:
1098 rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1099 break;
1100 case FPE_INTDIV:
1101 rec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1102 break;
1103 case FPE_INTOVF:
1104 rec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
1105 break;
1106 case FPE_FLTDIV:
1107 rec->ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
1108 break;
1109 case FPE_FLTOVF:
1110 rec->ExceptionCode = EXCEPTION_FLT_OVERFLOW;
1111 break;
1112 case FPE_FLTUND:
1113 rec->ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
1114 break;
1115 case FPE_FLTRES:
1116 rec->ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
1117 break;
1118 case FPE_FLTINV:
1119 default:
1120 rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1121 break;
1125 /**********************************************************************
1126 * int_handler
1128 * Handler for SIGINT.
1130 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1132 if (!dispatch_signal(SIGINT))
1134 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
1135 rec->ExceptionCode = CONTROL_C_EXIT;
1140 /**********************************************************************
1141 * abrt_handler
1143 * Handler for SIGABRT.
1145 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1147 EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
1148 rec->ExceptionCode = EXCEPTION_WINE_ASSERTION;
1149 rec->ExceptionFlags = EH_NONCONTINUABLE;
1153 /**********************************************************************
1154 * quit_handler
1156 * Handler for SIGQUIT.
1158 static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
1160 abort_thread(0);
1164 /**********************************************************************
1165 * usr1_handler
1167 * Handler for SIGUSR1, used to signal a thread that it got suspended.
1169 static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
1171 CONTEXT context;
1173 save_context( &context, ucontext );
1174 wait_suspend( &context );
1175 restore_context( &context, ucontext );
1179 /**********************************************************************
1180 * get_signal_stack_total_size
1182 * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
1183 * Must be a power of two.
1185 size_t get_signal_stack_total_size(void)
1187 assert( sizeof(TEB) <= teb_size );
1188 if (!signal_stack_size)
1190 size_t size = 8192, min_size = teb_size + max( MINSIGSTKSZ, 8192 );
1191 /* find the first power of two not smaller than min_size */
1192 while (size < min_size) size *= 2;
1193 signal_stack_size = size - teb_size;
1195 return signal_stack_size + teb_size;
1199 /***********************************************************************
1200 * __wine_set_signal_handler (NTDLL.@)
1202 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
1204 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
1205 if (handlers[sig] != NULL) return -2;
1206 handlers[sig] = wsh;
1207 return 0;
1211 /**********************************************************************
1212 * signal_init_thread
1214 void signal_init_thread( TEB *teb )
1216 stack_t ss;
1218 #ifdef __linux__
1219 arch_prctl( ARCH_SET_GS, teb );
1220 #else
1221 # error Please define setting %gs for your architecture
1222 #endif
1224 ss.ss_sp = (char *)teb + teb_size;
1225 ss.ss_size = signal_stack_size;
1226 ss.ss_flags = 0;
1227 if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
1230 /**********************************************************************
1231 * signal_init_process
1233 void signal_init_process(void)
1235 struct sigaction sig_act;
1237 sig_act.sa_mask = server_block_set;
1238 sig_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
1240 sig_act.sa_sigaction = int_handler;
1241 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
1242 sig_act.sa_sigaction = fpe_handler;
1243 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
1244 sig_act.sa_sigaction = abrt_handler;
1245 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
1246 sig_act.sa_sigaction = quit_handler;
1247 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
1248 sig_act.sa_sigaction = usr1_handler;
1249 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
1251 sig_act.sa_sigaction = segv_handler;
1252 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
1253 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
1254 #ifdef SIGBUS
1255 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
1256 #endif
1258 #ifdef SIGTRAP
1259 sig_act.sa_sigaction = trap_handler;
1260 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1261 #endif
1262 return;
1264 error:
1265 perror("sigaction");
1266 exit(1);
1270 /**********************************************************************
1271 * RtlLookupFunctionEntry (NTDLL.@)
1273 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWIND_HISTORY_TABLE *table )
1275 LDR_MODULE *module;
1276 RUNTIME_FUNCTION *func;
1277 ULONG size;
1279 /* FIXME: should use the history table to make things faster */
1281 if (LdrFindEntryForAddress( (void *)pc, &module ))
1283 WARN( "module not found for %lx\n", pc );
1284 return NULL;
1286 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1287 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1289 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1290 return NULL;
1292 func = find_function_info( pc, module->BaseAddress, func, size );
1293 if (func) *base = (ULONG64)module->BaseAddress;
1294 return func;
1297 static ULONG64 get_int_reg( CONTEXT *context, int reg )
1299 return *(&context->Rax + reg);
1302 static void set_int_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, ULONG64 val )
1304 *(&context->Rax + reg) = val;
1305 if (ctx_ptr) ctx_ptr->u2.IntegerContext[reg] = &context->Rax + reg;
1308 static void set_float_reg( CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr, int reg, M128A val )
1310 *(&context->u.s.Xmm0 + reg) = val;
1311 if (ctx_ptr) ctx_ptr->u1.FloatingContext[reg] = &context->u.s.Xmm0 + reg;
1314 static int get_opcode_size( struct opcode op )
1316 switch (op.code)
1318 case UWOP_ALLOC_LARGE:
1319 return 2 + (op.info != 0);
1320 case UWOP_SAVE_NONVOL:
1321 case UWOP_SAVE_XMM128:
1322 return 2;
1323 case UWOP_SAVE_NONVOL_FAR:
1324 case UWOP_SAVE_XMM128_FAR:
1325 return 3;
1326 default:
1327 return 1;
1331 static BOOL is_inside_epilog( BYTE *pc )
1333 /* add or lea must be the first instruction, and it must have a rex.W prefix */
1334 if ((pc[0] & 0xf8) == 0x48)
1336 switch (pc[1])
1338 case 0x81: /* add $nnnn,%rsp */
1339 if (pc[0] == 0x48 && pc[2] == 0xc4)
1341 pc += 7;
1342 break;
1344 return FALSE;
1345 case 0x83: /* add $n,%rsp */
1346 if (pc[0] == 0x48 && pc[2] == 0xc4)
1348 pc += 4;
1349 break;
1351 return FALSE;
1352 case 0x8d: /* lea n(reg),%rsp */
1353 if (pc[0] & 0x06) return FALSE; /* rex.RX must be cleared */
1354 if (((pc[2] >> 3) & 7) != 4) return FALSE; /* dest reg mus be %rsp */
1355 if ((pc[2] & 7) == 4) return FALSE; /* no SIB byte allowed */
1356 if ((pc[2] >> 6) == 1) /* 8-bit offset */
1358 pc += 4;
1359 break;
1361 if ((pc[2] >> 6) == 2) /* 32-bit offset */
1363 pc += 7;
1364 break;
1366 return FALSE;
1370 /* now check for various pop instructions */
1372 for (;;)
1374 BYTE rex = 0;
1376 if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f; /* rex prefix */
1378 switch (*pc)
1380 case 0x58: /* pop %rax/%r8 */
1381 case 0x59: /* pop %rcx/%r9 */
1382 case 0x5a: /* pop %rdx/%r10 */
1383 case 0x5b: /* pop %rbx/%r11 */
1384 case 0x5c: /* pop %rsp/%r12 */
1385 case 0x5d: /* pop %rbp/%r13 */
1386 case 0x5e: /* pop %rsi/%r14 */
1387 case 0x5f: /* pop %rdi/%r15 */
1388 pc++;
1389 continue;
1390 case 0xc2: /* ret $nn */
1391 case 0xc3: /* ret */
1392 return TRUE;
1393 /* FIXME: add various jump instructions */
1395 return FALSE;
1399 /* execute a function epilog, which must have been validated with is_inside_epilog() */
1400 static void interpret_epilog( BYTE *pc, CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
1402 for (;;)
1404 BYTE rex = 0;
1406 if ((*pc & 0xf0) == 0x40) rex = *pc++ & 0x0f; /* rex prefix */
1408 switch (*pc)
1410 case 0x58: /* pop %rax/r8 */
1411 case 0x59: /* pop %rcx/r9 */
1412 case 0x5a: /* pop %rdx/r10 */
1413 case 0x5b: /* pop %rbx/r11 */
1414 case 0x5c: /* pop %rsp/r12 */
1415 case 0x5d: /* pop %rbp/r13 */
1416 case 0x5e: /* pop %rsi/r14 */
1417 case 0x5f: /* pop %rdi/r15 */
1418 set_int_reg( context, ctx_ptr, *pc - 0x58 + (rex & 1) * 8, *(ULONG64 *)context->Rsp );
1419 context->Rsp += sizeof(ULONG64);
1420 pc++;
1421 continue;
1422 case 0x81: /* add $nnnn,%rsp */
1423 context->Rsp += *(LONG *)(pc + 2);
1424 pc += 2 + sizeof(LONG);
1425 continue;
1426 case 0x83: /* add $n,%rsp */
1427 context->Rsp += (signed char)pc[2];
1428 pc += 3;
1429 continue;
1430 case 0x8d:
1431 if ((pc[1] >> 6) == 1) /* lea n(reg),%rsp */
1433 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + (signed char)pc[2];
1434 pc += 3;
1436 else /* lea nnnn(reg),%rsp */
1438 context->Rsp = get_int_reg( context, (pc[1] & 7) + (rex & 1) * 8 ) + *(LONG *)(pc + 2);
1439 pc += 2 + sizeof(LONG);
1441 continue;
1442 case 0xc2: /* ret $nn */
1443 context->Rip = *(ULONG64 *)context->Rsp;
1444 context->Rsp += sizeof(ULONG64) + *(WORD *)(pc + 1);
1445 return;
1446 case 0xc3: /* ret */
1447 context->Rip = *(ULONG64 *)context->Rsp;
1448 context->Rsp += sizeof(ULONG64);
1449 return;
1450 /* FIXME: add various jump instructions */
1452 return;
1456 /**********************************************************************
1457 * RtlVirtualUnwind (NTDLL.@)
1459 PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
1460 RUNTIME_FUNCTION *function, CONTEXT *context,
1461 PVOID *data, ULONG64 *frame_ret,
1462 KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
1464 union handler_data *handler_data;
1465 ULONG64 frame, off;
1466 struct UNWIND_INFO *info;
1467 unsigned int i, prolog_offset;
1469 TRACE( "type %x rip %lx rsp %lx\n", type, pc, context->Rsp );
1470 if (TRACE_ON(seh)) dump_unwind_info( base, function );
1472 frame = *frame_ret = context->Rsp;
1473 for (;;)
1475 info = (struct UNWIND_INFO *)((char *)base + function->UnwindData);
1476 handler_data = (union handler_data *)&info->opcodes[(info->count + 1) & ~1];
1478 if (info->version != 1)
1480 FIXME( "unknown unwind info version %u at %p\n", info->version, info );
1481 return NULL;
1484 if (info->frame_reg)
1485 frame = get_int_reg( context, info->frame_reg ) - info->frame_offset * 16;
1487 /* check if in prolog */
1488 if (pc >= base + function->BeginAddress && pc < base + function->BeginAddress + info->prolog)
1490 prolog_offset = pc - base - function->BeginAddress;
1492 else
1494 prolog_offset = ~0;
1495 if (is_inside_epilog( (BYTE *)pc ))
1497 interpret_epilog( (BYTE *)pc, context, ctx_ptr );
1498 *frame_ret = frame;
1499 return NULL;
1503 for (i = 0; i < info->count; i += get_opcode_size(info->opcodes[i]))
1505 if (prolog_offset < info->opcodes[i].offset) continue; /* skip it */
1507 switch (info->opcodes[i].code)
1509 case UWOP_PUSH_NONVOL: /* pushq %reg */
1510 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)context->Rsp );
1511 context->Rsp += sizeof(ULONG64);
1512 break;
1513 case UWOP_ALLOC_LARGE: /* subq $nn,%rsp */
1514 if (info->opcodes[i].info) context->Rsp += *(DWORD *)&info->opcodes[i+1];
1515 else context->Rsp += *(USHORT *)&info->opcodes[i+1] * 8;
1516 break;
1517 case UWOP_ALLOC_SMALL: /* subq $n,%rsp */
1518 context->Rsp += (info->opcodes[i].info + 1) * 8;
1519 break;
1520 case UWOP_SET_FPREG: /* leaq nn(%rsp),%framereg */
1521 context->Rsp = *frame_ret = frame;
1522 break;
1523 case UWOP_SAVE_NONVOL: /* movq %reg,n(%rsp) */
1524 off = frame + *(USHORT *)&info->opcodes[i+1] * 8;
1525 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)off );
1526 break;
1527 case UWOP_SAVE_NONVOL_FAR: /* movq %reg,nn(%rsp) */
1528 off = frame + *(DWORD *)&info->opcodes[i+1];
1529 set_int_reg( context, ctx_ptr, info->opcodes[i].info, *(ULONG64 *)off );
1530 break;
1531 case UWOP_SAVE_XMM128: /* movaps %xmmreg,n(%rsp) */
1532 off = frame + *(USHORT *)&info->opcodes[i+1] * 16;
1533 set_float_reg( context, ctx_ptr, info->opcodes[i].info, *(M128A *)off );
1534 break;
1535 case UWOP_SAVE_XMM128_FAR: /* movaps %xmmreg,nn(%rsp) */
1536 off = frame + *(DWORD *)&info->opcodes[i+1];
1537 set_float_reg( context, ctx_ptr, info->opcodes[i].info, *(M128A *)off );
1538 break;
1539 case UWOP_PUSH_MACHFRAME:
1540 FIXME( "PUSH_MACHFRAME %u\n", info->opcodes[i].info );
1541 break;
1542 default:
1543 FIXME( "unknown code %u\n", info->opcodes[i].code );
1544 break;
1548 if (!(info->flags & UNW_FLAG_CHAININFO)) break;
1549 function = &handler_data->chain; /* restart with the chained info */
1552 /* now pop return address */
1553 context->Rip = *(ULONG64 *)context->Rsp;
1554 context->Rsp += sizeof(ULONG64);
1556 if (!(info->flags & type)) return NULL; /* no matching handler */
1557 if (prolog_offset != ~0) return NULL; /* inside prolog */
1559 *data = &handler_data->handler + 1;
1560 return (char *)base + handler_data->handler;
1564 /*******************************************************************
1565 * RtlUnwindEx (NTDLL.@)
1567 void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1568 ULONG64 retval, CONTEXT *context, UNWIND_HISTORY_TABLE *table )
1570 EXCEPTION_RECORD record;
1571 ULONG64 frame;
1572 RUNTIME_FUNCTION *dir, *info;
1573 PEXCEPTION_ROUTINE handler;
1574 DISPATCHER_CONTEXT dispatch;
1575 CONTEXT new_context;
1576 LDR_MODULE *module;
1577 DWORD size;
1579 /* build an exception record, if we do not have one */
1580 if (!rec)
1582 record.ExceptionCode = STATUS_UNWIND;
1583 record.ExceptionFlags = 0;
1584 record.ExceptionRecord = NULL;
1585 record.ExceptionAddress = (void *)context->Rip;
1586 record.NumberParameters = 0;
1587 rec = &record;
1590 rec->ExceptionFlags |= EH_UNWINDING | (end_frame ? 0 : EH_EXIT_UNWIND);
1592 FIXME( "code=%x flags=%x end_frame=%lx target_ip=%lx\n",
1593 rec->ExceptionCode, rec->ExceptionFlags, end_frame, target_ip );
1595 frame = context->Rsp;
1596 while (frame != end_frame)
1598 /* FIXME: should use the history table to make things faster */
1600 if (LdrFindEntryForAddress( (void *)context->Rip, &module ))
1602 ERR( "no module found for rip %p, can't unwind exception\n", (void *)context->Rip );
1603 raise_status( STATUS_BAD_FUNCTION_TABLE, rec );
1605 if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1606 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1608 ERR( "module %s doesn't contain exception data, can't unwind exception\n",
1609 debugstr_w(module->BaseDllName.Buffer) );
1610 raise_status( STATUS_BAD_FUNCTION_TABLE, rec );
1612 if (!(info = find_function_info( context->Rip, module->BaseAddress, dir, size )))
1614 /* leaf function */
1615 context->Rip = *(ULONG64 *)context->Rsp;
1616 context->Rsp += sizeof(ULONG64);
1617 continue;
1620 new_context = *context;
1622 handler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, (ULONG64)module->BaseAddress, context->Rip,
1623 info, &new_context, &dispatch.HandlerData, &frame, NULL );
1625 if ((frame & 7) ||
1626 frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
1627 frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
1629 ERR( "invalid frame %lx\n", frame );
1630 raise_status( STATUS_BAD_STACK, rec );
1633 if (end_frame && (frame > end_frame))
1635 ERR( "invalid frame %lx/%lx\n", frame, end_frame );
1636 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1639 if (handler)
1641 dispatch.ControlPc = context->Rip;
1642 dispatch.ImageBase = (ULONG64)module->BaseAddress;
1643 dispatch.FunctionEntry = info;
1644 dispatch.EstablisherFrame = frame;
1645 dispatch.TargetIp = target_ip;
1646 dispatch.ContextRecord = context;
1647 dispatch.LanguageHandler = handler;
1648 dispatch.HistoryTable = table;
1649 dispatch.ScopeIndex = 0; /* FIXME */
1651 TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
1652 handler, rec, frame, context, &dispatch );
1654 switch( handler( rec, frame, context, &dispatch ))
1656 case ExceptionContinueSearch:
1657 break;
1658 case ExceptionCollidedUnwind:
1659 FIXME( "ExceptionCollidedUnwind not supported yet\n" );
1660 break;
1661 default:
1662 raise_status( STATUS_INVALID_DISPOSITION, rec );
1663 break;
1666 *context = new_context;
1668 context->Rax = retval;
1669 context->Rip = target_ip;
1670 TRACE( "returning to %lx stack %lx\n", context->Rip, context->Rsp );
1671 set_cpu_context( context );
1675 /*******************************************************************
1676 * RtlUnwind (NTDLL.@)
1678 void WINAPI __regs_RtlUnwind( ULONG64 frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
1679 ULONG64 retval, CONTEXT *context )
1681 RtlUnwindEx( frame, target_ip, rec, retval, context, NULL );
1683 DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
1686 /*******************************************************************
1687 * __C_specific_handler (NTDLL.@)
1689 EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
1690 ULONG64 frame,
1691 CONTEXT *context,
1692 struct _DISPATCHER_CONTEXT *dispatch )
1694 SCOPE_TABLE *table = dispatch->HandlerData;
1695 ULONG i;
1697 TRACE( "%p %lx %p %p\n", rec, frame, context, dispatch );
1698 if (TRACE_ON(seh)) dump_scope_table( dispatch->ImageBase, table );
1700 if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) /* FIXME */
1701 return ExceptionContinueSearch;
1703 for (i = 0; i < table->Count; i++)
1705 if (context->Rip >= dispatch->ImageBase + table->ScopeRecord[i].BeginAddress &&
1706 context->Rip < dispatch->ImageBase + table->ScopeRecord[i].EndAddress)
1708 if (!table->ScopeRecord[i].JumpTarget) continue;
1709 if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER)
1711 EXCEPTION_POINTERS ptrs;
1712 PC_LANGUAGE_EXCEPTION_HANDLER filter;
1714 filter = (PC_LANGUAGE_EXCEPTION_HANDLER)(dispatch->ImageBase + table->ScopeRecord[i].HandlerAddress);
1715 ptrs.ExceptionRecord = rec;
1716 ptrs.ContextRecord = context;
1717 TRACE( "calling filter %p ptrs %p frame %lx\n", filter, &ptrs, frame );
1718 switch (filter( &ptrs, frame ))
1720 case EXCEPTION_EXECUTE_HANDLER:
1721 break;
1722 case EXCEPTION_CONTINUE_SEARCH:
1723 continue;
1724 case EXCEPTION_CONTINUE_EXECUTION:
1725 return ExceptionContinueExecution;
1728 TRACE( "unwinding to target %lx\n", dispatch->ImageBase + table->ScopeRecord[i].JumpTarget );
1729 RtlUnwindEx( frame, dispatch->ImageBase + table->ScopeRecord[i].JumpTarget,
1730 rec, 0, context, dispatch->HistoryTable );
1733 return ExceptionContinueSearch;
1737 /*******************************************************************
1738 * NtRaiseException (NTDLL.@)
1740 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1742 NTSTATUS status = raise_exception( rec, context, first_chance );
1743 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1744 return status;
1748 /***********************************************************************
1749 * RtlRaiseException (NTDLL.@)
1751 void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
1753 NTSTATUS status;
1755 rec->ExceptionAddress = (void *)context->Rip;
1756 status = raise_exception( rec, context, TRUE );
1757 if (status != STATUS_SUCCESS) raise_status( status, rec );
1759 DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
1762 /**********************************************************************
1763 * __wine_enter_vm86 (NTDLL.@)
1765 void __wine_enter_vm86( CONTEXT *context )
1767 MESSAGE("vm86 mode not supported on this platform\n");
1770 /**********************************************************************
1771 * DbgBreakPoint (NTDLL.@)
1773 __ASM_STDCALL_FUNC( DbgBreakPoint, 0, "int $3; ret")
1775 /**********************************************************************
1776 * DbgUserBreakPoint (NTDLL.@)
1778 __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "int $3; ret")
1780 #endif /* __x86_64__ */