ntoskrnl.exe: Add a helper function for accessing registers.
[wine.git] / dlls / ntoskrnl.exe / instr.c
blob2822aac083d2f3c8a4cf6d19719d353c5f7ca8fb
1 /*
2 * Emulation of privileged instructions
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 2005 Ivan Leo Puoti
6 * Copyright 2005 Laurent Pinchart
7 * Copyright 2014-2015 Sebastian Lackner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.h"
32 #define WIN32_NO_STATUS
33 #include "ddk/wdm.h"
34 #include "excpt.h"
35 #include "wine/debug.h"
36 #include "wine/exception.h"
38 #ifdef __i386__
40 WINE_DEFAULT_DEBUG_CHANNEL(int);
42 #include "pshpack1.h"
43 struct idtr
45 WORD limit;
46 BYTE *base;
48 #include "poppack.h"
50 static LDT_ENTRY idt[256];
52 static inline struct idtr get_idtr(void)
54 struct idtr ret;
55 #ifdef __GNUC__
56 __asm__( "sidtl %0" : "=m" (ret) );
57 #else
58 ret.base = (BYTE *)idt;
59 ret.limit = sizeof(idt) - 1;
60 #endif
61 return ret;
64 /* store an operand into a register */
65 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op )
67 switch((regmodrm >> 3) & 7)
69 case 0:
70 if (long_op) context->Eax = *(const DWORD *)addr;
71 else context->Eax = (context->Eax & 0xffff0000) | *(const WORD *)addr;
72 break;
73 case 1:
74 if (long_op) context->Ecx = *(const DWORD *)addr;
75 else context->Ecx = (context->Ecx & 0xffff0000) | *(const WORD *)addr;
76 break;
77 case 2:
78 if (long_op) context->Edx = *(const DWORD *)addr;
79 else context->Edx = (context->Edx & 0xffff0000) | *(const WORD *)addr;
80 break;
81 case 3:
82 if (long_op) context->Ebx = *(const DWORD *)addr;
83 else context->Ebx = (context->Ebx & 0xffff0000) | *(const WORD *)addr;
84 break;
85 case 4:
86 if (long_op) context->Esp = *(const DWORD *)addr;
87 else context->Esp = (context->Esp & 0xffff0000) | *(const WORD *)addr;
88 break;
89 case 5:
90 if (long_op) context->Ebp = *(const DWORD *)addr;
91 else context->Ebp = (context->Ebp & 0xffff0000) | *(const WORD *)addr;
92 break;
93 case 6:
94 if (long_op) context->Esi = *(const DWORD *)addr;
95 else context->Esi = (context->Esi & 0xffff0000) | *(const WORD *)addr;
96 break;
97 case 7:
98 if (long_op) context->Edi = *(const DWORD *)addr;
99 else context->Edi = (context->Edi & 0xffff0000) | *(const WORD *)addr;
100 break;
104 /* store an operand into a byte register */
105 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr )
107 switch((regmodrm >> 3) & 7)
109 case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break;
110 case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break;
111 case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break;
112 case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break;
113 case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break;
114 case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break;
115 case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break;
116 case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break;
120 static DWORD *get_reg_address( CONTEXT *context, BYTE rm )
122 switch (rm & 7)
124 case 0: return &context->Eax;
125 case 1: return &context->Ecx;
126 case 2: return &context->Edx;
127 case 3: return &context->Ebx;
128 case 4: return &context->Esp;
129 case 5: return &context->Ebp;
130 case 6: return &context->Esi;
131 case 7: return &context->Edi;
133 return NULL;
137 /***********************************************************************
138 * INSTR_GetOperandAddr
140 * Return the address of an instruction operand (from the mod/rm byte).
142 static void *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
143 int long_addr, int segprefix, int *len )
145 int mod, rm, base = 0, index = 0, ss = 0, off;
147 #define GET_VAL(val,type) \
148 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
150 *len = 0;
151 GET_VAL( &mod, BYTE );
152 rm = mod & 7;
153 mod >>= 6;
155 if (mod == 3) return get_reg_address( context, rm );
157 if (long_addr)
159 if (rm == 4)
161 BYTE sib;
162 GET_VAL( &sib, BYTE );
163 rm = sib & 7;
164 ss = sib >> 6;
165 switch((sib >> 3) & 7)
167 case 0: index = context->Eax; break;
168 case 1: index = context->Ecx; break;
169 case 2: index = context->Edx; break;
170 case 3: index = context->Ebx; break;
171 case 4: index = 0; break;
172 case 5: index = context->Ebp; break;
173 case 6: index = context->Esi; break;
174 case 7: index = context->Edi; break;
178 switch(rm)
180 case 0: base = context->Eax; break;
181 case 1: base = context->Ecx; break;
182 case 2: base = context->Edx; break;
183 case 3: base = context->Ebx; break;
184 case 4: base = context->Esp; break;
185 case 5: base = context->Ebp; break;
186 case 6: base = context->Esi; break;
187 case 7: base = context->Edi; break;
189 switch (mod)
191 case 0:
192 if (rm == 5) /* special case: ds:(disp32) */
194 GET_VAL( &base, DWORD );
196 break;
198 case 1: /* 8-bit disp */
199 GET_VAL( &off, BYTE );
200 base += (signed char)off;
201 break;
203 case 2: /* 32-bit disp */
204 GET_VAL( &off, DWORD );
205 base += (signed long)off;
206 break;
209 else /* short address */
211 switch(rm)
213 case 0: /* ds:(bx,si) */
214 base = LOWORD(context->Ebx) + LOWORD(context->Esi);
215 break;
216 case 1: /* ds:(bx,di) */
217 base = LOWORD(context->Ebx) + LOWORD(context->Edi);
218 break;
219 case 2: /* ss:(bp,si) */
220 base = LOWORD(context->Ebp) + LOWORD(context->Esi);
221 break;
222 case 3: /* ss:(bp,di) */
223 base = LOWORD(context->Ebp) + LOWORD(context->Edi);
224 break;
225 case 4: /* ds:(si) */
226 base = LOWORD(context->Esi);
227 break;
228 case 5: /* ds:(di) */
229 base = LOWORD(context->Edi);
230 break;
231 case 6: /* ss:(bp) */
232 base = LOWORD(context->Ebp);
233 break;
234 case 7: /* ds:(bx) */
235 base = LOWORD(context->Ebx);
236 break;
239 switch(mod)
241 case 0:
242 if (rm == 6) /* special case: ds:(disp16) */
244 GET_VAL( &base, WORD );
246 break;
248 case 1: /* 8-bit disp */
249 GET_VAL( &off, BYTE );
250 base += (signed char)off;
251 break;
253 case 2: /* 16-bit disp */
254 GET_VAL( &off, WORD );
255 base += (signed short)off;
256 break;
258 base &= 0xffff;
260 /* FIXME: we assume that all segments have a base of 0 */
261 return (void *)(base + (index << ss));
262 #undef GET_VAL
266 /***********************************************************************
267 * emulate_instruction
269 * Emulate a privileged instruction.
270 * Returns exception continuation status.
272 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
274 int prefix, segprefix, prefixlen, len, long_op, long_addr;
275 BYTE *instr;
277 long_op = long_addr = 1;
278 instr = (BYTE *)context->Eip;
279 if (!instr) return ExceptionContinueSearch;
281 /* First handle any possible prefix */
283 segprefix = -1; /* no prefix */
284 prefix = 1;
285 prefixlen = 0;
286 while(prefix)
288 switch(*instr)
290 case 0x2e:
291 segprefix = context->SegCs;
292 break;
293 case 0x36:
294 segprefix = context->SegSs;
295 break;
296 case 0x3e:
297 segprefix = context->SegDs;
298 break;
299 case 0x26:
300 segprefix = context->SegEs;
301 break;
302 case 0x64:
303 segprefix = context->SegFs;
304 break;
305 case 0x65:
306 segprefix = context->SegGs;
307 break;
308 case 0x66:
309 long_op = !long_op; /* opcode size prefix */
310 break;
311 case 0x67:
312 long_addr = !long_addr; /* addr size prefix */
313 break;
314 case 0xf0: /* lock */
315 break;
316 case 0xf2: /* repne */
317 break;
318 case 0xf3: /* repe */
319 break;
320 default:
321 prefix = 0; /* no more prefixes */
322 break;
324 if (prefix)
326 instr++;
327 prefixlen++;
331 /* Now look at the actual instruction */
333 switch(*instr)
335 case 0x0f: /* extended instruction */
336 switch(instr[1])
338 case 0x22: /* mov eax, crX */
339 switch (instr[2])
341 case 0xc0:
342 TRACE("mov eax,cr0 at 0x%08x, EAX=0x%08x\n", context->Eip,context->Eax );
343 context->Eip += prefixlen+3;
344 return ExceptionContinueExecution;
345 case 0xe0:
346 TRACE("mov eax,cr4 at 0x%08x, EAX=0x%08x\n", context->Eip,context->Eax );
347 context->Eip += prefixlen+3;
348 return ExceptionContinueExecution;
349 default:
350 break; /*fallthrough to bad instruction handling */
352 ERR("Unsupported EAX -> CR register, eip+2 is %02x\n", instr[2]);
353 break; /*fallthrough to bad instruction handling */
354 case 0x20: /* mov crX, eax */
355 switch (instr[2])
357 case 0xe0: /* mov cr4, eax */
358 /* CR4 register . See linux/arch/i386/mm/init.c, X86_CR4_ defs
359 * bit 0: VME Virtual Mode Exception ?
360 * bit 1: PVI Protected mode Virtual Interrupt
361 * bit 2: TSD Timestamp disable
362 * bit 3: DE Debugging extensions
363 * bit 4: PSE Page size extensions
364 * bit 5: PAE Physical address extension
365 * bit 6: MCE Machine check enable
366 * bit 7: PGE Enable global pages
367 * bit 8: PCE Enable performance counters at IPL3
369 TRACE("mov cr4,eax at 0x%08x\n",context->Eip);
370 context->Eax = 0;
371 context->Eip += prefixlen+3;
372 return ExceptionContinueExecution;
373 case 0xc0: /* mov cr0, eax */
374 TRACE("mov cr0,eax at 0x%08x\n",context->Eip);
375 context->Eax = 0x10; /* FIXME: set more bits ? */
376 context->Eip += prefixlen+3;
377 return ExceptionContinueExecution;
378 default: /* fallthrough to illegal instruction */
379 break;
381 /* fallthrough to illegal instruction */
382 break;
383 case 0x21: /* mov drX, eax */
384 switch (instr[2])
386 case 0xc8: /* mov dr1, eax */
387 TRACE("mov dr1,eax at 0x%08x\n",context->Eip);
388 context->Eax = context->Dr1;
389 context->Eip += prefixlen+3;
390 return ExceptionContinueExecution;
391 case 0xf8: /* mov dr7, eax */
392 TRACE("mov dr7,eax at 0x%08x\n",context->Eip);
393 context->Eax = 0x400;
394 context->Eip += prefixlen+3;
395 return ExceptionContinueExecution;
397 ERR("Unsupported DR register -> EAX, eip+2 is %02x\n", instr[2]);
398 /* fallthrough to illegal instruction */
399 break;
400 case 0x23: /* mov eax drX */
401 switch (instr[2])
403 case 0xc0: /* mov eax, dr0 */
404 context->Dr0 = context->Eax;
405 context->Eip += prefixlen+3;
406 return ExceptionContinueExecution;
407 case 0xc8: /* mov eax, dr1 */
408 context->Dr1 = context->Eax;
409 context->Eip += prefixlen+3;
410 return ExceptionContinueExecution;
411 case 0xd0: /* mov eax, dr2 */
412 context->Dr2 = context->Eax;
413 context->Eip += prefixlen+3;
414 return ExceptionContinueExecution;
415 case 0xd8: /* mov eax, dr3 */
416 context->Dr3 = context->Eax;
417 context->Eip += prefixlen+3;
418 return ExceptionContinueExecution;
419 case 0xf8: /* mov eax, dr7 */
420 context->Dr7 = context->Eax;
421 context->Eip += prefixlen+3;
422 return ExceptionContinueExecution;
424 ERR("Unsupported EAX -> DR register, eip+2 is %02x\n", instr[2]);
425 /* fallthrough to illegal instruction */
426 break;
428 break; /* Unable to emulate it */
430 case 0x8a: /* mov Eb, Gb */
431 case 0x8b: /* mov Ev, Gv */
433 BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr,
434 segprefix, &len);
435 unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1;
436 struct idtr idtr = get_idtr();
437 unsigned int offset = data - idtr.base;
439 if (offset <= idtr.limit + 1 - data_size)
441 idt[1].LimitLow = 0x100; /* FIXME */
442 idt[2].LimitLow = 0x11E; /* FIXME */
443 idt[3].LimitLow = 0x500; /* FIXME */
445 switch (*instr)
447 case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break;
448 case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break;
450 context->Eip += prefixlen + len + 1;
451 return ExceptionContinueExecution;
453 break; /* Unable to emulate it */
456 case 0xfa: /* cli */
457 case 0xfb: /* sti */
458 context->Eip += prefixlen + 1;
459 return ExceptionContinueExecution;
461 return ExceptionContinueSearch; /* Unable to emulate it */
465 /***********************************************************************
466 * vectored_handler
468 * Vectored exception handler used to emulate protected instructions
469 * from 32-bit code.
471 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
473 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
474 CONTEXT *context = ptrs->ContextRecord;
476 if ((record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
477 record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION))
479 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
480 return EXCEPTION_CONTINUE_EXECUTION;
482 return EXCEPTION_CONTINUE_SEARCH;
485 #elif defined(__x86_64__) /* __i386__ */
487 WINE_DEFAULT_DEBUG_CHANNEL(int);
489 #define REX_B 1
490 #define REX_X 2
491 #define REX_R 4
492 #define REX_W 8
494 #define REGMODRM_MOD( regmodrm, rex ) ((regmodrm) >> 6)
495 #define REGMODRM_REG( regmodrm, rex ) (((regmodrm) >> 3) & 7) | (((rex) & REX_R) ? 8 : 0)
496 #define REGMODRM_RM( regmodrm, rex ) (((regmodrm) & 7) | (((rex) & REX_B) ? 8 : 0))
498 #define SIB_SS( sib, rex ) ((sib) >> 6)
499 #define SIB_INDEX( sib, rex ) (((sib) >> 3) & 7) | (((rex) & REX_X) ? 8 : 0)
500 #define SIB_BASE( sib, rex ) (((sib) & 7) | (((rex) & REX_B) ? 8 : 0))
502 /* keep in sync with dlls/ntdll/thread.c:thread_init */
503 static const BYTE *wine_user_shared_data = (BYTE *)0x7ffe0000;
504 static const BYTE *user_shared_data = (BYTE *)0xfffff78000000000;
506 static inline DWORD64 *get_int_reg( CONTEXT *context, int index )
508 return &context->Rax + index; /* index should be in range 0 .. 15 */
511 static inline int get_op_size( int long_op, int rex )
513 if (rex & REX_W)
514 return sizeof(DWORD64);
515 else if (long_op)
516 return sizeof(DWORD);
517 else
518 return sizeof(WORD);
521 /* store an operand into a register */
522 static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op, int rex )
524 int index = REGMODRM_REG( regmodrm, rex );
525 BYTE *reg = (BYTE *)get_int_reg( context, index );
526 memcpy( reg, addr, get_op_size( long_op, rex ) );
529 /* store an operand into a byte register */
530 static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int rex )
532 int index = REGMODRM_REG( regmodrm, rex );
533 BYTE *reg = (BYTE *)get_int_reg( context, index );
534 if (!rex && index >= 4 && index < 8) reg -= (4 * sizeof(DWORD64) - 1); /* special case: ah, ch, dh, bh */
535 *reg = *addr;
538 /***********************************************************************
539 * INSTR_GetOperandAddr
541 * Return the address of an instruction operand (from the mod/rm byte).
543 static BYTE *INSTR_GetOperandAddr( CONTEXT *context, BYTE *instr,
544 int long_addr, int rex, int segprefix, int *len )
546 int mod, rm, ss = 0, off, have_sib = 0;
547 DWORD64 base = 0, index = 0;
549 #define GET_VAL( val, type ) \
550 { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
552 *len = 0;
553 GET_VAL( &mod, BYTE );
554 rm = REGMODRM_RM( mod, rex );
555 mod = REGMODRM_MOD( mod, rex );
557 if (mod == 3)
558 return (BYTE *)get_int_reg( context, rm );
560 if ((rm & 7) == 4)
562 BYTE sib;
563 int id;
565 GET_VAL( &sib, BYTE );
566 rm = SIB_BASE( sib, rex );
567 id = SIB_INDEX( sib, rex );
568 ss = SIB_SS( sib, rex );
570 index = (id != 4) ? *get_int_reg( context, id ) : 0;
571 if (!long_addr) index &= 0xffffffff;
572 have_sib = 1;
575 base = *get_int_reg( context, rm );
576 if (!long_addr) base &= 0xffffffff;
578 switch (mod)
580 case 0:
581 if (rm == 5) /* special case */
583 base = have_sib ? 0 : context->Rip;
584 if (!long_addr) base &= 0xffffffff;
585 GET_VAL( &off, DWORD );
586 base += (signed long)off;
588 break;
590 case 1: /* 8-bit disp */
591 GET_VAL( &off, BYTE );
592 base += (signed char)off;
593 break;
595 case 2: /* 32-bit disp */
596 GET_VAL( &off, DWORD );
597 base += (signed long)off;
598 break;
601 /* FIXME: we assume that all segments have a base of 0 */
602 return (BYTE *)(base + (index << ss));
603 #undef GET_VAL
607 /***********************************************************************
608 * emulate_instruction
610 * Emulate a privileged instruction.
611 * Returns exception continuation status.
613 static DWORD emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context )
615 int prefix, segprefix, prefixlen, len, long_op, long_addr, rex;
616 BYTE *instr;
618 long_op = long_addr = 1;
619 instr = (BYTE *)context->Rip;
620 if (!instr) return ExceptionContinueSearch;
622 /* First handle any possible prefix */
624 segprefix = -1; /* no seg prefix */
625 rex = 0; /* no rex prefix */
626 prefix = 1;
627 prefixlen = 0;
628 while(prefix)
630 switch(*instr)
632 case 0x2e:
633 segprefix = context->SegCs;
634 break;
635 case 0x36:
636 segprefix = context->SegSs;
637 break;
638 case 0x3e:
639 segprefix = context->SegDs;
640 break;
641 case 0x26:
642 segprefix = context->SegEs;
643 break;
644 case 0x64:
645 segprefix = context->SegFs;
646 break;
647 case 0x65:
648 segprefix = context->SegGs;
649 break;
650 case 0x66:
651 long_op = !long_op; /* opcode size prefix */
652 break;
653 case 0x67:
654 long_addr = !long_addr; /* addr size prefix */
655 break;
656 case 0xf0: /* lock */
657 break;
658 case 0xf2: /* repne */
659 break;
660 case 0xf3: /* repe */
661 break;
662 default:
663 prefix = 0; /* no more prefixes */
664 break;
666 if (*instr >= 0x40 && *instr < 0x50) /* rex */
668 rex = *instr;
669 prefix = TRUE;
671 if (prefix)
673 instr++;
674 prefixlen++;
678 /* Now look at the actual instruction */
680 switch(*instr)
682 case 0x0f: /* extended instruction */
683 switch(instr[1])
685 case 0xb6: /* movzx Eb, Gv */
686 case 0xb7: /* movzx Ew, Gv */
688 BYTE *data = INSTR_GetOperandAddr( context, instr + 2, long_addr,
689 rex, segprefix, &len );
690 unsigned int data_size = (instr[1] == 0xb7) ? 2 : 1;
691 SIZE_T offset = data - user_shared_data;
693 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
695 ULONGLONG temp = 0;
696 memcpy( &temp, wine_user_shared_data + offset, data_size );
697 store_reg_word( context, instr[2], (BYTE *)&temp, long_op, rex );
698 context->Rip += prefixlen + len + 2;
699 return ExceptionContinueExecution;
701 break; /* Unable to emulate it */
704 break; /* Unable to emulate it */
706 case 0x8a: /* mov Eb, Gb */
707 case 0x8b: /* mov Ev, Gv */
709 BYTE *data = INSTR_GetOperandAddr( context, instr + 1, long_addr,
710 rex, segprefix, &len );
711 unsigned int data_size = (*instr == 0x8b) ? get_op_size( long_op, rex ) : 1;
712 SIZE_T offset = data - user_shared_data;
714 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
716 switch (*instr)
718 case 0x8a: store_reg_byte( context, instr[1], wine_user_shared_data + offset, rex ); break;
719 case 0x8b: store_reg_word( context, instr[1], wine_user_shared_data + offset, long_op, rex ); break;
721 context->Rip += prefixlen + len + 1;
722 return ExceptionContinueExecution;
724 break; /* Unable to emulate it */
727 case 0xa0: /* mov Ob, AL */
728 case 0xa1: /* mov Ovqp, rAX */
730 BYTE *data = (BYTE *)(long_addr ? *(DWORD64 *)(instr + 1) : *(DWORD *)(instr + 1));
731 unsigned int data_size = (*instr == 0xa1) ? get_op_size( long_op, rex ) : 1;
732 SIZE_T offset = data - user_shared_data;
733 len = long_addr ? sizeof(DWORD64) : sizeof(DWORD);
735 if (offset <= sizeof(KSHARED_USER_DATA) - data_size)
737 memcpy( &context->Rax, wine_user_shared_data + offset, data_size );
738 context->Rip += prefixlen + len + 1;
739 return ExceptionContinueExecution;
741 break; /* Unable to emulate it */
744 return ExceptionContinueSearch; /* Unable to emulate it */
748 /***********************************************************************
749 * vectored_handler
751 * Vectored exception handler used to emulate protected instructions
752 * from 64-bit code.
754 LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
756 EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
757 CONTEXT *context = ptrs->ContextRecord;
759 if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
760 record->ExceptionInformation[0] == EXCEPTION_READ_FAULT)
762 if (emulate_instruction( record, context ) == ExceptionContinueExecution)
764 TRACE( "next instruction rip=%lx\n", context->Rip );
765 TRACE( " rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
766 context->Rax, context->Rbx, context->Rcx, context->Rdx );
767 TRACE( " rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
768 context->Rsi, context->Rdi, context->Rbp, context->Rsp );
769 TRACE( " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n",
770 context->R8, context->R9, context->R10, context->R11 );
771 TRACE( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
772 context->R12, context->R13, context->R14, context->R15 );
774 return EXCEPTION_CONTINUE_EXECUTION;
777 return EXCEPTION_CONTINUE_SEARCH;
780 #endif /* __x86_64__ */