2007-03-06 11:59:18 +00:00
|
|
|
/*
|
|
|
|
* Unit test suite for ntdll exceptions
|
|
|
|
*
|
|
|
|
* Copyright 2005 Alexandre Julliard
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2008-12-12 23:42:40 +00:00
|
|
|
#ifndef _WIN32_WINNT
|
|
|
|
#define _WIN32_WINNT 0x500 /* For NTSTATUS */
|
|
|
|
#endif
|
|
|
|
|
2010-03-15 22:13:19 +00:00
|
|
|
#define NONAMELESSUNION
|
|
|
|
#define NONAMELESSSTRUCT
|
2007-03-06 11:59:18 +00:00
|
|
|
#include "ntstatus.h"
|
|
|
|
#define WIN32_NO_STATUS
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winnt.h"
|
|
|
|
#include "winreg.h"
|
|
|
|
#include "winternl.h"
|
2008-05-12 08:33:26 +00:00
|
|
|
#include "wine/exception.h"
|
2007-03-06 11:59:18 +00:00
|
|
|
#include "wine/test.h"
|
|
|
|
|
2010-03-15 22:13:19 +00:00
|
|
|
static void *code_mem;
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
|
2008-05-12 08:33:26 +00:00
|
|
|
static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
|
|
|
|
static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
|
|
|
|
static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
|
|
|
|
static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
|
|
|
|
static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler);
|
|
|
|
static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
|
|
|
|
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
|
2010-03-15 22:13:19 +00:00
|
|
|
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
|
|
|
|
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
2010-03-15 22:13:19 +00:00
|
|
|
|
|
|
|
#ifdef __i386__
|
|
|
|
|
|
|
|
#ifndef __WINE_WINTRNL_H
|
|
|
|
#define ProcessExecuteFlags 0x22
|
|
|
|
#define MEM_EXECUTE_OPTION_DISABLE 0x01
|
|
|
|
#define MEM_EXECUTE_OPTION_ENABLE 0x02
|
|
|
|
#define MEM_EXECUTE_OPTION_PERMANENT 0x08
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int my_argc;
|
|
|
|
static char** my_argv;
|
|
|
|
static int test_stage;
|
2007-03-06 11:59:18 +00:00
|
|
|
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
static BOOL is_wow64;
|
|
|
|
|
2007-03-06 11:59:18 +00:00
|
|
|
/* Test various instruction combinations that cause a protection fault on the i386,
|
|
|
|
* and check what the resulting exception looks like.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const struct exception
|
|
|
|
{
|
2011-10-03 19:29:29 +00:00
|
|
|
BYTE code[18]; /* asm code */
|
|
|
|
BYTE offset; /* offset of faulting instruction */
|
|
|
|
BYTE length; /* length of faulting instruction */
|
|
|
|
BOOL wow64_broken; /* broken on Wow64, should be skipped */
|
|
|
|
NTSTATUS status; /* expected status code */
|
|
|
|
DWORD nb_params; /* expected number of parameters */
|
|
|
|
DWORD params[4]; /* expected parameters */
|
|
|
|
NTSTATUS alt_status; /* alternative status code */
|
|
|
|
DWORD alt_nb_params; /* alternative number of parameters */
|
|
|
|
DWORD alt_params[4]; /* alternative parameters */
|
2007-03-06 11:59:18 +00:00
|
|
|
} exceptions[] =
|
|
|
|
{
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* 0 */
|
2007-03-06 11:59:18 +00:00
|
|
|
/* test some privileged instructions */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xfb, 0xc3 }, /* 0: sti; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0x6c, 0xc3 }, /* 1: insb (%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0x6d, 0xc3 }, /* 2: insl (%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0x6e, 0xc3 }, /* 3: outsb (%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0x6f, 0xc3 }, /* 4: outsl (%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
|
|
|
/* 5 */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xe4, 0x11, 0xc3 }, /* 5: inb $0x11,%al; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 2, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xe5, 0x11, 0xc3 }, /* 6: inl $0x11,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 2, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xe6, 0x11, 0xc3 }, /* 7: outb %al,$0x11; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 2, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xe7, 0x11, 0xc3 }, /* 8: outl %eax,$0x11; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 2, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xed, 0xc3 }, /* 9: inl (%dx),%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
|
|
|
/* 10 */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xee, 0xc3 }, /* 10: outb %al,(%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xef, 0xc3 }, /* 11: outl %eax,(%dx); ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xf4, 0xc3 }, /* 12: hlt; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xfa, 0xc3 }, /* 13: cli; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 1, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test long jump to invalid selector */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xea, 0, 0, 0, 0, 0, 0, 0xc3 }, /* 14: ljmp $0,$0; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 7, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* 15 */
|
2007-03-06 11:59:18 +00:00
|
|
|
/* test iret to invalid selector */
|
|
|
|
{ { 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0xcf, 0x83, 0xc4, 0x0c, 0xc3 },
|
2008-12-12 23:42:40 +00:00
|
|
|
/* 15: pushl $0; pushl $0; pushl $0; iret; addl $12,%esp; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
6, 1, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test loading an invalid selector */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0xb8, 0xef, 0xbe, 0x00, 0x00, 0x8e, 0xe8, 0xc3 }, /* 16: mov $beef,%ax; mov %ax,%gs; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
5, 2, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xbee8 } }, /* 0xbee8 or 0xffffffff */
|
2007-03-06 11:59:18 +00:00
|
|
|
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* test accessing a zero selector (%es broken on Wow64) */
|
2007-03-06 11:59:18 +00:00
|
|
|
{ { 0x06, 0x31, 0xc0, 0x8e, 0xc0, 0x26, 0xa1, 0, 0, 0, 0, 0x07, 0xc3 },
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* push %es; xor %eax,%eax; mov %ax,%es; mov %es:(0),%ax; pop %es; ret */
|
|
|
|
5, 6, TRUE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
|
|
|
{ { 0x0f, 0xa8, 0x31, 0xc0, 0x8e, 0xe8, 0x65, 0xa1, 0, 0, 0, 0, 0x0f, 0xa9, 0xc3 },
|
|
|
|
/* push %gs; xor %eax,%eax; mov %ax,%gs; mov %gs:(0),%ax; pop %gs; ret */
|
|
|
|
6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test moving %cs -> %ss */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0e, 0x17, 0x58, 0xc3 }, /* pushl %cs; popl %ss; popl %eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
1, 1, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* 20 */
|
|
|
|
/* test overlong instruction (limit is 15 bytes, 5 on Win7) */
|
2007-03-06 11:59:18 +00:00
|
|
|
{ { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 },
|
2011-10-03 19:29:29 +00:00
|
|
|
0, 16, TRUE, STATUS_ILLEGAL_INSTRUCTION, 0, { 0 },
|
|
|
|
STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2010-03-15 22:13:19 +00:00
|
|
|
{ { 0x64,0x64,0x64,0x64,0xfa,0xc3 },
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, TRUE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test invalid interrupt */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xcd, 0xff, 0xc3 }, /* int $0xff; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 2, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test moves to/from Crx */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x20, 0xc0, 0xc3 }, /* movl %cr0,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x20, 0xe0, 0xc3 }, /* movl %cr4,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
|
|
|
/* 25 */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x22, 0xc0, 0xc3 }, /* movl %eax,%cr0; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x22, 0xe0, 0xc3 }, /* movl %eax,%cr4; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test moves to/from Drx */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x21, 0xc0, 0xc3 }, /* movl %dr0,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x21, 0xc8, 0xc3 }, /* movl %dr1,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x21, 0xf8, 0xc3 }, /* movl %dr7,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
|
|
|
/* 30 */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x23, 0xc0, 0xc3 }, /* movl %eax,%dr0; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x23, 0xc8, 0xc3 }, /* movl %eax,%dr1; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0x0f, 0x23, 0xf8, 0xc3 }, /* movl %eax,%dr7; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test memory reads */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffc,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffc } },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffd,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffd } },
|
|
|
|
/* 35 */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffe,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffe } },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xffffffff,%eax; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
/* test memory writes */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffc; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffc } },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffd; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffd } },
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffe; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffe } },
|
|
|
|
/* 40 */
|
2011-10-03 19:29:29 +00:00
|
|
|
{ { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xffffffff; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } },
|
2008-12-12 23:42:40 +00:00
|
|
|
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/* test exception with cleared %ds and %es (broken on Wow64) */
|
2008-12-12 23:42:40 +00:00
|
|
|
{ { 0x1e, 0x06, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfa, 0x07, 0x1f, 0xc3 },
|
|
|
|
/* push %ds; push %es; xorl %eax,%eax; mov %ax,%ds; mov %ax,%es; cli; pop %es; pop %ds; ret */
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
8, 1, TRUE, STATUS_PRIVILEGED_INSTRUCTION, 0 },
|
Sync advapi32, gdi32, gdiplus, inetmib1, kernel32, mlang, msi, msvcrt, ntdll, oleaut32, rpcrt4, secur32, setupapi, shdocvw, shlwapi, snmpapi, twain_32, urlmon, user32, userenv, usp10, winhttp, wininet, wintrust, ws2_32 winetests to Wine 1.2rc6
svn path=/trunk/; revision=47939
2010-07-04 19:08:47 +00:00
|
|
|
|
|
|
|
{ { 0xf1, 0x90, 0xc3 }, /* icebp; nop; ret */
|
|
|
|
1, 1, FALSE, STATUS_SINGLE_STEP, 0 },
|
2007-03-06 11:59:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int got_exception;
|
2008-05-12 08:33:26 +00:00
|
|
|
static BOOL have_vectored_api;
|
|
|
|
|
|
|
|
static void run_exception_test(void *handler, const void* context,
|
2010-03-15 22:13:19 +00:00
|
|
|
const void *code, unsigned int code_size,
|
|
|
|
DWORD access)
|
2008-05-12 08:33:26 +00:00
|
|
|
{
|
|
|
|
struct {
|
|
|
|
EXCEPTION_REGISTRATION_RECORD frame;
|
|
|
|
const void *context;
|
|
|
|
} exc_frame;
|
|
|
|
void (*func)(void) = code_mem;
|
2010-03-15 22:13:19 +00:00
|
|
|
DWORD oldaccess, oldaccess2;
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
exc_frame.frame.Handler = handler;
|
|
|
|
exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
|
|
|
exc_frame.context = context;
|
|
|
|
|
|
|
|
memcpy(code_mem, code, code_size);
|
2010-03-15 22:13:19 +00:00
|
|
|
if(access)
|
|
|
|
VirtualProtect(code_mem, code_size, access, &oldaccess);
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame;
|
|
|
|
func();
|
|
|
|
pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev;
|
2010-03-15 22:13:19 +00:00
|
|
|
|
|
|
|
if(access)
|
|
|
|
VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2);
|
2008-05-12 08:33:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-12 23:42:40 +00:00
|
|
|
static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
|
2008-05-12 08:33:26 +00:00
|
|
|
{
|
|
|
|
PCONTEXT context = ExceptionInfo->ContextRecord;
|
|
|
|
PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
|
|
|
|
trace("vect. handler %08x addr:%p context.Eip:%x\n", rec->ExceptionCode,
|
|
|
|
rec->ExceptionAddress, context->Eip);
|
|
|
|
|
|
|
|
ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n",
|
|
|
|
rec->ExceptionAddress, (char *)code_mem + 0xb);
|
|
|
|
|
|
|
|
if (pNtCurrentTeb()->Peb->BeingDebugged)
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
ok((void *)context->Eax == pRtlRaiseException ||
|
|
|
|
broken( is_wow64 && context->Eax == 0xf00f00f1 ), /* broken on vista */
|
|
|
|
"debugger managed to modify Eax to %x should be %p\n",
|
2008-05-12 08:33:26 +00:00
|
|
|
context->Eax, pRtlRaiseException);
|
|
|
|
|
|
|
|
/* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT
|
|
|
|
* even if raised by RtlRaiseException
|
|
|
|
*/
|
|
|
|
if(rec->ExceptionCode == EXCEPTION_BREAKPOINT)
|
|
|
|
{
|
2008-12-12 23:42:40 +00:00
|
|
|
ok(context->Eip == (DWORD)code_mem + 0xa ||
|
|
|
|
broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */
|
|
|
|
"Eip at %x instead of %x or %x\n", context->Eip,
|
|
|
|
(DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb);
|
2008-05-12 08:33:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem + 0xb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test if context change is preserved from vectored handler to stack handlers */
|
|
|
|
context->Eax = 0xf00f00f0;
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
trace( "exception: %08x flags:%x addr:%p context: Eip:%x\n",
|
|
|
|
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip );
|
|
|
|
|
|
|
|
ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n",
|
|
|
|
rec->ExceptionAddress, (char *)code_mem + 0xb);
|
|
|
|
|
|
|
|
/* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT
|
|
|
|
* even if raised by RtlRaiseException
|
|
|
|
*/
|
|
|
|
if(rec->ExceptionCode == EXCEPTION_BREAKPOINT)
|
|
|
|
{
|
2008-12-12 23:42:40 +00:00
|
|
|
ok(context->Eip == (DWORD)code_mem + 0xa ||
|
|
|
|
broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */
|
|
|
|
"Eip at %x instead of %x or %x\n", context->Eip,
|
|
|
|
(DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb);
|
2008-05-12 08:33:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok(context->Eip == (DWORD)code_mem + 0xb, "Eip at %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem + 0xb);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(have_vectored_api)
|
|
|
|
ok(context->Eax == 0xf00f00f0, "Eax is %x, should have been set to 0xf00f00f0 in vectored handler\n",
|
|
|
|
context->Eax);
|
|
|
|
|
|
|
|
/* give the debugger a chance to examine the state a second time */
|
|
|
|
/* without the exception handler changing Eip */
|
|
|
|
if (test_stage == 2)
|
|
|
|
return ExceptionContinueSearch;
|
|
|
|
|
|
|
|
/* Eip in context is decreased by 1
|
|
|
|
* Increase it again, else execution will continue in the middle of a instruction */
|
|
|
|
if(rec->ExceptionCode == EXCEPTION_BREAKPOINT && (context->Eip == (DWORD)code_mem + 0xa))
|
|
|
|
context->Eip += 1;
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const BYTE call_one_arg_code[] = {
|
|
|
|
0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */
|
|
|
|
0x50, /* push %eax */
|
|
|
|
0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp),%eax */
|
|
|
|
0xff, 0xd0, /* call *%eax */
|
|
|
|
0x90, /* nop */
|
|
|
|
0x90, /* nop */
|
|
|
|
0x90, /* nop */
|
|
|
|
0x90, /* nop */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void run_rtlraiseexception_test(DWORD exceptioncode)
|
|
|
|
{
|
|
|
|
EXCEPTION_REGISTRATION_RECORD frame;
|
|
|
|
EXCEPTION_RECORD record;
|
|
|
|
PVOID vectored_handler = NULL;
|
|
|
|
|
|
|
|
void (*func)(void* function, EXCEPTION_RECORD* record) = code_mem;
|
|
|
|
|
|
|
|
record.ExceptionCode = exceptioncode;
|
|
|
|
record.ExceptionFlags = 0;
|
|
|
|
record.ExceptionRecord = NULL;
|
|
|
|
record.ExceptionAddress = NULL; /* does not matter, copied return address */
|
|
|
|
record.NumberParameters = 0;
|
|
|
|
|
|
|
|
frame.Handler = rtlraiseexception_handler;
|
|
|
|
frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
|
|
|
|
|
|
|
|
memcpy(code_mem, call_one_arg_code, sizeof(call_one_arg_code));
|
|
|
|
|
|
|
|
pNtCurrentTeb()->Tib.ExceptionList = &frame;
|
|
|
|
if (have_vectored_api)
|
|
|
|
{
|
|
|
|
vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &rtlraiseexception_vectored_handler);
|
|
|
|
ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
func(pRtlRaiseException, &record);
|
2009-05-17 07:05:22 +00:00
|
|
|
ok( record.ExceptionAddress == (char *)code_mem + 0x0b,
|
|
|
|
"address set to %p instead of %p\n", record.ExceptionAddress, (char *)code_mem + 0x0b );
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
if (have_vectored_api)
|
|
|
|
pRtlRemoveVectoredExceptionHandler(vectored_handler);
|
|
|
|
pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_rtlraiseexception(void)
|
|
|
|
{
|
|
|
|
if (!pRtlRaiseException)
|
|
|
|
{
|
|
|
|
skip("RtlRaiseException not found\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test without debugger */
|
|
|
|
run_rtlraiseexception_test(0x12345);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
|
|
|
|
}
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
const struct exception *except = *(const struct exception **)(frame + 1);
|
|
|
|
unsigned int i, entry = except - exceptions;
|
|
|
|
|
|
|
|
got_exception++;
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
trace( "exception %u: %x flags:%x addr:%p\n",
|
|
|
|
entry, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
|
2007-03-06 11:59:18 +00:00
|
|
|
|
2011-10-03 19:29:29 +00:00
|
|
|
ok( rec->ExceptionCode == except->status ||
|
|
|
|
(except->alt_status != 0 && rec->ExceptionCode == except->alt_status),
|
2008-05-12 08:33:26 +00:00
|
|
|
"%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status );
|
|
|
|
ok( rec->ExceptionAddress == (char*)code_mem + except->offset,
|
2007-03-06 11:59:18 +00:00
|
|
|
"%u: Wrong exception address %p/%p\n", entry,
|
2008-05-12 08:33:26 +00:00
|
|
|
rec->ExceptionAddress, (char*)code_mem + except->offset );
|
2007-03-06 11:59:18 +00:00
|
|
|
|
2011-10-03 19:29:29 +00:00
|
|
|
if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status)
|
|
|
|
{
|
|
|
|
ok( rec->NumberParameters == except->nb_params,
|
|
|
|
"%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok( rec->NumberParameters == except->alt_nb_params,
|
|
|
|
"%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params );
|
|
|
|
}
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
/* Most CPUs (except Intel Core apparently) report a segment limit violation */
|
|
|
|
/* instead of page faults for accesses beyond 0xffffffff */
|
|
|
|
if (except->nb_params == 2 && except->params[1] >= 0xfffffffd)
|
|
|
|
{
|
|
|
|
if (rec->ExceptionInformation[0] == 0 && rec->ExceptionInformation[1] == 0xffffffff)
|
|
|
|
goto skip_params;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Seems that both 0xbee8 and 0xfffffffff can be returned in windows */
|
|
|
|
if (except->nb_params == 2 && rec->NumberParameters == 2
|
|
|
|
&& except->params[1] == 0xbee8 && rec->ExceptionInformation[1] == 0xffffffff
|
|
|
|
&& except->params[0] == rec->ExceptionInformation[0])
|
|
|
|
{
|
|
|
|
goto skip_params;
|
|
|
|
}
|
|
|
|
|
2011-10-03 19:29:29 +00:00
|
|
|
if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status)
|
|
|
|
{
|
|
|
|
for (i = 0; i < rec->NumberParameters; i++)
|
|
|
|
ok( rec->ExceptionInformation[i] == except->params[i],
|
|
|
|
"%u: Wrong parameter %d: %lx/%x\n",
|
|
|
|
entry, i, rec->ExceptionInformation[i], except->params[i] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < rec->NumberParameters; i++)
|
|
|
|
ok( rec->ExceptionInformation[i] == except->alt_params[i],
|
|
|
|
"%u: Wrong parameter %d: %lx/%x\n",
|
|
|
|
entry, i, rec->ExceptionInformation[i], except->alt_params[i] );
|
|
|
|
}
|
2007-03-06 11:59:18 +00:00
|
|
|
|
2008-05-12 08:33:26 +00:00
|
|
|
skip_params:
|
2007-03-06 11:59:18 +00:00
|
|
|
/* don't handle exception if it's not the address we expected */
|
2008-05-12 08:33:26 +00:00
|
|
|
if (rec->ExceptionAddress != (char*)code_mem + except->offset) return ExceptionContinueSearch;
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
context->Eip += except->length;
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_prot_fault(void)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(exceptions)/sizeof(exceptions[0]); i++)
|
|
|
|
{
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
if (is_wow64 && exceptions[i].wow64_broken && !strcmp( winetest_platform, "windows" ))
|
|
|
|
{
|
|
|
|
skip( "Exception %u broken on Wow64\n", i );
|
|
|
|
continue;
|
|
|
|
}
|
2007-03-06 11:59:18 +00:00
|
|
|
got_exception = 0;
|
2008-05-12 08:33:26 +00:00
|
|
|
run_exception_test(handler, &exceptions[i], &exceptions[i].code,
|
2010-03-15 22:13:19 +00:00
|
|
|
sizeof(exceptions[i].code), 0);
|
2007-03-06 11:59:18 +00:00
|
|
|
if (!i && !got_exception)
|
|
|
|
{
|
|
|
|
trace( "No exception, assuming win9x, no point in testing further\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ok( got_exception == (exceptions[i].status != 0),
|
|
|
|
"%u: bad exception count %d\n", i, got_exception );
|
|
|
|
}
|
2008-05-12 08:33:26 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 19:29:29 +00:00
|
|
|
struct dbgreg_test {
|
|
|
|
DWORD dr0, dr1, dr2, dr3, dr6, dr7;
|
|
|
|
};
|
|
|
|
|
2008-05-12 08:33:26 +00:00
|
|
|
/* test handling of debug registers */
|
|
|
|
static DWORD dreg_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
2011-10-03 19:29:29 +00:00
|
|
|
const struct dbgreg_test *test = *(const struct dbgreg_test **)(frame + 1);
|
|
|
|
|
2008-05-12 08:33:26 +00:00
|
|
|
context->Eip += 2; /* Skips the popl (%eax) */
|
2011-10-03 19:29:29 +00:00
|
|
|
context->Dr0 = test->dr0;
|
|
|
|
context->Dr1 = test->dr1;
|
|
|
|
context->Dr2 = test->dr2;
|
|
|
|
context->Dr3 = test->dr3;
|
|
|
|
context->Dr6 = test->dr6;
|
|
|
|
context->Dr7 = test->dr7;
|
2008-05-12 08:33:26 +00:00
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
2011-10-03 19:29:29 +00:00
|
|
|
#define CHECK_DEBUG_REG(n, m) \
|
|
|
|
ok((ctx.Dr##n & m) == test->dr##n, "(%d) failed to set debug register " #n " to %x, got %x\n", \
|
|
|
|
test_num, test->dr##n, ctx.Dr##n)
|
|
|
|
|
|
|
|
static void check_debug_registers(int test_num, const struct dbgreg_test *test)
|
|
|
|
{
|
|
|
|
CONTEXT ctx;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
|
|
|
status = pNtGetContextThread(GetCurrentThread(), &ctx);
|
|
|
|
ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status);
|
|
|
|
|
|
|
|
CHECK_DEBUG_REG(0, ~0);
|
|
|
|
CHECK_DEBUG_REG(1, ~0);
|
|
|
|
CHECK_DEBUG_REG(2, ~0);
|
|
|
|
CHECK_DEBUG_REG(3, ~0);
|
|
|
|
CHECK_DEBUG_REG(6, 0x0f);
|
|
|
|
CHECK_DEBUG_REG(7, ~0xdc00);
|
|
|
|
}
|
|
|
|
|
2008-05-12 08:33:26 +00:00
|
|
|
static const BYTE segfault_code[5] = {
|
|
|
|
0x31, 0xc0, /* xor %eax,%eax */
|
|
|
|
0x8f, 0x00, /* popl (%eax) - cause exception */
|
|
|
|
0xc3 /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* test the single step exception behaviour */
|
|
|
|
static DWORD single_step_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
got_exception++;
|
|
|
|
ok (!(context->EFlags & 0x100), "eflags has single stepping bit set\n");
|
|
|
|
|
|
|
|
if( got_exception < 3)
|
|
|
|
context->EFlags |= 0x100; /* single step until popf instruction */
|
|
|
|
else {
|
|
|
|
/* show that the last single step exception on the popf instruction
|
|
|
|
* (which removed the TF bit), still is a EXCEPTION_SINGLE_STEP exception */
|
|
|
|
ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP,
|
|
|
|
"exception is not EXCEPTION_SINGLE_STEP: %x\n", rec->ExceptionCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const BYTE single_stepcode[] = {
|
|
|
|
0x9c, /* pushf */
|
|
|
|
0x58, /* pop %eax */
|
|
|
|
0x0d,0,1,0,0, /* or $0x100,%eax */
|
|
|
|
0x50, /* push %eax */
|
|
|
|
0x9d, /* popf */
|
|
|
|
0x35,0,1,0,0, /* xor $0x100,%eax */
|
|
|
|
0x50, /* push %eax */
|
|
|
|
0x9d, /* popf */
|
|
|
|
0xc3
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Test the alignment check (AC) flag handling. */
|
|
|
|
static const BYTE align_check_code[] = {
|
|
|
|
0x55, /* push %ebp */
|
|
|
|
0x89,0xe5, /* mov %esp,%ebp */
|
|
|
|
0x9c, /* pushf */
|
|
|
|
0x58, /* pop %eax */
|
|
|
|
0x0d,0,0,4,0, /* or $0x40000,%eax */
|
|
|
|
0x50, /* push %eax */
|
|
|
|
0x9d, /* popf */
|
|
|
|
0x89,0xe0, /* mov %esp, %eax */
|
|
|
|
0x8b,0x40,0x1, /* mov 0x1(%eax), %eax - cause exception */
|
|
|
|
0x9c, /* pushf */
|
|
|
|
0x58, /* pop %eax */
|
|
|
|
0x35,0,0,4,0, /* xor $0x40000,%eax */
|
|
|
|
0x50, /* push %eax */
|
|
|
|
0x9d, /* popf */
|
|
|
|
0x5d, /* pop %ebp */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD align_check_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
ok (!(context->EFlags & 0x40000), "eflags has AC bit set\n");
|
|
|
|
got_exception++;
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test the direction flag handling. */
|
|
|
|
static const BYTE direction_flag_code[] = {
|
|
|
|
0x55, /* push %ebp */
|
|
|
|
0x89,0xe5, /* mov %esp,%ebp */
|
|
|
|
0xfd, /* std */
|
|
|
|
0xfa, /* cli - cause exception */
|
|
|
|
0x5d, /* pop %ebp */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD direction_flag_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
#ifdef __GNUC__
|
|
|
|
unsigned int flags;
|
2008-12-12 23:42:40 +00:00
|
|
|
__asm__("pushfl; popl %0; cld" : "=r" (flags) );
|
2008-05-12 08:33:26 +00:00
|
|
|
/* older windows versions don't clear DF properly so don't test */
|
|
|
|
if (flags & 0x400) trace( "eflags has DF bit set\n" );
|
|
|
|
#endif
|
|
|
|
ok( context->EFlags & 0x400, "context eflags has DF bit cleared\n" );
|
|
|
|
got_exception++;
|
|
|
|
context->Eip++; /* skip cli */
|
2008-12-12 23:42:40 +00:00
|
|
|
context->EFlags &= ~0x400; /* make sure it is cleared on return */
|
2008-05-12 08:33:26 +00:00
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test single stepping over hardware breakpoint */
|
|
|
|
static DWORD bpx_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
got_exception++;
|
|
|
|
ok( rec->ExceptionCode == EXCEPTION_SINGLE_STEP,
|
|
|
|
"wrong exception code: %x\n", rec->ExceptionCode);
|
|
|
|
|
|
|
|
if(got_exception == 1) {
|
|
|
|
/* hw bp exception on first nop */
|
|
|
|
ok( context->Eip == (DWORD)code_mem, "eip is wrong: %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem);
|
|
|
|
ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n");
|
|
|
|
ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n");
|
|
|
|
context->Dr0 = context->Dr0 + 1; /* set hw bp again on next instruction */
|
|
|
|
context->EFlags |= 0x100; /* enable single stepping */
|
|
|
|
} else if( got_exception == 2) {
|
|
|
|
/* single step exception on second nop */
|
|
|
|
ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem + 1);
|
|
|
|
ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
|
|
|
|
/* depending on the win version the B0 bit is already set here as well
|
|
|
|
ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n"); */
|
|
|
|
context->EFlags |= 0x100;
|
|
|
|
} else if( got_exception == 3) {
|
|
|
|
/* hw bp exception on second nop */
|
|
|
|
ok( context->Eip == (DWORD)code_mem + 1, "eip is wrong: %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem + 1);
|
|
|
|
ok( (context->Dr6 & 0xf) == 1, "B0 flag is not set in Dr6\n");
|
|
|
|
ok( !(context->Dr6 & 0x4000), "BS flag is set in Dr6\n");
|
|
|
|
context->Dr0 = 0; /* clear breakpoint */
|
|
|
|
context->EFlags |= 0x100;
|
|
|
|
} else {
|
|
|
|
/* single step exception on ret */
|
|
|
|
ok( context->Eip == (DWORD)code_mem + 2, "eip is wrong: %x instead of %x\n",
|
|
|
|
context->Eip, (DWORD)code_mem + 2);
|
|
|
|
ok( (context->Dr6 & 0xf) == 0, "B0...3 flags in Dr6 shouldn't be set\n");
|
|
|
|
ok( (context->Dr6 & 0x4000), "BS flag is not set in Dr6\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
context->Dr6 = 0; /* clear status register */
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const BYTE dummy_code[] = { 0x90, 0x90, 0xc3 }; /* nop, nop, ret */
|
|
|
|
|
|
|
|
/* test int3 handling */
|
|
|
|
static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
ok( rec->ExceptionAddress == code_mem, "exception address not at: %p, but at %p\n",
|
|
|
|
code_mem, rec->ExceptionAddress);
|
|
|
|
ok( context->Eip == (DWORD)code_mem, "eip not at: %p, but at %#x\n", code_mem, context->Eip);
|
|
|
|
if(context->Eip == (DWORD)code_mem) context->Eip++; /* skip breakpoint */
|
|
|
|
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */
|
|
|
|
|
|
|
|
|
|
|
|
static void test_exceptions(void)
|
|
|
|
{
|
|
|
|
CONTEXT ctx;
|
|
|
|
NTSTATUS res;
|
2011-10-03 19:29:29 +00:00
|
|
|
struct dbgreg_test dreg_test;
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
if (!pNtGetContextThread || !pNtSetContextThread)
|
|
|
|
{
|
|
|
|
skip( "NtGetContextThread/NtSetContextThread not found\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test handling of debug registers */
|
2011-10-03 19:29:29 +00:00
|
|
|
memset(&dreg_test, 0, sizeof(dreg_test));
|
|
|
|
|
|
|
|
dreg_test.dr0 = 0x42424240;
|
|
|
|
dreg_test.dr2 = 0x126bb070;
|
|
|
|
dreg_test.dr3 = 0x0badbad0;
|
|
|
|
dreg_test.dr7 = 0xffff0115;
|
|
|
|
run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0);
|
|
|
|
check_debug_registers(1, &dreg_test);
|
|
|
|
|
|
|
|
dreg_test.dr0 = 0x42424242;
|
|
|
|
dreg_test.dr2 = 0x100f0fe7;
|
|
|
|
dreg_test.dr3 = 0x0abebabe;
|
|
|
|
dreg_test.dr7 = 0x115;
|
|
|
|
run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0);
|
|
|
|
check_debug_registers(2, &dreg_test);
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
/* test single stepping behavior */
|
|
|
|
got_exception = 0;
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(single_step_handler, NULL, &single_stepcode, sizeof(single_stepcode), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
ok(got_exception == 3, "expected 3 single step exceptions, got %d\n", got_exception);
|
|
|
|
|
|
|
|
/* test alignment exceptions */
|
|
|
|
got_exception = 0;
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(align_check_handler, NULL, align_check_code, sizeof(align_check_code), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
ok(got_exception == 0, "got %d alignment faults, expected 0\n", got_exception);
|
|
|
|
|
|
|
|
/* test direction flag */
|
|
|
|
got_exception = 0;
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(direction_flag_handler, NULL, direction_flag_code, sizeof(direction_flag_code), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
ok(got_exception == 1, "got %d exceptions, expected 1\n", got_exception);
|
|
|
|
|
|
|
|
/* test single stepping over hardware breakpoint */
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
ctx.Dr0 = (DWORD) code_mem; /* set hw bp on first nop */
|
|
|
|
ctx.Dr7 = 3;
|
|
|
|
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
|
|
|
|
res = pNtSetContextThread( GetCurrentThread(), &ctx);
|
2011-10-03 19:29:29 +00:00
|
|
|
ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res);
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
got_exception = 0;
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
ok( got_exception == 4,"expected 4 exceptions, got %d\n", got_exception);
|
|
|
|
|
|
|
|
/* test int3 handling */
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void test_debugger(void)
|
|
|
|
{
|
|
|
|
char cmdline[MAX_PATH];
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
STARTUPINFO si = { 0 };
|
|
|
|
DEBUG_EVENT de;
|
|
|
|
DWORD continuestatus;
|
|
|
|
PVOID code_mem_address = NULL;
|
|
|
|
NTSTATUS status;
|
|
|
|
SIZE_T size_read;
|
|
|
|
BOOL ret;
|
|
|
|
int counter = 0;
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
|
|
|
|
if(!pNtGetContextThread || !pNtSetContextThread || !pNtReadVirtualMemory || !pNtTerminateProcess)
|
|
|
|
{
|
2010-03-15 22:13:19 +00:00
|
|
|
skip("NtGetContextThread, NtSetContextThread, NtReadVirtualMemory or NtTerminateProcess not found\n");
|
2008-05-12 08:33:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage);
|
|
|
|
ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi);
|
|
|
|
ok(ret, "could not create child process error: %u\n", GetLastError());
|
|
|
|
if (!ret)
|
|
|
|
return;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
continuestatus = DBG_CONTINUE;
|
|
|
|
ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n");
|
|
|
|
|
|
|
|
if (de.dwThreadId != pi.dwThreadId)
|
|
|
|
{
|
|
|
|
trace("event %d not coming from main thread, ignoring\n", de.dwDebugEventCode);
|
|
|
|
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
|
|
|
|
{
|
|
|
|
if(de.u.CreateProcessInfo.lpBaseOfImage != pNtCurrentTeb()->Peb->ImageBaseAddress)
|
|
|
|
{
|
|
|
|
skip("child process loaded at different address, terminating it\n");
|
|
|
|
pNtTerminateProcess(pi.hProcess, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
|
|
|
|
{
|
|
|
|
CONTEXT ctx;
|
|
|
|
int stage;
|
|
|
|
|
|
|
|
counter++;
|
|
|
|
status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address,
|
|
|
|
sizeof(code_mem_address), &size_read);
|
|
|
|
ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
|
|
|
|
status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage,
|
|
|
|
sizeof(stage), &size_read);
|
|
|
|
ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status);
|
|
|
|
|
|
|
|
ctx.ContextFlags = CONTEXT_FULL;
|
|
|
|
status = pNtGetContextThread(pi.hThread, &ctx);
|
|
|
|
ok(!status, "NtGetContextThread failed with 0x%x\n", status);
|
|
|
|
|
|
|
|
trace("exception 0x%x at %p firstchance=%d Eip=0x%x, Eax=0x%x\n",
|
|
|
|
de.u.Exception.ExceptionRecord.ExceptionCode,
|
|
|
|
de.u.Exception.ExceptionRecord.ExceptionAddress, de.u.Exception.dwFirstChance, ctx.Eip, ctx.Eax);
|
|
|
|
|
|
|
|
if (counter > 100)
|
|
|
|
{
|
2011-10-03 19:29:29 +00:00
|
|
|
ok(FALSE, "got way too many exceptions, probably caught in a infinite loop, terminating child\n");
|
2008-05-12 08:33:26 +00:00
|
|
|
pNtTerminateProcess(pi.hProcess, 1);
|
|
|
|
}
|
|
|
|
else if (counter >= 2) /* skip startup breakpoint */
|
|
|
|
{
|
|
|
|
if (stage == 1)
|
|
|
|
{
|
|
|
|
ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at %x instead of %p\n",
|
|
|
|
ctx.Eip, (char *)code_mem_address + 0xb);
|
|
|
|
/* setting the context from debugger does not affect the context, the exception handlers gets */
|
|
|
|
/* uncomment once wine is fixed */
|
|
|
|
/* ctx.Eip = 0x12345; */
|
|
|
|
ctx.Eax = 0xf00f00f1;
|
|
|
|
|
|
|
|
/* let the debuggee handle the exception */
|
|
|
|
continuestatus = DBG_EXCEPTION_NOT_HANDLED;
|
|
|
|
}
|
|
|
|
else if (stage == 2)
|
|
|
|
{
|
|
|
|
if (de.u.Exception.dwFirstChance)
|
|
|
|
{
|
|
|
|
/* debugger gets first chance exception with unmodified ctx.Eip */
|
|
|
|
ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n",
|
|
|
|
ctx.Eip, (char *)code_mem_address + 0xb);
|
|
|
|
|
|
|
|
/* setting the context from debugger does not affect the context, the exception handlers gets */
|
|
|
|
/* uncomment once wine is fixed */
|
|
|
|
/* ctx.Eip = 0x12345; */
|
|
|
|
ctx.Eax = 0xf00f00f1;
|
|
|
|
|
|
|
|
/* pass exception to debuggee
|
|
|
|
* exception will not be handled and
|
|
|
|
* a second chance exception will be raised */
|
|
|
|
continuestatus = DBG_EXCEPTION_NOT_HANDLED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* debugger gets context after exception handler has played with it */
|
|
|
|
/* ctx.Eip is the same value the exception handler got */
|
|
|
|
if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
|
|
|
|
{
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
ok((char *)ctx.Eip == (char *)code_mem_address + 0xa ||
|
|
|
|
broken(is_wow64 && (char *)ctx.Eip == (char *)code_mem_address + 0xb),
|
|
|
|
"Eip at 0x%x instead of %p\n",
|
2008-05-12 08:33:26 +00:00
|
|
|
ctx.Eip, (char *)code_mem_address + 0xa);
|
|
|
|
/* need to fixup Eip for debuggee */
|
|
|
|
if ((char *)ctx.Eip == (char *)code_mem_address + 0xa)
|
|
|
|
ctx.Eip += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at 0x%x instead of %p\n",
|
|
|
|
ctx.Eip, (char *)code_mem_address + 0xb);
|
|
|
|
/* here we handle exception */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok(FALSE, "unexpected stage %x\n", stage);
|
|
|
|
|
|
|
|
status = pNtSetContextThread(pi.hThread, &ctx);
|
|
|
|
ok(!status, "NtSetContextThread failed with 0x%x\n", status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus);
|
|
|
|
|
|
|
|
} while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
|
|
|
|
|
|
|
|
winetest_wait_child_process( pi.hProcess );
|
2011-10-03 19:29:29 +00:00
|
|
|
ret = CloseHandle(pi.hThread);
|
|
|
|
ok(ret, "error %u\n", GetLastError());
|
|
|
|
ret = CloseHandle(pi.hProcess);
|
|
|
|
ok(ret, "error %u\n", GetLastError());
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
|
|
|
{
|
|
|
|
int *stage = *(int **)(frame + 1);
|
|
|
|
|
|
|
|
got_exception++;
|
|
|
|
|
|
|
|
if( *stage == 1) {
|
|
|
|
/* fault while executing sse instruction */
|
|
|
|
context->Eip += 3; /* skip addps */
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stage 2 - divide by zero fault */
|
|
|
|
if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
|
|
|
|
skip("system doesn't support SIMD exceptions\n");
|
|
|
|
else {
|
|
|
|
ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS,
|
|
|
|
"exception code: %#x, should be %#x\n",
|
|
|
|
rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS);
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
ok( rec->NumberParameters == 1 || broken(is_wow64 && rec->NumberParameters == 2),
|
|
|
|
"# of params: %i, should be 1\n",
|
2008-05-12 08:33:26 +00:00
|
|
|
rec->NumberParameters);
|
|
|
|
if( rec->NumberParameters == 1 )
|
|
|
|
ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be 0\n", rec->ExceptionInformation[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
context->Eip += 3; /* skip divps */
|
|
|
|
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const BYTE simd_exception_test[] = {
|
|
|
|
0x83, 0xec, 0x4, /* sub $0x4, %esp */
|
|
|
|
0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */
|
|
|
|
0x66, 0x81, 0x24, 0x24, 0xff, 0xfd, /* andw $0xfdff,(%esp) * enable divide by */
|
|
|
|
0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * zero exceptions */
|
|
|
|
0x6a, 0x01, /* push $0x1 */
|
|
|
|
0x6a, 0x01, /* push $0x1 */
|
|
|
|
0x6a, 0x01, /* push $0x1 */
|
|
|
|
0x6a, 0x01, /* push $0x1 */
|
|
|
|
0x0f, 0x10, 0x0c, 0x24, /* movups (%esp),%xmm1 * fill dividend */
|
|
|
|
0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */
|
|
|
|
0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */
|
|
|
|
0x83, 0xc4, 0x10, /* add $0x10,%esp */
|
|
|
|
0x66, 0x81, 0x0c, 0x24, 0x00, 0x02, /* orw $0x200,(%esp) * disable exceptions */
|
|
|
|
0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */
|
|
|
|
0x83, 0xc4, 0x04, /* add $0x4,%esp */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const BYTE sse_check[] = {
|
|
|
|
0x0f, 0x58, 0xc8, /* addps %xmm0,%xmm1 */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static void test_simd_exceptions(void)
|
|
|
|
{
|
|
|
|
int stage;
|
|
|
|
|
|
|
|
/* test if CPU & OS can do sse */
|
|
|
|
stage = 1;
|
|
|
|
got_exception = 0;
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(simd_fault_handler, &stage, sse_check, sizeof(sse_check), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
if(got_exception) {
|
|
|
|
skip("system doesn't support SSE\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a SIMD exception */
|
|
|
|
stage = 2;
|
|
|
|
got_exception = 0;
|
|
|
|
run_exception_test(simd_fault_handler, &stage, simd_exception_test,
|
2010-03-15 22:13:19 +00:00
|
|
|
sizeof(simd_exception_test), 0);
|
2008-05-12 08:33:26 +00:00
|
|
|
ok( got_exception == 1, "got exception: %i, should be 1\n", got_exception);
|
2007-03-06 11:59:18 +00:00
|
|
|
}
|
|
|
|
|
2009-05-17 07:05:22 +00:00
|
|
|
struct fpu_exception_info
|
|
|
|
{
|
|
|
|
DWORD exception_code;
|
|
|
|
DWORD exception_offset;
|
|
|
|
DWORD eip_offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD fpu_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
|
|
|
|
{
|
|
|
|
struct fpu_exception_info *info = *(struct fpu_exception_info **)(frame + 1);
|
|
|
|
|
|
|
|
info->exception_code = rec->ExceptionCode;
|
|
|
|
info->exception_offset = (BYTE *)rec->ExceptionAddress - (BYTE *)code_mem;
|
|
|
|
info->eip_offset = context->Eip - (DWORD)code_mem;
|
|
|
|
|
|
|
|
++context->Eip;
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_fpu_exceptions(void)
|
|
|
|
{
|
|
|
|
static const BYTE fpu_exception_test_ie[] =
|
|
|
|
{
|
|
|
|
0x83, 0xec, 0x04, /* sub $0x4,%esp */
|
|
|
|
0x66, 0xc7, 0x04, 0x24, 0xfe, 0x03, /* movw $0x3fe,(%esp) */
|
|
|
|
0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */
|
|
|
|
0xd9, 0x2c, 0x24, /* fldcw (%esp) */
|
|
|
|
0xd9, 0xee, /* fldz */
|
|
|
|
0xd9, 0xe8, /* fld1 */
|
|
|
|
0xde, 0xf1, /* fdivp */
|
|
|
|
0xdd, 0xd8, /* fstp %st(0) */
|
|
|
|
0xdd, 0xd8, /* fstp %st(0) */
|
|
|
|
0x9b, /* fwait */
|
|
|
|
0xdb, 0xe2, /* fnclex */
|
|
|
|
0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */
|
|
|
|
0x83, 0xc4, 0x04, /* add $0x4,%esp */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const BYTE fpu_exception_test_de[] =
|
|
|
|
{
|
|
|
|
0x83, 0xec, 0x04, /* sub $0x4,%esp */
|
|
|
|
0x66, 0xc7, 0x04, 0x24, 0xfb, 0x03, /* movw $0x3fb,(%esp) */
|
|
|
|
0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */
|
|
|
|
0xd9, 0x2c, 0x24, /* fldcw (%esp) */
|
|
|
|
0xdd, 0xd8, /* fstp %st(0) */
|
|
|
|
0xd9, 0xee, /* fldz */
|
|
|
|
0xd9, 0xe8, /* fld1 */
|
|
|
|
0xde, 0xf1, /* fdivp */
|
|
|
|
0x9b, /* fwait */
|
|
|
|
0xdb, 0xe2, /* fnclex */
|
|
|
|
0xdd, 0xd8, /* fstp %st(0) */
|
|
|
|
0xdd, 0xd8, /* fstp %st(0) */
|
|
|
|
0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */
|
|
|
|
0x83, 0xc4, 0x04, /* add $0x4,%esp */
|
|
|
|
0xc3, /* ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct fpu_exception_info info;
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(fpu_exception_handler, &info, fpu_exception_test_ie, sizeof(fpu_exception_test_ie), 0);
|
2009-05-17 07:05:22 +00:00
|
|
|
ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK,
|
|
|
|
"Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n", info.exception_code);
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
ok(info.exception_offset == 0x19 ||
|
|
|
|
broken( is_wow64 && info.exception_offset == info.eip_offset ),
|
|
|
|
"Got exception offset %#x, expected 0x19\n", info.exception_offset);
|
2009-05-17 07:05:22 +00:00
|
|
|
ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n", info.eip_offset);
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
2010-03-15 22:13:19 +00:00
|
|
|
run_exception_test(fpu_exception_handler, &info, fpu_exception_test_de, sizeof(fpu_exception_test_de), 0);
|
2009-05-17 07:05:22 +00:00
|
|
|
ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
|
|
|
"Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n", info.exception_code);
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
ok(info.exception_offset == 0x17 ||
|
|
|
|
broken( is_wow64 && info.exception_offset == info.eip_offset ),
|
|
|
|
"Got exception offset %#x, expected 0x17\n", info.exception_offset);
|
2009-05-17 07:05:22 +00:00
|
|
|
ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n", info.eip_offset);
|
|
|
|
}
|
|
|
|
|
2010-03-15 22:13:19 +00:00
|
|
|
struct dpe_exception_info {
|
|
|
|
BOOL exception_caught;
|
|
|
|
DWORD exception_info;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD dpe_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
|
|
|
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
|
|
|
|
{
|
|
|
|
DWORD old_prot;
|
|
|
|
struct dpe_exception_info *info = *(struct dpe_exception_info **)(frame + 1);
|
|
|
|
|
|
|
|
ok(rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION,
|
|
|
|
"Exception code %08x\n", rec->ExceptionCode);
|
|
|
|
ok(rec->NumberParameters == 2,
|
|
|
|
"Parameter count: %d\n", rec->NumberParameters);
|
|
|
|
ok((LPVOID)rec->ExceptionInformation[1] == code_mem,
|
|
|
|
"Exception address: %p, expected %p\n",
|
|
|
|
(LPVOID)rec->ExceptionInformation[1], code_mem);
|
|
|
|
|
|
|
|
info->exception_info = rec->ExceptionInformation[0];
|
|
|
|
info->exception_caught = TRUE;
|
|
|
|
|
|
|
|
VirtualProtect(code_mem, 1, PAGE_EXECUTE_READWRITE, &old_prot);
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_dpe_exceptions(void)
|
|
|
|
{
|
|
|
|
static char single_ret[] = {0xC3};
|
|
|
|
struct dpe_exception_info info;
|
|
|
|
NTSTATUS stat;
|
|
|
|
BOOL has_hw_support;
|
|
|
|
BOOL is_permanent = FALSE, can_test_without = TRUE, can_test_with = TRUE;
|
|
|
|
DWORD val;
|
|
|
|
ULONG len;
|
|
|
|
|
|
|
|
/* Query DEP with len to small */
|
|
|
|
stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val - 1, &len);
|
|
|
|
if(stat == STATUS_INVALID_INFO_CLASS)
|
|
|
|
{
|
|
|
|
skip("This software platform does not support DEP\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ok(stat == STATUS_INFO_LENGTH_MISMATCH, "buffer too small: %08x\n", stat);
|
|
|
|
|
|
|
|
/* Query DEP */
|
|
|
|
stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val, &len);
|
|
|
|
ok(stat == STATUS_SUCCESS, "querying DEP: status %08x\n", stat);
|
|
|
|
if(stat == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
ok(len == sizeof val, "returned length: %d\n", len);
|
|
|
|
if(val & MEM_EXECUTE_OPTION_PERMANENT)
|
|
|
|
{
|
|
|
|
skip("toggling DEP impossible - status locked\n");
|
|
|
|
is_permanent = TRUE;
|
|
|
|
if(val & MEM_EXECUTE_OPTION_DISABLE)
|
|
|
|
can_test_without = FALSE;
|
|
|
|
else
|
|
|
|
can_test_with = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!is_permanent)
|
|
|
|
{
|
|
|
|
/* Enable DEP */
|
|
|
|
val = MEM_EXECUTE_OPTION_DISABLE;
|
|
|
|
stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
|
|
|
|
ok(stat == STATUS_SUCCESS, "enabling DEP: status %08x\n", stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(can_test_with)
|
|
|
|
{
|
|
|
|
/* Try access to locked page with DEP on*/
|
|
|
|
info.exception_caught = FALSE;
|
|
|
|
run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS);
|
|
|
|
ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n");
|
|
|
|
ok(info.exception_info == EXCEPTION_READ_FAULT ||
|
|
|
|
info.exception_info == EXCEPTION_EXECUTE_FAULT,
|
|
|
|
"Access violation type: %08x\n", (unsigned)info.exception_info);
|
|
|
|
has_hw_support = info.exception_info == EXCEPTION_EXECUTE_FAULT;
|
|
|
|
trace("DEP hardware support: %s\n", has_hw_support?"Yes":"No");
|
|
|
|
|
|
|
|
/* Try execution of data with DEP on*/
|
|
|
|
info.exception_caught = FALSE;
|
|
|
|
run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE);
|
|
|
|
if(has_hw_support)
|
|
|
|
{
|
|
|
|
ok(info.exception_caught == TRUE, "Execution of data memory succeeded\n");
|
|
|
|
ok(info.exception_info == EXCEPTION_EXECUTE_FAULT,
|
|
|
|
"Access violation type: %08x\n", (unsigned)info.exception_info);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok(info.exception_caught == FALSE, "Execution trapped without hardware support\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip("DEP is in AlwaysOff state\n");
|
|
|
|
|
|
|
|
if(!is_permanent)
|
|
|
|
{
|
|
|
|
/* Disable DEP */
|
|
|
|
val = MEM_EXECUTE_OPTION_ENABLE;
|
|
|
|
stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
|
|
|
|
ok(stat == STATUS_SUCCESS, "disabling DEP: status %08x\n", stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* page is read without exec here */
|
|
|
|
if(can_test_without)
|
|
|
|
{
|
|
|
|
/* Try execution of data with DEP off */
|
|
|
|
info.exception_caught = FALSE;
|
|
|
|
run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_READWRITE);
|
|
|
|
ok(info.exception_caught == FALSE, "Execution trapped with DEP turned off\n");
|
|
|
|
|
|
|
|
/* Try access to locked page with DEP off - error code is different than
|
|
|
|
with hardware DEP on */
|
|
|
|
info.exception_caught = FALSE;
|
|
|
|
run_exception_test(dpe_exception_handler, &info, single_ret, sizeof(single_ret), PAGE_NOACCESS);
|
|
|
|
ok(info.exception_caught == TRUE, "Execution of disabled memory succeeded\n");
|
|
|
|
ok(info.exception_info == EXCEPTION_READ_FAULT,
|
|
|
|
"Access violation type: %08x\n", (unsigned)info.exception_info);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip("DEP is in AlwaysOn state\n");
|
|
|
|
|
|
|
|
if(!is_permanent)
|
|
|
|
{
|
|
|
|
/* Turn off DEP permanently */
|
|
|
|
val = MEM_EXECUTE_OPTION_ENABLE | MEM_EXECUTE_OPTION_PERMANENT;
|
|
|
|
stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
|
|
|
|
ok(stat == STATUS_SUCCESS, "disabling DEP permanently: status %08x\n", stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to turn off DEP */
|
|
|
|
val = MEM_EXECUTE_OPTION_ENABLE;
|
|
|
|
stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
|
|
|
|
ok(stat == STATUS_ACCESS_DENIED, "disabling DEP while permanent: status %08x\n", stat);
|
|
|
|
|
|
|
|
/* Try to turn on DEP */
|
|
|
|
val = MEM_EXECUTE_OPTION_DISABLE;
|
|
|
|
stat = pNtSetInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val);
|
|
|
|
ok(stat == STATUS_ACCESS_DENIED, "enabling DEP while permanent: status %08x\n", stat);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
|
|
|
|
#define UNW_FLAG_NHANDLER 0
|
|
|
|
#define UNW_FLAG_EHANDLER 1
|
|
|
|
#define UNW_FLAG_UHANDLER 2
|
|
|
|
#define UNW_FLAG_CHAININFO 4
|
|
|
|
|
|
|
|
#define UWOP_PUSH_NONVOL 0
|
|
|
|
#define UWOP_ALLOC_LARGE 1
|
|
|
|
#define UWOP_ALLOC_SMALL 2
|
|
|
|
#define UWOP_SET_FPREG 3
|
|
|
|
#define UWOP_SAVE_NONVOL 4
|
|
|
|
#define UWOP_SAVE_NONVOL_FAR 5
|
|
|
|
#define UWOP_SAVE_XMM128 8
|
|
|
|
#define UWOP_SAVE_XMM128_FAR 9
|
|
|
|
#define UWOP_PUSH_MACHFRAME 10
|
|
|
|
|
|
|
|
struct results
|
|
|
|
{
|
|
|
|
int rip_offset; /* rip offset from code start */
|
|
|
|
int rbp_offset; /* rbp offset from stack pointer */
|
|
|
|
int handler; /* expect handler to be set? */
|
|
|
|
int rip; /* expected final rip value */
|
|
|
|
int frame; /* expected frame return value */
|
|
|
|
int regs[8][2]; /* expected values for registers */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct unwind_test
|
|
|
|
{
|
|
|
|
const BYTE *function;
|
|
|
|
size_t function_size;
|
|
|
|
const BYTE *unwind_info;
|
|
|
|
const struct results *results;
|
|
|
|
unsigned int nb_results;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum regs
|
|
|
|
{
|
|
|
|
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
|
|
|
|
r8, r9, r10, r11, r12, r13, r14, r15
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const reg_names[16] =
|
|
|
|
{
|
|
|
|
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
|
|
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
|
|
|
|
};
|
|
|
|
|
|
|
|
#define UWOP(code,info) (UWOP_##code | ((info) << 4))
|
|
|
|
|
|
|
|
static void call_virtual_unwind( int testnum, const struct unwind_test *test )
|
|
|
|
{
|
|
|
|
static const int code_offset = 1024;
|
|
|
|
static const int unwind_offset = 2048;
|
|
|
|
void *handler, *data;
|
|
|
|
CONTEXT context;
|
|
|
|
RUNTIME_FUNCTION runtime_func;
|
|
|
|
KNONVOLATILE_CONTEXT_POINTERS ctx_ptr;
|
|
|
|
UINT i, j, k;
|
|
|
|
ULONG64 fake_stack[256];
|
|
|
|
ULONG64 frame, orig_rip, orig_rbp, unset_reg;
|
|
|
|
UINT unwind_size = 4 + 2 * test->unwind_info[2] + 8;
|
|
|
|
|
|
|
|
memcpy( (char *)code_mem + code_offset, test->function, test->function_size );
|
|
|
|
memcpy( (char *)code_mem + unwind_offset, test->unwind_info, unwind_size );
|
|
|
|
|
|
|
|
runtime_func.BeginAddress = code_offset;
|
|
|
|
runtime_func.EndAddress = code_offset + test->function_size;
|
|
|
|
runtime_func.UnwindData = unwind_offset;
|
|
|
|
|
|
|
|
trace( "code: %p stack: %p\n", code_mem, fake_stack );
|
|
|
|
|
|
|
|
for (i = 0; i < test->nb_results; i++)
|
|
|
|
{
|
|
|
|
memset( &ctx_ptr, 0, sizeof(ctx_ptr) );
|
|
|
|
memset( &context, 0x55, sizeof(context) );
|
|
|
|
memset( &unset_reg, 0x55, sizeof(unset_reg) );
|
|
|
|
for (j = 0; j < 256; j++) fake_stack[j] = j * 8;
|
|
|
|
|
|
|
|
context.Rsp = (ULONG_PTR)fake_stack;
|
|
|
|
context.Rbp = (ULONG_PTR)fake_stack + test->results[i].rbp_offset;
|
|
|
|
orig_rbp = context.Rbp;
|
|
|
|
orig_rip = (ULONG64)code_mem + code_offset + test->results[i].rip_offset;
|
|
|
|
|
|
|
|
trace( "%u/%u: rip=%p (%02x) rbp=%p rsp=%p\n", testnum, i,
|
|
|
|
(void *)orig_rip, *(BYTE *)orig_rip, (void *)orig_rbp, (void *)context.Rsp );
|
|
|
|
|
|
|
|
data = (void *)0xdeadbeef;
|
|
|
|
handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)code_mem, orig_rip,
|
|
|
|
&runtime_func, &context, &data, &frame, &ctx_ptr );
|
|
|
|
if (test->results[i].handler)
|
|
|
|
{
|
|
|
|
ok( (char *)handler == (char *)code_mem + 0x200,
|
|
|
|
"%u/%u: wrong handler %p/%p\n", testnum, i, handler, (char *)code_mem + 0x200 );
|
|
|
|
if (handler) ok( *(DWORD *)data == 0x08070605,
|
|
|
|
"%u/%u: wrong handler data %p\n", testnum, i, data );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok( handler == NULL, "%u/%u: handler %p instead of NULL\n", testnum, i, handler );
|
|
|
|
ok( data == (void *)0xdeadbeef, "%u/%u: handler data set to %p\n", testnum, i, data );
|
|
|
|
}
|
|
|
|
|
|
|
|
ok( context.Rip == test->results[i].rip, "%u/%u: wrong rip %p/%x\n",
|
|
|
|
testnum, i, (void *)context.Rip, test->results[i].rip );
|
|
|
|
ok( frame == (ULONG64)fake_stack + test->results[i].frame, "%u/%u: wrong frame %p/%p\n",
|
|
|
|
testnum, i, (void *)frame, (char *)fake_stack + test->results[i].frame );
|
|
|
|
|
|
|
|
for (j = 0; j < 16; j++)
|
|
|
|
{
|
|
|
|
static const UINT nb_regs = sizeof(test->results[i].regs) / sizeof(test->results[i].regs[0]);
|
|
|
|
|
|
|
|
for (k = 0; k < nb_regs; k++)
|
|
|
|
{
|
|
|
|
if (test->results[i].regs[k][0] == -1)
|
|
|
|
{
|
|
|
|
k = nb_regs;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (test->results[i].regs[k][0] == j) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == rsp) /* rsp is special */
|
|
|
|
{
|
|
|
|
ok( !ctx_ptr.u2.IntegerContext[j],
|
|
|
|
"%u/%u: rsp should not be set in ctx_ptr\n", testnum, i );
|
|
|
|
ok( context.Rsp == (ULONG64)fake_stack + test->results[i].regs[k][1],
|
|
|
|
"%u/%u: register rsp wrong %p/%p\n",
|
|
|
|
testnum, i, (void *)context.Rsp, (char *)fake_stack + test->results[i].regs[k][1] );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx_ptr.u2.IntegerContext[j])
|
|
|
|
{
|
|
|
|
ok( k < nb_regs, "%u/%u: register %s should not be set to %lx\n",
|
|
|
|
testnum, i, reg_names[j], *(&context.Rax + j) );
|
|
|
|
if (k < nb_regs)
|
|
|
|
ok( *(&context.Rax + j) == test->results[i].regs[k][1],
|
|
|
|
"%u/%u: register %s wrong %p/%x\n",
|
|
|
|
testnum, i, reg_names[j], (void *)*(&context.Rax + j), test->results[i].regs[k][1] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok( k == nb_regs, "%u/%u: register %s should be set\n", testnum, i, reg_names[j] );
|
|
|
|
if (j == rbp)
|
|
|
|
ok( context.Rbp == orig_rbp, "%u/%u: register rbp wrong %p/unset\n",
|
|
|
|
testnum, i, (void *)context.Rbp );
|
|
|
|
else
|
|
|
|
ok( *(&context.Rax + j) == unset_reg,
|
|
|
|
"%u/%u: register %s wrong %p/unset\n",
|
|
|
|
testnum, i, reg_names[j], (void *)*(&context.Rax + j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_virtual_unwind(void)
|
|
|
|
{
|
|
|
|
static const BYTE function_0[] =
|
|
|
|
{
|
|
|
|
0xff, 0xf5, /* 00: push %rbp */
|
|
|
|
0x48, 0x81, 0xec, 0x10, 0x01, 0x00, 0x00, /* 02: sub $0x110,%rsp */
|
|
|
|
0x48, 0x8d, 0x6c, 0x24, 0x30, /* 09: lea 0x30(%rsp),%rbp */
|
|
|
|
0x48, 0x89, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 0e: mov %rbx,0xf0(%rbp) */
|
|
|
|
0x48, 0x89, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 15: mov %rsi,0xf8(%rbp) */
|
|
|
|
0x90, /* 1c: nop */
|
|
|
|
0x48, 0x8b, 0x9d, 0xf0, 0x00, 0x00, 0x00, /* 1d: mov 0xf0(%rbp),%rbx */
|
|
|
|
0x48, 0x8b, 0xb5, 0xf8, 0x00, 0x00, 0x00, /* 24: mov 0xf8(%rbp),%rsi */
|
|
|
|
0x48, 0x8d, 0xa5, 0xe0, 0x00, 0x00, 0x00, /* 2b: lea 0xe0(%rbp),%rsp */
|
|
|
|
0x5d, /* 32: pop %rbp */
|
|
|
|
0xc3 /* 33: ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const BYTE unwind_info_0[] =
|
|
|
|
{
|
|
|
|
1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
|
|
|
|
0x1c, /* prolog size */
|
|
|
|
8, /* opcode count */
|
|
|
|
(0x03 << 4) | rbp, /* frame reg rbp offset 0x30 */
|
|
|
|
|
|
|
|
0x1c, UWOP(SAVE_NONVOL, rsi), 0x25, 0, /* 1c: mov %rsi,0x128(%rsp) */
|
|
|
|
0x15, UWOP(SAVE_NONVOL, rbx), 0x24, 0, /* 15: mov %rbx,0x120(%rsp) */
|
|
|
|
0x0e, UWOP(SET_FPREG, rbp), /* 0e: lea 0x30(%rsp),rbp */
|
|
|
|
0x09, UWOP(ALLOC_LARGE, 0), 0x22, 0, /* 09: sub $0x110,%rsp */
|
|
|
|
0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
|
|
|
|
|
|
|
|
0x00, 0x02, 0x00, 0x00, /* handler */
|
|
|
|
0x05, 0x06, 0x07, 0x08, /* data */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct results results_0[] =
|
|
|
|
{
|
|
|
|
/* offset rbp handler rip frame registers */
|
|
|
|
{ 0x00, 0x40, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
|
|
|
|
{ 0x02, 0x40, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbp,0x000}, {-1,-1} }},
|
|
|
|
{ 0x09, 0x40, FALSE, 0x118, 0x000, { {rsp,0x120}, {rbp,0x110}, {-1,-1} }},
|
|
|
|
{ 0x0e, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1} }},
|
|
|
|
{ 0x15, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {-1,-1} }},
|
|
|
|
{ 0x1c, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
|
|
|
|
{ 0x1d, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
|
|
|
|
{ 0x24, 0x40, TRUE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {rbx,0x130}, {rsi,0x138}, {-1,-1}}},
|
|
|
|
{ 0x2b, 0x40, FALSE, 0x128, 0x010, { {rsp,0x130}, {rbp,0x120}, {-1,-1}}},
|
|
|
|
{ 0x32, 0x40, FALSE, 0x008, 0x010, { {rsp,0x010}, {rbp,0x000}, {-1,-1}}},
|
|
|
|
{ 0x33, 0x40, FALSE, 0x000, 0x010, { {rsp,0x008}, {-1,-1}}},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const BYTE function_1[] =
|
|
|
|
{
|
|
|
|
0x53, /* 00: push %rbx */
|
|
|
|
0x55, /* 01: push %rbp */
|
|
|
|
0x56, /* 02: push %rsi */
|
|
|
|
0x57, /* 03: push %rdi */
|
|
|
|
0x41, 0x54, /* 04: push %r12 */
|
|
|
|
0x48, 0x83, 0xec, 0x30, /* 06: sub $0x30,%rsp */
|
|
|
|
0x90, 0x90, /* 0a: nop; nop */
|
|
|
|
0x48, 0x83, 0xc4, 0x30, /* 0c: add $0x30,%rsp */
|
|
|
|
0x41, 0x5c, /* 10: pop %r12 */
|
|
|
|
0x5f, /* 12: pop %rdi */
|
|
|
|
0x5e, /* 13: pop %rsi */
|
|
|
|
0x5d, /* 14: pop %rbp */
|
|
|
|
0x5b, /* 15: pop %rbx */
|
|
|
|
0xc3 /* 16: ret */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const BYTE unwind_info_1[] =
|
|
|
|
{
|
|
|
|
1 | (UNW_FLAG_EHANDLER << 3), /* version + flags */
|
|
|
|
0x0a, /* prolog size */
|
|
|
|
6, /* opcode count */
|
|
|
|
0, /* frame reg */
|
|
|
|
|
|
|
|
0x0a, UWOP(ALLOC_SMALL, 5), /* 0a: sub $0x30,%rsp */
|
|
|
|
0x06, UWOP(PUSH_NONVOL, r12), /* 06: push %r12 */
|
|
|
|
0x04, UWOP(PUSH_NONVOL, rdi), /* 04: push %rdi */
|
|
|
|
0x03, UWOP(PUSH_NONVOL, rsi), /* 03: push %rsi */
|
|
|
|
0x02, UWOP(PUSH_NONVOL, rbp), /* 02: push %rbp */
|
|
|
|
0x01, UWOP(PUSH_NONVOL, rbx), /* 01: push %rbx */
|
|
|
|
|
|
|
|
0x00, 0x02, 0x00, 0x00, /* handler */
|
|
|
|
0x05, 0x06, 0x07, 0x08, /* data */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct results results_1[] =
|
|
|
|
{
|
|
|
|
/* offset rbp handler rip frame registers */
|
|
|
|
{ 0x00, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
|
|
|
|
{ 0x01, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
|
|
|
|
{ 0x02, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
|
|
|
|
{ 0x03, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
|
|
|
|
{ 0x04, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
|
|
|
|
{ 0x06, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
|
|
|
|
{ 0x0a, 0x50, TRUE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
|
|
|
|
{ 0x0c, 0x50, FALSE, 0x058, 0x000, { {rsp,0x060}, {rbx,0x050}, {rbp,0x048}, {rsi,0x040}, {rdi,0x038}, {r12,0x030}, {-1,-1} }},
|
|
|
|
{ 0x10, 0x50, FALSE, 0x028, 0x000, { {rsp,0x030}, {rbx,0x020}, {rbp,0x018}, {rsi,0x010}, {rdi,0x008}, {r12,0x000}, {-1,-1} }},
|
|
|
|
{ 0x12, 0x50, FALSE, 0x020, 0x000, { {rsp,0x028}, {rbx,0x018}, {rbp,0x010}, {rsi,0x008}, {rdi,0x000}, {-1,-1} }},
|
|
|
|
{ 0x13, 0x50, FALSE, 0x018, 0x000, { {rsp,0x020}, {rbx,0x010}, {rbp,0x008}, {rsi,0x000}, {-1,-1} }},
|
|
|
|
{ 0x14, 0x50, FALSE, 0x010, 0x000, { {rsp,0x018}, {rbx,0x008}, {rbp,0x000}, {-1,-1} }},
|
|
|
|
{ 0x15, 0x50, FALSE, 0x008, 0x000, { {rsp,0x010}, {rbx,0x000}, {-1,-1} }},
|
|
|
|
{ 0x16, 0x50, FALSE, 0x000, 0x000, { {rsp,0x008}, {-1,-1} }},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct unwind_test tests[] =
|
|
|
|
{
|
|
|
|
{ function_0, sizeof(function_0), unwind_info_0,
|
|
|
|
results_0, sizeof(results_0)/sizeof(results_0[0]) },
|
|
|
|
{ function_1, sizeof(function_1), unwind_info_1,
|
|
|
|
results_1, sizeof(results_1)/sizeof(results_1[0]) }
|
|
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
|
|
|
|
call_virtual_unwind( i, &tests[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* __x86_64__ */
|
2007-03-06 11:59:18 +00:00
|
|
|
|
|
|
|
START_TEST(exception)
|
|
|
|
{
|
2011-08-09 22:37:53 +00:00
|
|
|
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
|
2011-08-09 12:10:04 +00:00
|
|
|
|
2010-03-15 22:13:19 +00:00
|
|
|
code_mem = VirtualAlloc(NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
if(!code_mem) {
|
|
|
|
trace("VirtualAlloc failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-05-12 08:33:26 +00:00
|
|
|
pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" );
|
|
|
|
pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" );
|
|
|
|
pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" );
|
|
|
|
pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" );
|
|
|
|
pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" );
|
|
|
|
pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" );
|
|
|
|
pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
|
|
|
|
"RtlAddVectoredExceptionHandler" );
|
|
|
|
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
|
|
|
|
"RtlRemoveVectoredExceptionHandler" );
|
2010-03-15 22:13:19 +00:00
|
|
|
pNtQueryInformationProcess = (void*)GetProcAddress( hntdll,
|
|
|
|
"NtQueryInformationProcess" );
|
|
|
|
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
|
|
|
|
"NtSetInformationProcess" );
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process");
|
2010-03-15 22:13:19 +00:00
|
|
|
|
|
|
|
#ifdef __i386__
|
2008-05-12 08:33:26 +00:00
|
|
|
if (!pNtCurrentTeb)
|
|
|
|
{
|
|
|
|
skip( "NtCurrentTeb not found\n" );
|
|
|
|
return;
|
|
|
|
}
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
|
2008-05-12 08:33:26 +00:00
|
|
|
|
|
|
|
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
|
|
|
|
have_vectored_api = TRUE;
|
|
|
|
else
|
|
|
|
skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n");
|
|
|
|
|
|
|
|
my_argc = winetest_get_mainargs( &my_argv );
|
|
|
|
if (my_argc >= 4)
|
|
|
|
{
|
|
|
|
void *addr;
|
|
|
|
sscanf( my_argv[3], "%p", &addr );
|
|
|
|
|
|
|
|
if (addr != &test_stage)
|
|
|
|
{
|
|
|
|
skip( "child process not mapped at same address (%p/%p)\n", &test_stage, addr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* child must be run under a debugger */
|
|
|
|
if (!pNtCurrentTeb()->Peb->BeingDebugged)
|
|
|
|
{
|
|
|
|
ok(FALSE, "child process not being debugged?\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pRtlRaiseException)
|
|
|
|
{
|
|
|
|
test_stage = 1;
|
|
|
|
run_rtlraiseexception_test(0x12345);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
|
|
|
|
test_stage = 2;
|
|
|
|
run_rtlraiseexception_test(0x12345);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
|
|
|
|
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skip( "RtlRaiseException not found\n" );
|
|
|
|
|
|
|
|
/* rest of tests only run in parent */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-06 11:59:18 +00:00
|
|
|
test_prot_fault();
|
2008-05-12 08:33:26 +00:00
|
|
|
test_exceptions();
|
|
|
|
test_rtlraiseexception();
|
|
|
|
test_debugger();
|
|
|
|
test_simd_exceptions();
|
2009-05-17 07:05:22 +00:00
|
|
|
test_fpu_exceptions();
|
2010-03-15 22:13:19 +00:00
|
|
|
test_dpe_exceptions();
|
|
|
|
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
|
|
|
|
test_virtual_unwind();
|
2008-05-12 08:33:26 +00:00
|
|
|
|
2007-03-06 11:59:18 +00:00
|
|
|
#endif
|
2010-03-15 22:13:19 +00:00
|
|
|
|
|
|
|
VirtualFree(code_mem, 0, MEM_FREE);
|
2007-03-06 11:59:18 +00:00
|
|
|
}
|