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
07f84d04
Commit
07f84d04
authored
Dec 16, 2005
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: More compatible exception information for protection faults.
Added a bunch of test cases.
parent
a57790f4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
302 additions
and
3 deletions
+302
-3
signal_i386.c
dlls/ntdll/signal_i386.c
+77
-3
.gitignore
dlls/ntdll/tests/.gitignore
+1
-0
Makefile.in
dlls/ntdll/tests/Makefile.in
+1
-0
exception.c
dlls/ntdll/tests/exception.c
+223
-0
No files found.
dlls/ntdll/signal_i386.c
View file @
07f84d04
...
...
@@ -484,7 +484,7 @@ static inline int get_trap_code( const SIGCONTEXT *sigcontext )
*
* Get the error code for a signal.
*/
static
inline
int
get_error_code
(
const
SIGCONTEXT
*
sigcontext
)
static
inline
WORD
get_error_code
(
const
SIGCONTEXT
*
sigcontext
)
{
#ifdef ERROR_sig
return
ERROR_sig
(
sigcontext
);
...
...
@@ -794,6 +794,71 @@ inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigconte
/***********************************************************************
* is_privileged_instr
*
* Check if the fault location is a privileged instruction.
* Based on the instruction emulation code in dlls/kernel/instr.c.
*/
static
inline
int
is_privileged_instr
(
CONTEXT86
*
context
)
{
const
BYTE
*
instr
;
unsigned
int
prefix_count
=
0
;
if
(
!
wine_ldt_is_system
(
context
->
SegCs
))
return
0
;
instr
=
(
BYTE
*
)
context
->
Eip
;
for
(;;)
switch
(
*
instr
)
{
/* instruction prefixes */
case
0x2e
:
/* %cs: */
case
0x36
:
/* %ss: */
case
0x3e
:
/* %ds: */
case
0x26
:
/* %es: */
case
0x64
:
/* %fs: */
case
0x65
:
/* %gs: */
case
0x66
:
/* opcode size */
case
0x67
:
/* addr size */
case
0xf0
:
/* lock */
case
0xf2
:
/* repne */
case
0xf3
:
/* repe */
if
(
++
prefix_count
>=
15
)
return
0
;
instr
++
;
continue
;
case
0x0f
:
/* extended instruction */
switch
(
instr
[
1
])
{
case
0x20
:
/* mov crX, reg */
case
0x21
:
/* mov drX, reg */
case
0x22
:
/* mov reg, crX */
case
0x23
:
/* mov reg drX */
return
1
;
}
return
0
;
case
0x6c
:
/* insb (%dx) */
case
0x6d
:
/* insl (%dx) */
case
0x6e
:
/* outsb (%dx) */
case
0x6f
:
/* outsl (%dx) */
case
0xcd
:
/* int $xx */
case
0xe4
:
/* inb al,XX */
case
0xe5
:
/* in (e)ax,XX */
case
0xe6
:
/* outb XX,al */
case
0xe7
:
/* out XX,(e)ax */
case
0xec
:
/* inb (%dx),%al */
case
0xed
:
/* inl (%dx),%eax */
case
0xee
:
/* outb %al,(%dx) */
case
0xef
:
/* outl %eax,(%dx) */
case
0xf4
:
/* hlt */
case
0xfa
:
/* cli */
case
0xfb
:
/* sti */
return
1
;
default:
return
0
;
}
}
/***********************************************************************
* setup_exception
*
* Setup a proper stack frame for the raise function, and modify the
...
...
@@ -1063,8 +1128,17 @@ static HANDLER_DEF(segv_handler)
case
T_SEGNPFLT
:
/* Segment not present exception */
case
T_PROTFLT
:
/* General protection fault */
case
T_UNKNOWN
:
/* Unknown fault code */
rec
->
ExceptionCode
=
get_error_code
(
HANDLER_CONTEXT
)
?
EXCEPTION_ACCESS_VIOLATION
:
EXCEPTION_PRIV_INSTRUCTION
;
if
(
!
get_error_code
(
HANDLER_CONTEXT
)
&&
is_privileged_instr
(
get_exception_context
(
rec
)
))
rec
->
ExceptionCode
=
EXCEPTION_PRIV_INSTRUCTION
;
else
{
WORD
err
=
get_error_code
(
HANDLER_CONTEXT
);
rec
->
ExceptionCode
=
EXCEPTION_ACCESS_VIOLATION
;
rec
->
NumberParameters
=
2
;
rec
->
ExceptionInformation
[
0
]
=
0
;
/* if error contains a LDT selector, use that as fault address */
rec
->
ExceptionInformation
[
1
]
=
(
err
&
7
)
==
4
?
(
err
&
~
7
)
:
0xffffffff
;
}
break
;
case
T_PAGEFLT
:
/* Page fault */
rec
->
ExceptionCode
=
EXCEPTION_ACCESS_VIOLATION
;
...
...
dlls/ntdll/tests/.gitignore
View file @
07f84d04
...
...
@@ -2,6 +2,7 @@ Makefile
atom.ok
env.ok
error.ok
exception.ok
generated.ok
info.ok
large_int.ok
...
...
dlls/ntdll/tests/Makefile.in
View file @
07f84d04
...
...
@@ -9,6 +9,7 @@ CTESTS = \
atom.c
\
env.c
\
error.c
\
exception.c
\
generated.c
\
info.c
\
large_int.c
\
...
...
dlls/ntdll/tests/exception.c
0 → 100644
View file @
07f84d04
/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x500
/* For NTSTATUS */
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winnt.h"
#include "winreg.h"
#include "winternl.h"
#include "excpt.h"
#include "wine/test.h"
#ifdef __i386__
/* Test various instruction combinations that cause a protection fault on the i386,
* and check what the resulting exception looks like.
*/
static
const
struct
exception
{
BYTE
code
[
18
];
/* asm code */
BYTE
offset
;
/* offset of faulting instruction */
BYTE
length
;
/* length of faulting instruction */
NTSTATUS
status
;
/* expected status code */
DWORD
nb_params
;
/* expected number of parameters */
DWORD
params
[
4
];
/* expected parameters */
}
exceptions
[]
=
{
/* test some privileged instructions */
{
{
0x6c
,
0xc3
},
/* insb (%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x6d
,
0xc3
},
/* insl (%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x6e
,
0xc3
},
/* outsb (%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x6f
,
0xc3
},
/* outsl (%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xe4
,
0x11
,
0xc3
},
/* inb $0x11,%al; ret */
0
,
2
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xe5
,
0x11
,
0xc3
},
/* inl $0x11,%eax; ret */
0
,
2
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xe6
,
0x11
,
0xc3
},
/* outb %al,$0x11; ret */
0
,
2
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xe7
,
0x11
,
0xc3
},
/* outl %eax,$0x11; ret */
0
,
2
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xed
,
0xc3
},
/* inl (%dx),%eax; ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xee
,
0xc3
},
/* outb %al,(%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xef
,
0xc3
},
/* outl %eax,(%dx); ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xf4
,
0xc3
},
/* hlt; ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xfa
,
0xc3
},
/* cli; ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0xfb
,
0xc3
},
/* sti; ret */
0
,
1
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
/* test long jump to invalid selector */
{
{
0xea
,
0
,
0
,
0
,
0
,
0
,
0
,
0xc3
},
/* ljmp $0,$0; ret */
0
,
7
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test iret to invalid selector */
{
{
0x6a
,
0x00
,
0x6a
,
0x00
,
0x6a
,
0x00
,
0xcf
,
0x83
,
0xc4
,
0x0c
,
0xc3
},
/* pushl $0; pushl $0; pushl $0; iret; addl $12,%esp; ret */
6
,
1
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test loading an invalid selector */
{
{
0xb8
,
0xef
,
0xbe
,
0x00
,
0x00
,
0x8e
,
0xe8
,
0xc3
},
/* mov $beef,%ax; mov %ax,%gs; ret */
5
,
2
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xbee8
}
},
/* test accessing a zero selector */
{
{
0x06
,
0x31
,
0xc0
,
0x8e
,
0xc0
,
0x26
,
0xa1
,
0
,
0
,
0
,
0
,
0x07
,
0xc3
},
/* push %es; xor %eax,%eax; mov %ax,%es; mov %es:(0),%ax; pop %es */
5
,
6
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test moving %cs -> %ss */
{
{
0x0e
,
0x17
,
0x58
,
0xc3
},
/* pushl %cs; popl %ss; popl %eax; ret */
1
,
1
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test overlong instruction (limit is 16 bytes) */
{
{
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0xfa
,
0xc3
},
0
,
16
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
{
{
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0x64
,
0xfa
,
0xc3
},
0
,
15
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
/* test invalid interrupt */
{
{
0xcd
,
0xff
,
0xc3
},
/* int $0xff; ret */
0
,
2
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test moves to/from Crx */
{
{
0x0f
,
0x20
,
0xc0
,
0xc3
},
/* movl %cr0,%eax; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x20
,
0xe0
,
0xc3
},
/* movl %cr4,%eax; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x22
,
0xc0
,
0xc3
},
/* movl %eax,%cr0; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x22
,
0xe0
,
0xc3
},
/* movl %eax,%cr4; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
/* test moves to/from Drx */
{
{
0x0f
,
0x21
,
0xc0
,
0xc3
},
/* movl %dr0,%eax; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x21
,
0xc8
,
0xc3
},
/* movl %dr1,%eax; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x21
,
0xf8
,
0xc3
},
/* movl %dr7,%eax; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x23
,
0xc0
,
0xc3
},
/* movl %eax,%dr0; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x23
,
0xc8
,
0xc3
},
/* movl %eax,%dr1; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
{
{
0x0f
,
0x23
,
0xf8
,
0xc3
},
/* movl %eax,%dr7; ret */
0
,
3
,
STATUS_PRIVILEGED_INSTRUCTION
,
0
},
/* test memory reads */
{
{
0xa1
,
0xfc
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl 0xfffffffc,%eax; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xfffffffc
}
},
{
{
0xa1
,
0xfd
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl 0xfffffffd,%eax; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
{
{
0xa1
,
0xfe
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl 0xfffffffe,%eax; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
{
{
0xa1
,
0xff
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl 0xffffffff,%eax; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
/* test memory writes */
{
{
0xa3
,
0xfc
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl %eax,0xfffffffc; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
1
,
0xfffffffc
}
},
{
{
0xa3
,
0xfd
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl %eax,0xfffffffd; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
{
{
0xa3
,
0xfe
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl %eax,0xfffffffe; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
{
{
0xa3
,
0xff
,
0xff
,
0xff
,
0xff
,
0xc3
},
/* movl %eax,0xffffffff; ret */
0
,
5
,
STATUS_ACCESS_VIOLATION
,
2
,
{
0
,
0xffffffff
}
},
};
static
int
got_exception
;
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
++
;
trace
(
"exception: %lx flags:%lx addr:%p
\n
"
,
rec
->
ExceptionCode
,
rec
->
ExceptionFlags
,
rec
->
ExceptionAddress
);
ok
(
rec
->
ExceptionCode
==
except
->
status
,
"%u: Wrong exception code %lx/%lx
\n
"
,
entry
,
rec
->
ExceptionCode
,
except
->
status
);
ok
(
rec
->
ExceptionAddress
==
except
->
code
+
except
->
offset
,
"%u: Wrong exception address %p/%p
\n
"
,
entry
,
rec
->
ExceptionAddress
,
except
->
code
+
except
->
offset
);
ok
(
rec
->
NumberParameters
==
except
->
nb_params
,
"%u: Wrong number of parameters %lu/%lu
\n
"
,
entry
,
rec
->
NumberParameters
,
except
->
nb_params
);
for
(
i
=
0
;
i
<
rec
->
NumberParameters
;
i
++
)
ok
(
rec
->
ExceptionInformation
[
i
]
==
except
->
params
[
i
],
"%u: Wrong parameter %d: %lx/%lx
\n
"
,
entry
,
i
,
rec
->
ExceptionInformation
[
i
],
except
->
params
[
i
]
);
/* don't handle exception if it's not the address we expected */
if
(
rec
->
ExceptionAddress
!=
except
->
code
+
except
->
offset
)
return
ExceptionContinueSearch
;
context
->
Eip
+=
except
->
length
;
return
ExceptionContinueExecution
;
}
static
void
test_prot_fault
(
void
)
{
unsigned
int
i
;
struct
{
EXCEPTION_REGISTRATION_RECORD
frame
;
const
struct
exception
*
except
;
}
exc_frame
;
exc_frame
.
frame
.
Handler
=
handler
;
exc_frame
.
frame
.
Prev
=
NtCurrentTeb
()
->
Tib
.
ExceptionList
;
NtCurrentTeb
()
->
Tib
.
ExceptionList
=
&
exc_frame
.
frame
;
for
(
i
=
0
;
i
<
sizeof
(
exceptions
)
/
sizeof
(
exceptions
[
0
]);
i
++
)
{
void
(
*
func
)(
void
)
=
(
void
*
)
exceptions
[
i
].
code
;
exc_frame
.
except
=
&
exceptions
[
i
];
got_exception
=
0
;
func
();
ok
(
got_exception
==
(
exceptions
[
i
].
status
!=
0
),
"%u: bad exception count %d
\n
"
,
i
,
got_exception
);
}
NtCurrentTeb
()
->
Tib
.
ExceptionList
=
exc_frame
.
frame
.
Prev
;
}
#endif
/* __i386__ */
START_TEST
(
exception
)
{
#ifdef __i386__
test_prot_fault
();
#endif
}
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