Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
15b18f48
Commit
15b18f48
authored
Jun 18, 2021
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll/tests: Adapt some of the i386 tests to run on x86-64 as well.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
c0012ecd
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
431 additions
and
56 deletions
+431
-56
exception.c
dlls/ntdll/tests/exception.c
+431
-56
No files found.
dlls/ntdll/tests/exception.c
View file @
15b18f48
...
...
@@ -1309,10 +1309,8 @@ static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_R
ok
(
rec
->
ExceptionCode
==
STATUS_FLOAT_MULTIPLE_TRAPS
,
"exception code: %#x, should be %#x
\n
"
,
rec
->
ExceptionCode
,
STATUS_FLOAT_MULTIPLE_TRAPS
);
ok
(
rec
->
NumberParameters
==
1
||
broken
(
is_wow64
&&
rec
->
NumberParameters
==
2
),
"# of params: %i, should be 1
\n
"
,
rec
->
NumberParameters
);
if
(
rec
->
NumberParameters
==
1
)
ok
(
rec
->
NumberParameters
==
is_wow64
?
2
:
1
,
"# of params: %i
\n
"
,
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 */
...
...
@@ -1999,53 +1997,6 @@ static void test_kiuserexceptiondispatcher(void)
ok
(
ret
,
"Got unexpected ret %#x, GetLastError() %u.
\n
"
,
ret
,
GetLastError
());
}
static
BOOL
test_apc_called
;
static
void
CALLBACK
test_apc
(
ULONG_PTR
arg1
,
ULONG_PTR
arg2
,
ULONG_PTR
arg3
)
{
test_apc_called
=
TRUE
;
}
static
void
test_user_apc
(
void
)
{
NTSTATUS
status
;
CONTEXT
context
;
int
pass
;
if
(
!
pNtQueueApcThread
)
{
win_skip
(
"NtQueueApcThread is not available.
\n
"
);
return
;
}
pass
=
0
;
InterlockedIncrement
(
&
pass
);
RtlCaptureContext
(
&
context
);
InterlockedIncrement
(
&
pass
);
if
(
pass
==
2
)
{
/* Try to make sure context data is far enough below context.Esp. */
CONTEXT
c
[
4
];
c
[
0
]
=
context
;
test_apc_called
=
FALSE
;
status
=
pNtQueueApcThread
(
GetCurrentThread
(),
test_apc
,
0
,
0
,
0
);
ok
(
!
status
,
"Got unexpected status %#x.
\n
"
,
status
);
SleepEx
(
0
,
TRUE
);
ok
(
test_apc_called
,
"Test user APC was not called.
\n
"
);
test_apc_called
=
FALSE
;
status
=
pNtQueueApcThread
(
GetCurrentThread
(),
test_apc
,
0
,
0
,
0
);
ok
(
!
status
,
"Got unexpected status %#x.
\n
"
,
status
);
status
=
NtContinue
(
&
c
[
0
],
TRUE
);
/* Broken before Win7, in that case NtContinue returns here instead of restoring context after calling APC. */
ok
(
0
,
"Should not get here, status %#x.
\n
"
,
status
);
}
ok
(
pass
==
3
,
"Got unexpected pass %d.
\n
"
,
pass
);
ok
(
test_apc_called
,
"Test user APC was not called.
\n
"
);
}
#elif defined(__x86_64__)
#define UNW_FLAG_NHANDLER 0
...
...
@@ -3080,6 +3031,381 @@ skip_params:
return
ExceptionContinueExecution
;
}
static
const
BYTE
segfault_code
[
5
]
=
{
0x31
,
0xc0
,
/* xor %eax,%eax */
0x8f
,
0x00
,
/* popq (%rax) - cause exception */
0xc3
/* ret */
};
struct
dbgreg_test
{
ULONG_PTR
dr0
,
dr1
,
dr2
,
dr3
,
dr6
,
dr7
;
};
/* test handling of debug registers */
static
DWORD
WINAPI
dreg_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
const
struct
dbgreg_test
*
test
=
*
(
const
struct
dbgreg_test
**
)
dispatcher
->
HandlerData
;
context
->
Rip
+=
2
;
/* Skips the popq (%rax) */
context
->
Dr0
=
test
->
dr0
;
context
->
Dr1
=
test
->
dr1
;
context
->
Dr2
=
test
->
dr2
;
context
->
Dr3
=
test
->
dr3
;
context
->
Dr6
=
test
->
dr6
;
context
->
Dr7
=
test
->
dr7
;
return
ExceptionContinueExecution
;
}
#define CHECK_DEBUG_REG(n, m) \
ok((ctx.Dr##n & m) == test->dr##n, "(%d) failed to set debug register " #n " to %p, got %p\n", \
test_num, (void *)test->dr##n, (void *)ctx.Dr##n)
static
int
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
);
if
(
!
ctx
.
Dr0
&&
!
ctx
.
Dr1
&&
!
ctx
.
Dr2
&&
!
ctx
.
Dr3
&&
!
ctx
.
Dr6
&&
!
ctx
.
Dr7
)
{
win_skip
(
"debug registers broken
\n
"
);
return
0
;
}
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
);
return
1
;
}
static
const
BYTE
single_stepcode
[]
=
{
0x9c
,
/* pushf */
0x58
,
/* pop %rax */
0x0d
,
0
,
1
,
0
,
0
,
/* or $0x100,%eax */
0x50
,
/* push %rax */
0x9d
,
/* popf */
0x35
,
0
,
1
,
0
,
0
,
/* xor $0x100,%eax */
0x50
,
/* push %rax */
0x9d
,
/* popf */
0x90
,
0xc3
};
/* test the single step exception behaviour */
static
DWORD
WINAPI
single_step_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
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
;
}
/* Test the alignment check (AC) flag handling. */
static
const
BYTE
align_check_code
[]
=
{
0x55
,
/* push %rbp */
0x48
,
0x89
,
0xe5
,
/* mov %rsp,%rbp */
0x9c
,
/* pushf */
0x9c
,
/* pushf */
0x58
,
/* pop %rax */
0x0d
,
0
,
0
,
4
,
0
,
/* or $0x40000,%eax */
0x50
,
/* push %rax */
0x9d
,
/* popf */
0x48
,
0x89
,
0xe0
,
/* mov %rsp, %rax */
0x8b
,
0x40
,
0x1
,
/* mov 0x1(%rax), %eax - cause exception */
0x9d
,
/* popf */
0x5d
,
/* pop %rbp */
0xc3
,
/* ret */
};
static
DWORD
WINAPI
align_check_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
#ifdef __GNUC__
__asm__
volatile
(
"pushfq; andl $~0x40000,(%rsp); popfq"
);
#endif
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
[]
=
{
0xfd
,
/* std */
0xfa
,
/* cli - cause exception */
0xc3
,
/* ret */
};
static
DWORD
WINAPI
direction_flag_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
#ifdef __GNUC__
ULONG_PTR
flags
;
__asm__
(
"pushfq; popq %0; cld"
:
"=r"
(
flags
)
);
/* 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
->
Rip
++
;
/* skip cli */
context
->
EFlags
&=
~
0x400
;
/* make sure it is cleared on return */
return
ExceptionContinueExecution
;
}
/* test single stepping over hardware breakpoint */
static
const
BYTE
dummy_code
[]
=
{
0x90
,
0x90
,
0x90
,
0xc3
};
/* nop, nop, nop, ret */
static
DWORD
WINAPI
bpx_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
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
(
(
void
*
)
context
->
Rip
==
code_mem
,
"rip is wrong: %p instead of %p
\n
"
,
(
void
*
)
context
->
Rip
,
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
(
(
char
*
)
context
->
Rip
==
(
char
*
)
code_mem
+
1
,
"rip is wrong: %p instead of %p
\n
"
,
(
void
*
)
context
->
Rip
,
(
char
*
)
code_mem
+
1
);
ok
(
(
context
->
Dr6
&
0x4000
),
"BS flag is not set in Dr6
\n
"
);
context
->
EFlags
|=
0x100
;
}
else
if
(
got_exception
==
3
)
{
/* hw bp exception on second nop */
ok
(
(
void
*
)
context
->
Rip
==
(
char
*
)
code_mem
+
1
,
"rip is wrong: %p instead of %p
\n
"
,
(
void
*
)
context
->
Rip
,
(
char
*
)
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 third nop */
ok
(
(
void
*
)
context
->
Rip
==
(
char
*
)
code_mem
+
2
,
"rip is wrong: %p instead of %p
\n
"
,
(
void
*
)
context
->
Rip
,
(
char
*
)
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
;
}
/* test int3 handling */
static
const
BYTE
int3_code
[]
=
{
0xcc
,
0xc3
};
/* int 3, ret */
static
DWORD
WINAPI
int3_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
ok
(
rec
->
ExceptionAddress
==
code_mem
,
"exception address not at: %p, but at %p
\n
"
,
code_mem
,
rec
->
ExceptionAddress
);
ok
(
(
void
*
)
context
->
Rip
==
code_mem
,
"rip not at: %p, but at %p
\n
"
,
code_mem
,
(
void
*
)
context
->
Rip
);
if
((
void
*
)
context
->
Rip
==
code_mem
)
context
->
Rip
++
;
/* skip breakpoint */
return
ExceptionContinueExecution
;
}
/* trap unhandled exceptions */
static
LONG
CALLBACK
exc_filter
(
EXCEPTION_POINTERS
*
ptrs
)
{
printf
(
"%04x unhandled exception %08x at %p rip %p eflags %x
\n
"
,
GetCurrentProcessId
(),
ptrs
->
ExceptionRecord
->
ExceptionCode
,
ptrs
->
ExceptionRecord
->
ExceptionAddress
,
(
void
*
)
ptrs
->
ContextRecord
->
Rip
,
ptrs
->
ContextRecord
->
EFlags
);
fflush
(
stdout
);
return
EXCEPTION_EXECUTE_HANDLER
;
}
static
void
test_exceptions
(
void
)
{
CONTEXT
ctx
;
NTSTATUS
res
;
struct
dbgreg_test
dreg_test
;
/* test handling of debug registers */
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
);
if
(
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
);
/* test single stepping over hardware breakpoint */
memset
(
&
ctx
,
0
,
sizeof
(
ctx
));
ctx
.
Dr0
=
(
ULONG_PTR
)
code_mem
;
/* set hw bp on first nop */
ctx
.
Dr7
=
1
;
ctx
.
ContextFlags
=
CONTEXT_DEBUG_REGISTERS
;
res
=
pNtSetContextThread
(
GetCurrentThread
(),
&
ctx
);
ok
(
res
==
STATUS_SUCCESS
,
"NtSetContextThread failed with %x
\n
"
,
res
);
got_exception
=
0
;
run_exception_test
(
bpx_handler
,
NULL
,
dummy_code
,
sizeof
(
dummy_code
),
0
);
ok
(
got_exception
==
4
,
"expected 4 exceptions, got %d
\n
"
,
got_exception
);
}
/* test single stepping behavior */
SetUnhandledExceptionFilter
(
exc_filter
);
got_exception
=
0
;
run_exception_test
(
single_step_handler
,
NULL
,
&
single_stepcode
,
sizeof
(
single_stepcode
),
0
);
ok
(
got_exception
==
3
,
"expected 3 single step exceptions, got %d
\n
"
,
got_exception
);
/* test alignment exceptions */
if
(
0
)
/* broken on Windows */
{
got_exception
=
0
;
run_exception_test
(
align_check_handler
,
NULL
,
align_check_code
,
sizeof
(
align_check_code
),
0
);
ok
(
got_exception
==
0
,
"got %d alignment faults, expected 0
\n
"
,
got_exception
);
}
/* test direction flag */
got_exception
=
0
;
run_exception_test
(
direction_flag_handler
,
NULL
,
direction_flag_code
,
sizeof
(
direction_flag_code
),
0
);
ok
(
got_exception
==
1
,
"got %d exceptions, expected 1
\n
"
,
got_exception
);
/* test int3 handling */
run_exception_test
(
int3_handler
,
NULL
,
int3_code
,
sizeof
(
int3_code
),
0
);
}
static
DWORD
WINAPI
simd_fault_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG64
frame
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
int
*
stage
=
*
(
int
**
)
dispatcher
->
HandlerData
;
got_exception
++
;
if
(
*
stage
==
1
)
{
/* fault while executing sse instruction */
context
->
Rip
+=
3
;
/* skip addps */
return
ExceptionContinueExecution
;
}
else
if
(
*
stage
==
2
||
*
stage
==
3
)
{
/* stage 2 - divide by zero fault */
/* stage 3 - invalid operation fault */
if
(
rec
->
ExceptionCode
==
EXCEPTION_ILLEGAL_INSTRUCTION
)
skip
(
"system doesn't support SIMD exceptions
\n
"
);
else
{
ULONG
expect
=
*
stage
==
2
?
EXCEPTION_FLT_DIVIDE_BY_ZERO
:
EXCEPTION_FLT_INVALID_OPERATION
;
ok
(
rec
->
ExceptionCode
==
expect
,
"exception code: %#x, should be %#x
\n
"
,
rec
->
ExceptionCode
,
expect
);
todo_wine
ok
(
rec
->
NumberParameters
==
2
,
"# of params: %i, should be 2
\n
"
,
rec
->
NumberParameters
);
if
(
rec
->
NumberParameters
==
2
)
{
/* no idea what these mean */
ok
(
rec
->
ExceptionInformation
[
0
]
==
0
,
"param #0: %lx
\n
"
,
rec
->
ExceptionInformation
[
0
]);
ok
(
rec
->
ExceptionInformation
[
1
]
!=
0
,
"param #1: %lx
\n
"
,
rec
->
ExceptionInformation
[
1
]);
}
}
context
->
Rip
+=
3
;
/* skip divps */
}
else
ok
(
FALSE
,
"unexpected stage %x
\n
"
,
*
stage
);
return
ExceptionContinueExecution
;
}
static
const
BYTE
simd_exception_test
[]
=
{
0x48
,
0x83
,
0xec
,
0x8
,
/* sub $0x8, %rsp */
0x0f
,
0xae
,
0x1c
,
0x24
,
/* stmxcsr (%rsp) */
0x8b
,
0x04
,
0x24
,
/* mov (%rsp),%eax * store mxcsr */
0x66
,
0x81
,
0x24
,
0x24
,
0xff
,
0xfd
,
/* andw $0xfdff,(%rsp) * enable divide by */
0x0f
,
0xae
,
0x14
,
0x24
,
/* ldmxcsr (%rsp) * zero exceptions */
0xb9
,
0x01
,
0x00
,
0x00
,
0x00
,
/* movl $0x1,%ecx */
0x66
,
0x48
,
0x0f
,
0x6e
,
0xc9
,
/* movq %rcx,%xmm1 * fill dividend */
0x0f
,
0x57
,
0xc0
,
/* xorps %xmm0,%xmm0 * clear divisor */
0x0f
,
0x5e
,
0xc8
,
/* divps %xmm0,%xmm1 * generate fault */
0x89
,
0x04
,
0x24
,
/* mov %eax,(%rsp) * restore to old mxcsr */
0x0f
,
0xae
,
0x14
,
0x24
,
/* ldmxcsr (%rsp) */
0x48
,
0x83
,
0xc4
,
0x08
,
/* add $0x8,%rsp */
0xc3
,
/* ret */
};
static
const
BYTE
simd_exception_test2
[]
=
{
0x48
,
0x83
,
0xec
,
0x8
,
/* sub $0x8, %rsp */
0x0f
,
0xae
,
0x1c
,
0x24
,
/* stmxcsr (%rsp) */
0x8b
,
0x04
,
0x24
,
/* mov (%rsp),%eax * store mxcsr */
0x66
,
0x81
,
0x24
,
0x24
,
0x7f
,
0xff
,
/* andw $0xff7f,(%rsp) * enable invalid */
0x0f
,
0xae
,
0x14
,
0x24
,
/* ldmxcsr (%rsp) * operation exceptions */
0x0f
,
0x57
,
0xc9
,
/* xorps %xmm1,%xmm1 * clear dividend */
0x0f
,
0x57
,
0xc0
,
/* xorps %xmm0,%xmm0 * clear divisor */
0x0f
,
0x5e
,
0xc8
,
/* divps %xmm0,%xmm1 * generate fault */
0x89
,
0x04
,
0x24
,
/* mov %eax,(%rsp) * restore to old mxcsr */
0x0f
,
0xae
,
0x14
,
0x24
,
/* ldmxcsr (%rsp) */
0x48
,
0x83
,
0xc4
,
0x08
,
/* add $0x8,%rsp */
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
;
run_exception_test
(
simd_fault_handler
,
&
stage
,
sse_check
,
sizeof
(
sse_check
),
0
);
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
,
sizeof
(
simd_exception_test
),
0
);
ok
(
got_exception
==
1
,
"got exception: %i, should be 1
\n
"
,
got_exception
);
/* generate a SIMD exception, test FPE_FLTINV */
stage
=
3
;
got_exception
=
0
;
run_exception_test
(
simd_fault_handler
,
&
stage
,
simd_exception_test2
,
sizeof
(
simd_exception_test2
),
0
);
ok
(
got_exception
==
1
,
"got exception: %i, should be 1
\n
"
,
got_exception
);
}
static
void
test_prot_fault
(
void
)
{
unsigned
int
i
;
...
...
@@ -5870,7 +6196,7 @@ static void test_debug_registers(void)
ctx
.
Dr7
=
tests
[
i
].
dr7
;
status
=
pNtSetContextThread
(
GetCurrentThread
(),
&
ctx
);
ok
(
status
==
STATUS_SUCCESS
,
"Nt
G
etContextThread failed with %08x
\n
"
,
status
);
ok
(
status
==
STATUS_SUCCESS
,
"Nt
S
etContextThread failed with %08x
\n
"
,
status
);
memset
(
&
ctx
,
0
,
sizeof
(
ctx
));
ctx
.
ContextFlags
=
CONTEXT_DEBUG_REGISTERS
;
...
...
@@ -6490,6 +6816,55 @@ static void test_vectored_continue_handler(void)
ok
(
!
ret
,
"RtlRemoveVectoredContinueHandler succeeded
\n
"
);
}
static
BOOL
test_apc_called
;
static
void
CALLBACK
test_apc
(
ULONG_PTR
arg1
,
ULONG_PTR
arg2
,
ULONG_PTR
arg3
)
{
test_apc_called
=
TRUE
;
}
static
void
test_user_apc
(
void
)
{
NTSTATUS
status
;
CONTEXT
context
;
int
pass
;
if
(
!
pNtQueueApcThread
)
{
win_skip
(
"NtQueueApcThread is not available.
\n
"
);
return
;
}
pass
=
0
;
InterlockedIncrement
(
&
pass
);
RtlCaptureContext
(
&
context
);
InterlockedIncrement
(
&
pass
);
if
(
pass
==
2
)
{
/* Try to make sure context data is far enough below context.Esp. */
CONTEXT
c
[
4
];
c
[
0
]
=
context
;
test_apc_called
=
FALSE
;
status
=
pNtQueueApcThread
(
GetCurrentThread
(),
test_apc
,
0
,
0
,
0
);
ok
(
!
status
,
"Got unexpected status %#x.
\n
"
,
status
);
SleepEx
(
0
,
TRUE
);
ok
(
test_apc_called
,
"Test user APC was not called.
\n
"
);
test_apc_called
=
FALSE
;
status
=
pNtQueueApcThread
(
GetCurrentThread
(),
test_apc
,
0
,
0
,
0
);
ok
(
!
status
,
"Got unexpected status %#x.
\n
"
,
status
);
status
=
NtContinue
(
&
c
[
0
],
TRUE
);
/* Broken before Win7, in that case NtContinue returns here instead of restoring context after calling APC. */
ok
(
broken
(
TRUE
),
"Should not get here, status %#x.
\n
"
,
status
);
return
;
}
ok
(
pass
==
3
,
"Got unexpected pass %d.
\n
"
,
pass
);
ok
(
test_apc_called
,
"Test user APC was not called.
\n
"
);
}
static
DWORD
WINAPI
suspend_thread_test
(
void
*
arg
)
{
HANDLE
event
=
arg
;
...
...
@@ -8479,7 +8854,6 @@ START_TEST(exception)
test_kiuserexceptiondispatcher
();
test_extended_context
();
test_copy_context
();
test_user_apc
();
#elif defined(__x86_64__)
...
...
@@ -8498,14 +8872,14 @@ START_TEST(exception)
X
(
RtlWow64GetThreadContext
);
X
(
RtlWow64SetThreadContext
);
#undef X
p_setjmp
=
(
void
*
)
GetProcAddress
(
hmsvcrt
,
"_setjmp"
);
p_setjmp
=
(
void
*
)
GetProcAddress
(
hmsvcrt
,
"_setjmp"
);
test_exceptions
();
test_rtlraiseexception
();
test_debug_registers
();
test_debug_registers_wow64
();
test_debug_service
(
1
);
test_simd_exceptions
();
test_virtual_unwind
();
test___C_specific_handler
();
test_restore_context
();
...
...
@@ -8542,6 +8916,7 @@ START_TEST(exception)
test_closehandle
(
0
,
(
HANDLE
)
0xdeadbeef
);
NtCurrentTeb
()
->
Peb
->
BeingDebugged
=
0
;
test_user_apc
();
test_vectored_continue_handler
();
test_suspend_thread
();
test_suspend_process
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment