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
5e8234b3
Commit
5e8234b3
authored
Aug 29, 2019
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Implement stack unwinding on ARM64.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
d2e4a6fa
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
551 additions
and
40 deletions
+551
-40
signal_arm64.c
dlls/ntdll/signal_arm64.c
+551
-40
No files found.
dlls/ntdll/signal_arm64.c
View file @
5e8234b3
...
...
@@ -47,6 +47,10 @@
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
...
...
@@ -137,17 +141,38 @@ static inline int dispatch_signal(unsigned int sig)
return
handlers
[
sig
](
sig
);
}
/***********************************************************************
* get_signal_stack
*
* Get the base of the signal stack for the current thread.
*/
static
inline
void
*
get_signal_stack
(
void
)
{
return
(
char
*
)
NtCurrentTeb
()
+
teb_size
;
}
/*******************************************************************
* is_valid_frame
*/
static
inline
BOOL
is_valid_frame
(
void
*
frame
)
static
inline
BOOL
is_valid_frame
(
ULONG_PTR
frame
)
{
if
(
(
ULONG_PTR
)
frame
&
3
)
return
FALSE
;
return
(
frame
>=
NtCurrentTeb
()
->
Tib
.
StackLimit
&&
if
(
frame
&
7
)
return
FALSE
;
return
(
(
void
*
)
frame
>=
NtCurrentTeb
()
->
Tib
.
StackLimit
&&
(
void
**
)
frame
<
(
void
**
)
NtCurrentTeb
()
->
Tib
.
StackBase
-
1
);
}
/***********************************************************************
* is_inside_signal_stack
*
* Check if pointer is inside the signal stack.
*/
static
inline
BOOL
is_inside_signal_stack
(
void
*
ptr
)
{
return
((
char
*
)
ptr
>=
(
char
*
)
get_signal_stack
()
&&
(
char
*
)
ptr
<
(
char
*
)
get_signal_stack
()
+
signal_stack_size
);
}
/***********************************************************************
* save_context
*
* Set the register values from a sigcontext.
...
...
@@ -525,60 +550,409 @@ static void WINAPI raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *cont
raise_status
(
status
,
rec
);
}
/***********************************************************************
* libunwind_virtual_unwind
*
* Equivalent of RtlVirtualUnwind for builtin modules.
*/
static
NTSTATUS
libunwind_virtual_unwind
(
ULONG_PTR
ip
,
ULONG_PTR
*
frame
,
CONTEXT
*
context
,
PEXCEPTION_ROUTINE
*
handler
,
void
**
handler_data
)
{
#ifdef HAVE_LIBUNWIND
unw_context_t
unw_context
;
unw_cursor_t
cursor
;
unw_proc_info_t
info
;
int
rc
;
memcpy
(
unw_context
.
uc_mcontext
.
regs
,
context
->
u
.
X
,
sizeof
(
context
->
u
.
X
)
);
unw_context
.
uc_mcontext
.
sp
=
context
->
Sp
;
unw_context
.
uc_mcontext
.
pc
=
context
->
Pc
;
rc
=
unw_init_local
(
&
cursor
,
&
unw_context
);
if
(
rc
!=
UNW_ESUCCESS
)
{
WARN
(
"setup failed: %d
\n
"
,
rc
);
return
STATUS_INVALID_DISPOSITION
;
}
rc
=
unw_get_proc_info
(
&
cursor
,
&
info
);
if
(
rc
!=
UNW_ESUCCESS
&&
rc
!=
UNW_ENOINFO
)
{
WARN
(
"failed to get info: %d
\n
"
,
rc
);
return
STATUS_INVALID_DISPOSITION
;
}
if
(
rc
==
UNW_ENOINFO
||
ip
<
info
.
start_ip
||
ip
>
info
.
end_ip
)
{
WARN
(
"no info found for %lx ip %lx-%lx rc %d
\n
"
,
ip
,
info
.
start_ip
,
info
.
end_ip
,
rc
);
return
STATUS_SUCCESS
;
}
TRACE
(
"ip %#lx function %#lx-%#lx personality %#lx lsda %#lx fde %#lx
\n
"
,
ip
,
(
unsigned
long
)
info
.
start_ip
,
(
unsigned
long
)
info
.
end_ip
,
(
unsigned
long
)
info
.
handler
,
(
unsigned
long
)
info
.
lsda
,
(
unsigned
long
)
info
.
unwind_info
);
rc
=
unw_step
(
&
cursor
);
if
(
rc
<
0
)
{
WARN
(
"failed to unwind: %d
\n
"
,
rc
);
return
STATUS_INVALID_DISPOSITION
;
}
*
handler
=
(
void
*
)
info
.
handler
;
*
handler_data
=
(
void
*
)
info
.
lsda
;
*
frame
=
context
->
Sp
;
context
->
Pc
=
context
->
u
.
s
.
Lr
;
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X0
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X0
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X1
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X1
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X2
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X2
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X3
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X3
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X4
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X4
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X5
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X5
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X6
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X6
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X7
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X7
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X8
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X8
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X9
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X9
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X10
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X10
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X11
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X11
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X12
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X12
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X13
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X13
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X14
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X14
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X15
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X15
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X16
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X16
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X17
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X17
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X18
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X18
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X19
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X19
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X20
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X20
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X21
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X21
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X22
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X22
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X23
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X23
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X24
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X24
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X25
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X25
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X26
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X26
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X27
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X27
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X28
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
X28
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X29
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
Fp
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_X30
,
(
unw_word_t
*
)
&
context
->
u
.
s
.
Lr
);
unw_get_reg
(
&
cursor
,
UNW_AARCH64_SP
,
(
unw_word_t
*
)
&
context
->
Sp
);
TRACE
(
"next function pc=%016lx
\n
"
,
context
->
Pc
);
TRACE
(
" x0=%016lx x1=%016lx x2=%016lx x3=%016lx
\n
"
,
context
->
u
.
s
.
X0
,
context
->
u
.
s
.
X1
,
context
->
u
.
s
.
X2
,
context
->
u
.
s
.
X3
);
TRACE
(
" x4=%016lx x5=%016lx x6=%016lx x7=%016lx
\n
"
,
context
->
u
.
s
.
X4
,
context
->
u
.
s
.
X5
,
context
->
u
.
s
.
X6
,
context
->
u
.
s
.
X7
);
TRACE
(
" x8=%016lx x9=%016lx x10=%016lx x11=%016lx
\n
"
,
context
->
u
.
s
.
X8
,
context
->
u
.
s
.
X9
,
context
->
u
.
s
.
X10
,
context
->
u
.
s
.
X11
);
TRACE
(
" x12=%016lx x13=%016lx x14=%016lx x15=%016lx
\n
"
,
context
->
u
.
s
.
X12
,
context
->
u
.
s
.
X13
,
context
->
u
.
s
.
X14
,
context
->
u
.
s
.
X15
);
TRACE
(
" x16=%016lx x17=%016lx x18=%016lx x19=%016lx
\n
"
,
context
->
u
.
s
.
X16
,
context
->
u
.
s
.
X17
,
context
->
u
.
s
.
X18
,
context
->
u
.
s
.
X19
);
TRACE
(
" x20=%016lx x21=%016lx x22=%016lx x23=%016lx
\n
"
,
context
->
u
.
s
.
X20
,
context
->
u
.
s
.
X21
,
context
->
u
.
s
.
X22
,
context
->
u
.
s
.
X23
);
TRACE
(
" x24=%016lx x25=%016lx x26=%016lx x27=%016lx
\n
"
,
context
->
u
.
s
.
X24
,
context
->
u
.
s
.
X25
,
context
->
u
.
s
.
X26
,
context
->
u
.
s
.
X27
);
TRACE
(
" x28=%016lx fp=%016lx lr=%016lx sp=%016lx
\n
"
,
context
->
u
.
s
.
X28
,
context
->
u
.
s
.
Fp
,
context
->
u
.
s
.
Lr
,
context
->
Sp
);
#endif
return
STATUS_SUCCESS
;
}
/**********************************************************************
* virtual_unwind
*/
static
NTSTATUS
virtual_unwind
(
ULONG
type
,
DISPATCHER_CONTEXT
*
dispatch
,
CONTEXT
*
context
)
{
LDR_MODULE
*
module
;
NTSTATUS
status
;
dispatch
->
ImageBase
=
0
;
dispatch
->
ScopeIndex
=
0
;
dispatch
->
EstablisherFrame
=
0
;
dispatch
->
ControlPc
=
context
->
Pc
;
/* first look for PE exception information */
if
((
dispatch
->
FunctionEntry
=
lookup_function_info
(
context
->
Pc
,
&
dispatch
->
ImageBase
,
&
module
)))
{
dispatch
->
LanguageHandler
=
RtlVirtualUnwind
(
type
,
dispatch
->
ImageBase
,
context
->
Pc
,
dispatch
->
FunctionEntry
,
context
,
&
dispatch
->
HandlerData
,
&
dispatch
->
EstablisherFrame
,
NULL
);
return
STATUS_SUCCESS
;
}
/* then look for host system exception information */
if
(
!
module
||
(
module
->
Flags
&
LDR_WINE_INTERNAL
))
{
status
=
libunwind_virtual_unwind
(
context
->
Pc
,
&
dispatch
->
EstablisherFrame
,
context
,
&
dispatch
->
LanguageHandler
,
&
dispatch
->
HandlerData
);
if
(
status
!=
STATUS_SUCCESS
)
return
status
;
if
(
dispatch
->
EstablisherFrame
)
{
dispatch
->
FunctionEntry
=
NULL
;
if
(
dispatch
->
LanguageHandler
&&
!
module
)
{
FIXME
(
"calling personality routine in system library not supported yet
\n
"
);
dispatch
->
LanguageHandler
=
NULL
;
}
return
STATUS_SUCCESS
;
}
}
else
WARN
(
"exception data not found in %s
\n
"
,
debugstr_w
(
module
->
BaseDllName
.
Buffer
)
);
dispatch
->
EstablisherFrame
=
context
->
u
.
s
.
Fp
;
dispatch
->
LanguageHandler
=
NULL
;
context
->
Pc
=
context
->
u
.
s
.
Lr
;
return
STATUS_SUCCESS
;
}
struct
unwind_exception_frame
{
EXCEPTION_REGISTRATION_RECORD
frame
;
DISPATCHER_CONTEXT
*
dispatch
;
};
/**********************************************************************
* unwind_exception_handler
*
* Handler for exceptions happening while calling an unwind handler.
*/
static
DWORD
__cdecl
unwind_exception_handler
(
EXCEPTION_RECORD
*
rec
,
EXCEPTION_REGISTRATION_RECORD
*
frame
,
CONTEXT
*
context
,
EXCEPTION_REGISTRATION_RECORD
**
dispatcher
)
{
struct
unwind_exception_frame
*
unwind_frame
=
(
struct
unwind_exception_frame
*
)
frame
;
DISPATCHER_CONTEXT
*
dispatch
=
(
DISPATCHER_CONTEXT
*
)
dispatcher
;
/* copy the original dispatcher into the current one, except for the TargetIp */
dispatch
->
ControlPc
=
unwind_frame
->
dispatch
->
ControlPc
;
dispatch
->
ImageBase
=
unwind_frame
->
dispatch
->
ImageBase
;
dispatch
->
FunctionEntry
=
unwind_frame
->
dispatch
->
FunctionEntry
;
dispatch
->
EstablisherFrame
=
unwind_frame
->
dispatch
->
EstablisherFrame
;
dispatch
->
ContextRecord
=
unwind_frame
->
dispatch
->
ContextRecord
;
dispatch
->
LanguageHandler
=
unwind_frame
->
dispatch
->
LanguageHandler
;
dispatch
->
HandlerData
=
unwind_frame
->
dispatch
->
HandlerData
;
dispatch
->
HistoryTable
=
unwind_frame
->
dispatch
->
HistoryTable
;
dispatch
->
ScopeIndex
=
unwind_frame
->
dispatch
->
ScopeIndex
;
TRACE
(
"detected collided unwind
\n
"
);
return
ExceptionCollidedUnwind
;
}
/**********************************************************************
* call_unwind_handler
*
* Call a single unwind handler.
*/
static
DWORD
call_unwind_handler
(
EXCEPTION_RECORD
*
rec
,
DISPATCHER_CONTEXT
*
dispatch
)
{
struct
unwind_exception_frame
frame
;
DWORD
res
;
frame
.
frame
.
Handler
=
unwind_exception_handler
;
frame
.
dispatch
=
dispatch
;
__wine_push_frame
(
&
frame
.
frame
);
TRACE
(
"calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)
\n
"
,
dispatch
->
LanguageHandler
,
rec
,
dispatch
->
EstablisherFrame
,
dispatch
->
ContextRecord
,
dispatch
);
res
=
dispatch
->
LanguageHandler
(
rec
,
(
void
*
)
dispatch
->
EstablisherFrame
,
dispatch
->
ContextRecord
,
dispatch
);
TRACE
(
"handler %p returned %x
\n
"
,
dispatch
->
LanguageHandler
,
res
);
__wine_pop_frame
(
&
frame
.
frame
);
switch
(
res
)
{
case
ExceptionContinueSearch
:
case
ExceptionCollidedUnwind
:
break
;
default:
raise_status
(
STATUS_INVALID_DISPOSITION
,
rec
);
break
;
}
return
res
;
}
/**********************************************************************
* call_teb_unwind_handler
*
* Call a single unwind handler from the TEB chain.
*/
static
DWORD
call_teb_unwind_handler
(
EXCEPTION_RECORD
*
rec
,
DISPATCHER_CONTEXT
*
dispatch
,
EXCEPTION_REGISTRATION_RECORD
*
teb_frame
)
{
DWORD
res
;
TRACE
(
"calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)
\n
"
,
teb_frame
->
Handler
,
rec
,
teb_frame
,
dispatch
->
ContextRecord
,
dispatch
);
res
=
teb_frame
->
Handler
(
rec
,
teb_frame
,
dispatch
->
ContextRecord
,
(
EXCEPTION_REGISTRATION_RECORD
**
)
dispatch
);
TRACE
(
"handler at %p returned %u
\n
"
,
teb_frame
->
Handler
,
res
);
switch
(
res
)
{
case
ExceptionContinueSearch
:
case
ExceptionCollidedUnwind
:
break
;
default:
raise_status
(
STATUS_INVALID_DISPOSITION
,
rec
);
break
;
}
return
res
;
}
static
DWORD
__cdecl
nested_exception_handler
(
EXCEPTION_RECORD
*
rec
,
EXCEPTION_REGISTRATION_RECORD
*
frame
,
CONTEXT
*
context
,
EXCEPTION_REGISTRATION_RECORD
**
dispatcher
)
{
if
(
rec
->
ExceptionFlags
&
(
EH_UNWINDING
|
EH_EXIT_UNWIND
))
return
ExceptionContinueSearch
;
/* FIXME */
return
ExceptionNestedException
;
}
/**********************************************************************
* call_handler
*
* Call a single exception handler.
* FIXME: Handle nested exceptions.
*/
static
DWORD
call_handler
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatch
)
{
EXCEPTION_REGISTRATION_RECORD
frame
;
DWORD
res
;
frame
.
Handler
=
nested_exception_handler
;
__wine_push_frame
(
&
frame
);
TRACE
(
"calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)
\n
"
,
dispatch
->
LanguageHandler
,
rec
,
dispatch
->
EstablisherFrame
,
dispatch
->
ContextRecord
,
dispatch
);
res
=
dispatch
->
LanguageHandler
(
rec
,
(
void
*
)
dispatch
->
EstablisherFrame
,
context
,
dispatch
);
TRACE
(
"handler at %p returned %u
\n
"
,
dispatch
->
LanguageHandler
,
res
);
__wine_pop_frame
(
&
frame
);
return
res
;
}
/**********************************************************************
* call_
stack_handlers
* call_
teb_handler
*
* Call the stack handlers chain.
* Call a single exception handler from the TEB chain.
* FIXME: Handle nested exceptions.
*/
static
NTSTATUS
call_stack_handlers
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
)
static
DWORD
call_teb_handler
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatch
,
EXCEPTION_REGISTRATION_RECORD
*
teb_frame
)
{
EXCEPTION_REGISTRATION_RECORD
*
frame
,
*
dispatch
,
*
nested_frame
;
DWORD
res
;
frame
=
NtCurrentTeb
()
->
Tib
.
ExceptionList
;
nested_frame
=
NULL
;
while
(
frame
!=
(
EXCEPTION_REGISTRATION_RECORD
*
)
~
0UL
)
TRACE
(
"calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)
\n
"
,
teb_frame
->
Handler
,
rec
,
teb_frame
,
dispatch
->
ContextRecord
,
dispatch
);
res
=
teb_frame
->
Handler
(
rec
,
teb_frame
,
context
,
(
EXCEPTION_REGISTRATION_RECORD
**
)
dispatch
);
TRACE
(
"handler at %p returned %u
\n
"
,
teb_frame
->
Handler
,
res
);
return
res
;
}
/**********************************************************************
* call_function_handlers
*
* Call the per-function handlers.
*/
static
NTSTATUS
call_function_handlers
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
orig_context
)
{
EXCEPTION_REGISTRATION_RECORD
*
teb_frame
=
NtCurrentTeb
()
->
Tib
.
ExceptionList
;
UNWIND_HISTORY_TABLE
table
;
DISPATCHER_CONTEXT
dispatch
;
CONTEXT
context
;
NTSTATUS
status
;
context
=
*
orig_context
;
dispatch
.
TargetPc
=
0
;
dispatch
.
ContextRecord
=
&
context
;
dispatch
.
HistoryTable
=
&
table
;
for
(;;)
{
/* Check frame address */
if
(
!
is_valid_frame
(
frame
))
status
=
virtual_unwind
(
UNW_FLAG_EHANDLER
,
&
dispatch
,
&
context
);
if
(
status
!=
STATUS_SUCCESS
)
return
status
;
unwind_done:
if
(
!
dispatch
.
EstablisherFrame
)
break
;
if
(
!
is_valid_frame
(
dispatch
.
EstablisherFrame
))
{
ERR
(
"invalid frame %lx (%p-%p)
\n
"
,
dispatch
.
EstablisherFrame
,
NtCurrentTeb
()
->
Tib
.
StackLimit
,
NtCurrentTeb
()
->
Tib
.
StackBase
);
rec
->
ExceptionFlags
|=
EH_STACK_INVALID
;
break
;
}
/* Call handler */
TRACE
(
"calling handler at %p code=%x flags=%x
\n
"
,
frame
->
Handler
,
rec
->
ExceptionCode
,
rec
->
ExceptionFlags
);
res
=
frame
->
Handler
(
rec
,
frame
,
context
,
&
dispatch
);
TRACE
(
"handler at %p returned %x
\n
"
,
frame
->
Handler
,
res
);
if
(
frame
==
nested_frame
)
if
(
dispatch
.
LanguageHandler
)
{
/* no longer nested */
nested_frame
=
NULL
;
rec
->
ExceptionFlags
&=
~
EH_NESTED_CALL
;
switch
(
call_handler
(
rec
,
orig_context
,
&
dispatch
))
{
case
ExceptionContinueExecution
:
if
(
rec
->
ExceptionFlags
&
EH_NONCONTINUABLE
)
return
STATUS_NONCONTINUABLE_EXCEPTION
;
return
STATUS_SUCCESS
;
case
ExceptionContinueSearch
:
break
;
case
ExceptionNestedException
:
FIXME
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
{
ULONG64
frame
;
context
=
*
dispatch
.
ContextRecord
;
dispatch
.
ContextRecord
=
&
context
;
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
context
,
NULL
,
&
frame
,
NULL
);
goto
unwind_done
;
}
default:
return
STATUS_INVALID_DISPOSITION
;
}
}
switch
(
res
)
/* hack: call wine handlers registered in the tib list */
else
while
((
ULONG64
)
teb_frame
<
context
.
Sp
)
{
case
ExceptionContinueExecution
:
if
(
!
(
rec
->
ExceptionFlags
&
EH_NONCONTINUABLE
))
return
STATUS_SUCCESS
;
return
STATUS_NONCONTINUABLE_EXCEPTION
;
case
ExceptionContinueSearch
:
break
;
case
ExceptionNestedException
:
if
(
nested_frame
<
dispatch
)
nested_frame
=
dispatch
;
rec
->
ExceptionFlags
|=
EH_NESTED_CALL
;
break
;
default
:
return
STATUS_INVALID_DISPOSITION
;
TRACE
(
"found wine frame %p rsp %lx handler %p
\n
"
,
teb_frame
,
context
.
Sp
,
teb_frame
->
Handler
);
dispatch
.
EstablisherFrame
=
(
ULONG64
)
teb_frame
;
switch
(
call_teb_handler
(
rec
,
orig_context
,
&
dispatch
,
teb_frame
))
{
case
ExceptionContinueExecution
:
if
(
rec
->
ExceptionFlags
&
EH_NONCONTINUABLE
)
return
STATUS_NONCONTINUABLE_EXCEPTION
;
return
STATUS_SUCCESS
;
case
ExceptionContinueSearch
:
break
;
case
ExceptionNestedException
:
FIXME
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
{
ULONG64
frame
;
context
=
*
dispatch
.
ContextRecord
;
dispatch
.
ContextRecord
=
&
context
;
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
context
,
NULL
,
&
frame
,
NULL
);
teb_frame
=
teb_frame
->
Prev
;
goto
unwind_done
;
}
default:
return
STATUS_INVALID_DISPOSITION
;
}
teb_frame
=
teb_frame
->
Prev
;
}
frame
=
frame
->
Prev
;
if
(
context
.
Sp
==
(
ULONG64
)
NtCurrentTeb
()
->
Tib
.
StackBase
)
break
;
}
return
STATUS_UNHANDLED_EXCEPTION
;
}
/*******************************************************************
* raise_exception
*
...
...
@@ -637,7 +1011,7 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f
if
(
call_vectored_handlers
(
rec
,
context
)
==
EXCEPTION_CONTINUE_EXECUTION
)
return
STATUS_SUCCESS
;
if
((
status
=
call_
stack
_handlers
(
rec
,
context
))
!=
STATUS_UNHANDLED_EXCEPTION
)
if
((
status
=
call_
function
_handlers
(
rec
,
context
))
!=
STATUS_UNHANDLED_EXCEPTION
)
return
status
;
}
...
...
@@ -1378,13 +1752,150 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc,
}
/*******************************************************************
* RtlUnwindEx (NTDLL.@)
*/
void
WINAPI
RtlUnwindEx
(
PVOID
end_frame
,
PVOID
target_ip
,
EXCEPTION_RECORD
*
rec
,
PVOID
retval
,
CONTEXT
*
context
,
UNWIND_HISTORY_TABLE
*
table
)
{
EXCEPTION_REGISTRATION_RECORD
*
teb_frame
=
NtCurrentTeb
()
->
Tib
.
ExceptionList
;
EXCEPTION_RECORD
record
;
DISPATCHER_CONTEXT
dispatch
;
CONTEXT
new_context
;
NTSTATUS
status
;
DWORD
i
;
RtlCaptureContext
(
context
);
new_context
=
*
context
;
/* build an exception record, if we do not have one */
if
(
!
rec
)
{
record
.
ExceptionCode
=
STATUS_UNWIND
;
record
.
ExceptionFlags
=
0
;
record
.
ExceptionRecord
=
NULL
;
record
.
ExceptionAddress
=
(
void
*
)
context
->
Pc
;
record
.
NumberParameters
=
0
;
rec
=
&
record
;
}
rec
->
ExceptionFlags
|=
EH_UNWINDING
|
(
end_frame
?
0
:
EH_EXIT_UNWIND
);
TRACE
(
"code=%x flags=%x end_frame=%p target_ip=%p pc=%016lx
\n
"
,
rec
->
ExceptionCode
,
rec
->
ExceptionFlags
,
end_frame
,
target_ip
,
context
->
Pc
);
for
(
i
=
0
;
i
<
min
(
EXCEPTION_MAXIMUM_PARAMETERS
,
rec
->
NumberParameters
);
i
++
)
TRACE
(
" info[%d]=%016lx
\n
"
,
i
,
rec
->
ExceptionInformation
[
i
]
);
TRACE
(
" x0=%016lx x1=%016lx x2=%016lx x3=%016lx
\n
"
,
context
->
u
.
s
.
X0
,
context
->
u
.
s
.
X1
,
context
->
u
.
s
.
X2
,
context
->
u
.
s
.
X3
);
TRACE
(
" x4=%016lx x5=%016lx x6=%016lx x7=%016lx
\n
"
,
context
->
u
.
s
.
X4
,
context
->
u
.
s
.
X5
,
context
->
u
.
s
.
X6
,
context
->
u
.
s
.
X7
);
TRACE
(
" x8=%016lx x9=%016lx x10=%016lx x11=%016lx
\n
"
,
context
->
u
.
s
.
X8
,
context
->
u
.
s
.
X9
,
context
->
u
.
s
.
X10
,
context
->
u
.
s
.
X11
);
TRACE
(
" x12=%016lx x13=%016lx x14=%016lx x15=%016lx
\n
"
,
context
->
u
.
s
.
X12
,
context
->
u
.
s
.
X13
,
context
->
u
.
s
.
X14
,
context
->
u
.
s
.
X15
);
TRACE
(
" x16=%016lx x17=%016lx x18=%016lx x19=%016lx
\n
"
,
context
->
u
.
s
.
X16
,
context
->
u
.
s
.
X17
,
context
->
u
.
s
.
X18
,
context
->
u
.
s
.
X19
);
TRACE
(
" x20=%016lx x21=%016lx x22=%016lx x23=%016lx
\n
"
,
context
->
u
.
s
.
X20
,
context
->
u
.
s
.
X21
,
context
->
u
.
s
.
X22
,
context
->
u
.
s
.
X23
);
TRACE
(
" x24=%016lx x25=%016lx x26=%016lx x27=%016lx
\n
"
,
context
->
u
.
s
.
X24
,
context
->
u
.
s
.
X25
,
context
->
u
.
s
.
X26
,
context
->
u
.
s
.
X27
);
TRACE
(
" x28=%016lx fp=%016lx lr=%016lx sp=%016lx
\n
"
,
context
->
u
.
s
.
X28
,
context
->
u
.
s
.
Fp
,
context
->
u
.
s
.
Lr
,
context
->
Sp
);
dispatch
.
EstablisherFrame
=
context
->
Sp
;
dispatch
.
TargetPc
=
(
ULONG64
)
target_ip
;
dispatch
.
ContextRecord
=
context
;
dispatch
.
HistoryTable
=
table
;
for
(;;)
{
status
=
virtual_unwind
(
UNW_FLAG_UHANDLER
,
&
dispatch
,
&
new_context
);
if
(
status
!=
STATUS_SUCCESS
)
raise_status
(
status
,
rec
);
unwind_done:
if
(
!
dispatch
.
EstablisherFrame
)
break
;
if
(
is_inside_signal_stack
(
(
void
*
)
dispatch
.
EstablisherFrame
))
{
TRACE
(
"frame %lx is inside signal stack (%p-%p)
\n
"
,
dispatch
.
EstablisherFrame
,
get_signal_stack
(),
(
char
*
)
get_signal_stack
()
+
signal_stack_size
);
*
context
=
new_context
;
continue
;
}
if
(
!
is_valid_frame
(
dispatch
.
EstablisherFrame
))
{
ERR
(
"invalid frame %lx (%p-%p)
\n
"
,
dispatch
.
EstablisherFrame
,
NtCurrentTeb
()
->
Tib
.
StackLimit
,
NtCurrentTeb
()
->
Tib
.
StackBase
);
rec
->
ExceptionFlags
|=
EH_STACK_INVALID
;
break
;
}
if
(
dispatch
.
LanguageHandler
)
{
if
(
end_frame
&&
(
dispatch
.
EstablisherFrame
>
(
ULONG64
)
end_frame
))
{
ERR
(
"invalid end frame %lx/%p
\n
"
,
dispatch
.
EstablisherFrame
,
end_frame
);
raise_status
(
STATUS_INVALID_UNWIND_TARGET
,
rec
);
}
if
(
dispatch
.
EstablisherFrame
==
(
ULONG64
)
end_frame
)
rec
->
ExceptionFlags
|=
EH_TARGET_UNWIND
;
if
(
call_unwind_handler
(
rec
,
&
dispatch
)
==
ExceptionCollidedUnwind
)
{
ULONG64
frame
;
*
context
=
new_context
=
*
dispatch
.
ContextRecord
;
dispatch
.
ContextRecord
=
context
;
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
new_context
,
NULL
,
&
frame
,
NULL
);
rec
->
ExceptionFlags
|=
EH_COLLIDED_UNWIND
;
goto
unwind_done
;
}
rec
->
ExceptionFlags
&=
~
EH_COLLIDED_UNWIND
;
}
else
/* hack: call builtin handlers registered in the tib list */
{
DWORD64
backup_frame
=
dispatch
.
EstablisherFrame
;
while
((
ULONG64
)
teb_frame
<
new_context
.
Sp
&&
(
ULONG64
)
teb_frame
<
(
ULONG64
)
end_frame
)
{
TRACE
(
"found builtin frame %p handler %p
\n
"
,
teb_frame
,
teb_frame
->
Handler
);
dispatch
.
EstablisherFrame
=
(
ULONG64
)
teb_frame
;
if
(
call_teb_unwind_handler
(
rec
,
&
dispatch
,
teb_frame
)
==
ExceptionCollidedUnwind
)
{
ULONG64
frame
;
teb_frame
=
__wine_pop_frame
(
teb_frame
);
*
context
=
new_context
=
*
dispatch
.
ContextRecord
;
dispatch
.
ContextRecord
=
context
;
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
new_context
,
NULL
,
&
frame
,
NULL
);
rec
->
ExceptionFlags
|=
EH_COLLIDED_UNWIND
;
goto
unwind_done
;
}
teb_frame
=
__wine_pop_frame
(
teb_frame
);
}
if
((
ULONG64
)
teb_frame
==
(
ULONG64
)
end_frame
&&
(
ULONG64
)
end_frame
<
new_context
.
Sp
)
break
;
dispatch
.
EstablisherFrame
=
backup_frame
;
}
if
(
dispatch
.
EstablisherFrame
==
(
ULONG64
)
end_frame
)
break
;
*
context
=
new_context
;
}
context
->
u
.
s
.
X0
=
(
ULONG64
)
retval
;
context
->
Pc
=
(
ULONG64
)
target_ip
;
set_cpu_context
(
context
);
}
/***********************************************************************
* RtlUnwind (NTDLL.@)
*/
void
WINAPI
RtlUnwind
(
PVOID
pEndFrame
,
PVOID
targetIp
,
PEXCEPTION_RECORD
pRecord
,
PVOID
retval
)
void
WINAPI
RtlUnwind
(
void
*
frame
,
void
*
target_ip
,
EXCEPTION_RECORD
*
rec
,
void
*
retval
)
{
FIXME
(
"Not implemented on ARM64
\n
"
);
CONTEXT
context
;
RtlUnwindEx
(
frame
,
target_ip
,
rec
,
retval
,
&
context
,
NULL
);
}
/*******************************************************************
...
...
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