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
9bbdf6c7
Commit
9bbdf6c7
authored
Nov 30, 2023
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Fix stack layout and unwind information for KiUserExceptionDispatcher on ARM64.
parent
1e4db62e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
141 additions
and
94 deletions
+141
-94
signal_arm64.c
dlls/ntdll/signal_arm64.c
+19
-6
exception.c
dlls/ntdll/tests/exception.c
+101
-0
signal_arm64.c
dlls/ntdll/unix/signal_arm64.c
+21
-88
No files found.
dlls/ntdll/signal_arm64.c
View file @
9bbdf6c7
...
...
@@ -491,16 +491,11 @@ static NTSTATUS call_function_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_con
}
/*******************************************************************
* KiUserExceptionDispatcher (NTDLL.@)
*/
NTSTATUS
WINAPI
KiUserExceptionDispatcher
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
)
NTSTATUS
WINAPI
dispatch_exception
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
)
{
NTSTATUS
status
;
DWORD
c
;
if
(
pWow64PrepareForException
)
pWow64PrepareForException
(
rec
,
context
);
TRACE
(
"code=%lx flags=%lx addr=%p pc=%016I64x
\n
"
,
rec
->
ExceptionCode
,
rec
->
ExceptionFlags
,
rec
->
ExceptionAddress
,
context
->
Pc
);
for
(
c
=
0
;
c
<
rec
->
NumberParameters
;
c
++
)
...
...
@@ -572,6 +567,24 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
/*******************************************************************
* KiUserExceptionDispatcher (NTDLL.@)
*/
__ASM_GLOBAL_FUNC
(
KiUserExceptionDispatcher
,
__ASM_SEH
(
".seh_context
\n\t
"
)
__ASM_SEH
(
".seh_endprologue
\n\t
"
)
"adr x16, "
__ASM_NAME
(
"pWow64PrepareForException"
)
"
\n\t
"
"ldr x16, [x16]
\n\t
"
"cbz x16, 1f
\n\t
"
"add x0, sp, #0x390
\n\t
"
/* rec (context + 1) */
"mov x1, sp
\n\t
"
/* context */
"blr x16
\n
"
"1:
\t
add x0, sp, #0x390
\n\t
"
/* rec (context + 1) */
"mov x1, sp
\n\t
"
/* context */
"bl "
__ASM_NAME
(
"dispatch_exception"
)
"
\n\t
"
"brk #1"
)
/*******************************************************************
* KiUserApcDispatcher (NTDLL.@)
*/
void
WINAPI
KiUserApcDispatcher
(
CONTEXT
*
context
,
ULONG_PTR
arg1
,
ULONG_PTR
arg2
,
ULONG_PTR
arg3
,
...
...
dlls/ntdll/tests/exception.c
View file @
9bbdf6c7
...
...
@@ -8566,6 +8566,106 @@ static void test_continue(void)
}
#undef COMPARE
}
static
BOOL
hook_called
;
static
BOOL
got_exception
;
static
ULONG
patched_code
[]
=
{
0x910003e0
,
/* mov x0, sp */
0x5800004f
,
/* ldr x15, 1f */
0xd61f01e0
,
/* br x15 */
0
,
0
,
/* 1: hook_trampoline */
};
static
ULONG
saved_code
[
ARRAY_SIZE
(
patched_code
)];
static
LONG
WINAPI
dbg_except_continue_vectored_handler
(
struct
_EXCEPTION_POINTERS
*
ptrs
)
{
EXCEPTION_RECORD
*
rec
=
ptrs
->
ExceptionRecord
;
CONTEXT
*
context
=
ptrs
->
ContextRecord
;
trace
(
"dbg_except_continue_vectored_handler, code %#lx, pc %#Ix.
\n
"
,
rec
->
ExceptionCode
,
context
->
Pc
);
got_exception
=
TRUE
;
ok
(
rec
->
ExceptionCode
==
0x80000003
,
"Got unexpected exception code %#lx.
\n
"
,
rec
->
ExceptionCode
);
return
EXCEPTION_CONTINUE_EXECUTION
;
}
static
void
*
WINAPI
hook_KiUserExceptionDispatcher
(
void
*
stack
)
{
CONTEXT
*
context
=
stack
;
EXCEPTION_RECORD
*
rec
=
(
EXCEPTION_RECORD
*
)(
context
+
1
);
trace
(
"rec %p context %p pc %#Ix sp %#Ix flags %#lx
\n
"
,
rec
,
context
,
context
->
Pc
,
context
->
Sp
,
context
->
ContextFlags
);
ok
(
!
((
ULONG_PTR
)
stack
&
15
),
"unaligned stack %p
\n
"
,
stack
);
ok
(
rec
->
ExceptionCode
==
0x80000003
,
"Got unexpected ExceptionCode %#lx.
\n
"
,
rec
->
ExceptionCode
);
hook_called
=
TRUE
;
memcpy
(
pKiUserExceptionDispatcher
,
saved_code
,
sizeof
(
saved_code
));
FlushInstructionCache
(
GetCurrentProcess
(),
pKiUserExceptionDispatcher
,
sizeof
(
saved_code
));
return
pKiUserExceptionDispatcher
;
}
static
void
test_KiUserExceptionDispatcher
(
void
)
{
ULONG
hook_trampoline
[]
=
{
0x910003e0
,
/* mov x0, sp */
0x5800006f
,
/* ldr x15, 1f */
0xd63f01e0
,
/* blr x15 */
0xd61f0000
,
/* br x0 */
0
,
0
,
/* 1: hook_KiUserExceptionDispatcher */
};
EXCEPTION_RECORD
record
=
{
EXCEPTION_BREAKPOINT
};
void
*
trampoline_ptr
,
*
vectored_handler
;
DWORD
old_protect
;
BOOL
ret
;
*
(
void
**
)
&
hook_trampoline
[
4
]
=
hook_KiUserExceptionDispatcher
;
trampoline_ptr
=
(
char
*
)
code_mem
+
1024
;
memcpy
(
trampoline_ptr
,
hook_trampoline
,
sizeof
(
hook_trampoline
));
ret
=
VirtualProtect
(
pKiUserExceptionDispatcher
,
sizeof
(
saved_code
),
PAGE_EXECUTE_READWRITE
,
&
old_protect
);
ok
(
ret
,
"Got unexpected ret %#x, GetLastError() %lu.
\n
"
,
ret
,
GetLastError
()
);
memcpy
(
saved_code
,
pKiUserExceptionDispatcher
,
sizeof
(
saved_code
)
);
*
(
void
**
)
&
patched_code
[
3
]
=
trampoline_ptr
;
vectored_handler
=
AddVectoredExceptionHandler
(
TRUE
,
dbg_except_continue_vectored_handler
);
memcpy
(
pKiUserExceptionDispatcher
,
patched_code
,
sizeof
(
patched_code
)
);
FlushInstructionCache
(
GetCurrentProcess
(),
pKiUserExceptionDispatcher
,
sizeof
(
patched_code
));
got_exception
=
FALSE
;
hook_called
=
FALSE
;
pRtlRaiseException
(
&
record
);
ok
(
got_exception
,
"Handler was not called.
\n
"
);
todo_wine
ok
(
!
hook_called
,
"Hook was called.
\n
"
);
memcpy
(
pKiUserExceptionDispatcher
,
patched_code
,
sizeof
(
patched_code
)
);
FlushInstructionCache
(
GetCurrentProcess
(),
pKiUserExceptionDispatcher
,
sizeof
(
patched_code
));
got_exception
=
0
;
hook_called
=
FALSE
;
NtCurrentTeb
()
->
Peb
->
BeingDebugged
=
1
;
pRtlRaiseException
(
&
record
);
ok
(
got_exception
,
"Handler was not called.
\n
"
);
ok
(
hook_called
,
"Hook was not called.
\n
"
);
NtCurrentTeb
()
->
Peb
->
BeingDebugged
=
0
;
RemoveVectoredExceptionHandler
(
vectored_handler
);
VirtualProtect
(
pKiUserExceptionDispatcher
,
sizeof
(
saved_code
),
old_protect
,
&
old_protect
);
}
#endif
/* __aarch64__ */
#if defined(__i386__) || defined(__x86_64__)
...
...
@@ -11828,6 +11928,7 @@ START_TEST(exception)
test_continue
();
test_virtual_unwind
();
test_KiUserExceptionDispatcher
();
#elif defined(__arm__)
...
...
dlls/ntdll/unix/signal_arm64.c
View file @
9bbdf6c7
...
...
@@ -127,6 +127,17 @@ static DWORD64 get_fault_esr( ucontext_t *sigcontext )
#endif
/* linux */
/* stack layout when calling KiUserExceptionDispatcher */
struct
exc_stack_layout
{
CONTEXT
context
;
/* 000 */
EXCEPTION_RECORD
rec
;
/* 390 */
ULONG64
align
;
/* 428 */
ULONG64
redzone
[
2
];
/* 430 */
};
C_ASSERT
(
offsetof
(
struct
exc_stack_layout
,
rec
)
==
0x390
);
C_ASSERT
(
sizeof
(
struct
exc_stack_layout
)
==
0x440
);
struct
syscall_frame
{
ULONG64
x
[
29
];
/* 000 */
...
...
@@ -167,8 +178,6 @@ static BOOL is_inside_syscall( ucontext_t *sigcontext )
(
char
*
)
SP_sig
(
sigcontext
)
<=
(
char
*
)
arm64_thread_data
()
->
syscall_frame
);
}
extern
void
raise_func_trampoline
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
,
void
*
dispatcher
);
/***********************************************************************
* dwarf_virtual_unwind
*
...
...
@@ -185,7 +194,6 @@ static NTSTATUS dwarf_virtual_unwind( ULONG64 ip, ULONG64 *frame, CONTEXT *conte
struct
frame_state
state_stack
[
MAX_SAVED_STATES
];
int
aug_z_format
=
0
;
unsigned
char
lsda_encoding
=
DW_EH_PE_omit
;
DWORD64
prev_x28
=
context
->
X28
;
memset
(
&
info
,
0
,
sizeof
(
info
)
);
info
.
state_stack
=
state_stack
;
...
...
@@ -274,17 +282,6 @@ static NTSTATUS dwarf_virtual_unwind( ULONG64 ip, ULONG64 *frame, CONTEXT *conte
/* Set Pc based on Lr; libunwind also does this as part of unw_step. */
context
->
Pc
=
context
->
Lr
;
if
(
bases
->
func
==
(
void
*
)
raise_func_trampoline
)
{
/* raise_func_trampoline has a pointer to a full CONTEXT stored in x28;
* restore the original Lr value from there. The function we unwind to
* might be a leaf function that hasn't backed up its own original Lr
* value on the stack.
* We could also just restore the full context here without doing
* unw_step at all. */
const
CONTEXT
*
next_ctx
=
(
const
CONTEXT
*
)
prev_x28
;
context
->
Lr
=
next_ctx
->
Lr
;
}
TRACE
(
"next function pc=%016lx
\n
"
,
context
->
Pc
);
TRACE
(
" x0=%016lx x1=%016lx x2=%016lx x3=%016lx
\n
"
,
context
->
X0
,
context
->
X1
,
context
->
X2
,
context
->
X3
);
...
...
@@ -315,7 +312,6 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
unw_cursor_t
cursor
;
unw_proc_info_t
info
;
int
rc
;
DWORD64
prev_x28
=
context
->
X28
;
#ifdef __APPLE__
rc
=
unw_getcontext
(
&
unw_context
);
...
...
@@ -421,17 +417,6 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
unw_get_reg
(
&
cursor
,
UNW_REG_IP
,
(
unw_word_t
*
)
&
context
->
Pc
);
context
->
ContextFlags
|=
CONTEXT_UNWOUND_TO_CALL
;
if
(
info
.
start_ip
==
(
unw_word_t
)
raise_func_trampoline
)
{
/* raise_func_trampoline has a pointer to a full CONTEXT stored in x28;
* restore the original Lr value from there. The function we unwind to
* might be a leaf function that hasn't backed up its own original Lr
* value on the stack.
* We could also just restore the full context here without doing
* unw_step at all. */
const
CONTEXT
*
next_ctx
=
(
const
CONTEXT
*
)
prev_x28
;
context
->
Lr
=
next_ctx
->
Lr
;
}
TRACE
(
"next function pc=%016lx%s
\n
"
,
context
->
Pc
,
rc
?
""
:
" (last frame)"
);
TRACE
(
" x0=%016lx x1=%016lx x2=%016lx x3=%016lx
\n
"
,
context
->
X0
,
context
->
X1
,
context
->
X2
,
context
->
X3
);
...
...
@@ -951,45 +936,6 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
}
/* Note, unwind_builtin_dll above has hardcoded assumptions on how this
* function stores a CONTEXT pointer in x28; if modified, modify that one in
* sync as well. */
__ASM_GLOBAL_FUNC
(
raise_func_trampoline
,
"stp x29, x30, [sp, #-0x20]!
\n\t
"
"str x28, [sp, #0x10]
\n\t
"
__ASM_CFI
(
".cfi_def_cfa_offset 32
\n\t
"
)
__ASM_CFI
(
".cfi_offset 29, -32
\n\t
"
)
__ASM_CFI
(
".cfi_offset 30, -24
\n\t
"
)
__ASM_CFI
(
".cfi_offset 28, -16
\n\t
"
)
"mov x29, sp
\n\t
"
__ASM_CFI
(
".cfi_def_cfa_register 29
\n\t
"
)
__ASM_CFI
(
".cfi_remember_state
\n\t
"
)
"mov x28, x1
\n\t
"
__ASM_CFI_REG_IS_AT2
(
x19
,
x28
,
0xa0
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x20
,
x28
,
0xa8
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x21
,
x28
,
0xb0
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x22
,
x28
,
0xb8
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x23
,
x28
,
0xc0
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x24
,
x28
,
0xc8
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x25
,
x28
,
0xd0
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x26
,
x28
,
0xd8
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x27
,
x28
,
0xe0
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x28
,
x28
,
0xe8
,
0x01
)
__ASM_CFI_REG_IS_AT2
(
x29
,
x28
,
0xf0
,
0x01
)
__ASM_CFI_CFA_IS_AT2
(
x28
,
0x80
,
0x02
)
__ASM_CFI_REG_IS_AT2
(
x30
,
x28
,
0x88
,
0x02
)
__ASM_CFI_REG_IS_AT2
(
v8
,
x28
,
0x90
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v9
,
x28
,
0x98
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v10
,
x28
,
0xa0
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v11
,
x28
,
0xa8
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v12
,
x28
,
0xb0
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v13
,
x28
,
0xb8
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v14
,
x28
,
0xc8
,
0x03
)
__ASM_CFI_REG_IS_AT2
(
v15
,
x28
,
0xc8
,
0x03
)
"blr x2
\n\t
"
__ASM_CFI
(
".cfi_restore_state
\n\t
"
)
"brk #1"
)
/***********************************************************************
* setup_exception
*
...
...
@@ -997,13 +943,7 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
*/
static
void
setup_exception
(
ucontext_t
*
sigcontext
,
EXCEPTION_RECORD
*
rec
)
{
struct
{
CONTEXT
context
;
EXCEPTION_RECORD
rec
;
void
*
redzone
[
3
];
}
*
stack
;
struct
exc_stack_layout
*
stack
;
void
*
stack_ptr
=
(
void
*
)(
SP_sig
(
sigcontext
)
&
~
15
);
CONTEXT
context
;
NTSTATUS
status
;
...
...
@@ -1021,16 +961,12 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if
(
rec
->
ExceptionCode
==
EXCEPTION_BREAKPOINT
)
context
.
Pc
-=
4
;
stack
=
virtual_setup_exception
(
stack_ptr
,
(
sizeof
(
*
stack
)
+
15
)
&
~
15
,
rec
);
stack
=
virtual_setup_exception
(
stack_ptr
,
sizeof
(
*
stack
)
,
rec
);
stack
->
rec
=
*
rec
;
stack
->
context
=
context
;
SP_sig
(
sigcontext
)
=
(
ULONG_PTR
)
stack
;
LR_sig
(
sigcontext
)
=
PC_sig
(
sigcontext
);
PC_sig
(
sigcontext
)
=
(
ULONG_PTR
)
raise_func_trampoline
;
REGn_sig
(
0
,
sigcontext
)
=
(
ULONG_PTR
)
&
stack
->
rec
;
/* first arg for KiUserExceptionDispatcher */
REGn_sig
(
1
,
sigcontext
)
=
(
ULONG_PTR
)
&
stack
->
context
;
/* second arg for KiUserExceptionDispatcher */
REGn_sig
(
2
,
sigcontext
)
=
(
ULONG_PTR
)
pKiUserExceptionDispatcher
;
/* dispatcher arg for raise_func_trampoline */
PC_sig
(
sigcontext
)
=
(
ULONG_PTR
)
pKiUserExceptionDispatcher
;
REGn_sig
(
18
,
sigcontext
)
=
(
ULONG_PTR
)
NtCurrentTeb
();
}
...
...
@@ -1086,19 +1022,16 @@ void call_raise_user_exception_dispatcher(void)
NTSTATUS
call_user_exception_dispatcher
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
context
)
{
struct
syscall_frame
*
frame
=
arm64_thread_data
()
->
syscall_frame
;
ULONG64
fp
=
frame
->
fp
;
ULONG64
lr
=
frame
->
lr
;
ULONG64
sp
=
frame
->
sp
;
struct
exc_stack_layout
*
stack
;
NTSTATUS
status
=
NtSetContextThread
(
GetCurrentThread
(),
context
);
if
(
status
)
return
status
;
frame
->
x
[
0
]
=
(
ULONG64
)
rec
;
frame
->
x
[
1
]
=
(
ULONG64
)
context
;
frame
->
pc
=
(
ULONG64
)
pKiUserExceptionDispatcher
;
frame
->
fp
=
fp
;
frame
->
lr
=
lr
;
frame
->
sp
=
sp
;
frame
->
restore_flags
|=
CONTEXT_INTEGER
|
CONTEXT_CONTROL
;
stack
=
(
struct
exc_stack_layout
*
)(
context
->
Sp
&
~
15
)
-
1
;
memmove
(
&
stack
->
context
,
context
,
sizeof
(
*
context
)
);
memmove
(
&
stack
->
rec
,
rec
,
sizeof
(
*
rec
)
);
frame
->
pc
=
(
ULONG64
)
pKiUserExceptionDispatcher
;
frame
->
sp
=
(
ULONG64
)
stack
;
frame
->
restore_flags
|=
CONTEXT_CONTROL
;
syscall_frame_fixup_for_fastpath
(
frame
);
return
status
;
}
...
...
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