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
e6ce5d5d
Commit
e6ce5d5d
authored
Mar 06, 2024
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Implement exception dispatching on ARM64EC.
parent
daea0b9b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
219 additions
and
1 deletion
+219
-1
signal_arm64ec.c
dlls/ntdll/signal_arm64ec.c
+186
-0
exception.c
dlls/ntdll/tests/exception.c
+33
-1
No files found.
dlls/ntdll/signal_arm64ec.c
View file @
e6ce5d5d
...
...
@@ -37,6 +37,20 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
seh
);
WINE_DECLARE_DEBUG_CHANNEL
(
relay
);
static
inline
CHPE_V2_CPU_AREA_INFO
*
get_arm64ec_cpu_area
(
void
)
{
return
NtCurrentTeb
()
->
ChpeV2CpuAreaInfo
;
}
static
inline
BOOL
is_valid_arm64ec_frame
(
ULONG_PTR
frame
)
{
if
(
frame
&
(
sizeof
(
void
*
)
-
1
))
return
FALSE
;
if
(
is_valid_frame
(
frame
))
return
TRUE
;
return
(
frame
>=
get_arm64ec_cpu_area
()
->
EmulatorStackLimit
&&
frame
<=
get_arm64ec_cpu_area
()
->
EmulatorStackBase
);
}
/*******************************************************************
* syscalls
*/
...
...
@@ -1485,6 +1499,178 @@ static NTSTATUS WINAPI LdrpSetX64Information( ULONG type, ULONG_PTR input, void
}
/**********************************************************************
* virtual_unwind
*/
static
NTSTATUS
virtual_unwind
(
ULONG
type
,
DISPATCHER_CONTEXT_ARM64EC
*
dispatch
,
ARM64EC_NT_CONTEXT
*
context
)
{
DISPATCHER_CONTEXT_NONVOLREG_ARM64
*
nonvol_regs
;
DWORD64
pc
=
context
->
Pc
;
int
i
;
dispatch
->
ScopeIndex
=
0
;
dispatch
->
ControlPc
=
pc
;
dispatch
->
ControlPcIsUnwound
=
(
context
->
ContextFlags
&
CONTEXT_UNWOUND_TO_CALL
)
!=
0
;
if
(
dispatch
->
ControlPcIsUnwound
&&
RtlIsEcCode
(
pc
))
pc
-=
4
;
nonvol_regs
=
(
DISPATCHER_CONTEXT_NONVOLREG_ARM64
*
)
dispatch
->
NonVolatileRegisters
;
nonvol_regs
->
GpNvRegs
[
0
]
=
context
->
X19
;
nonvol_regs
->
GpNvRegs
[
1
]
=
context
->
X20
;
nonvol_regs
->
GpNvRegs
[
2
]
=
context
->
X21
;
nonvol_regs
->
GpNvRegs
[
3
]
=
context
->
X22
;
nonvol_regs
->
GpNvRegs
[
4
]
=
0
;
nonvol_regs
->
GpNvRegs
[
5
]
=
0
;
nonvol_regs
->
GpNvRegs
[
6
]
=
context
->
X25
;
nonvol_regs
->
GpNvRegs
[
7
]
=
context
->
X26
;
nonvol_regs
->
GpNvRegs
[
8
]
=
context
->
X27
;
nonvol_regs
->
GpNvRegs
[
9
]
=
0
;
nonvol_regs
->
GpNvRegs
[
10
]
=
context
->
Fp
;
for
(
i
=
0
;
i
<
8
;
i
++
)
nonvol_regs
->
FpNvRegs
[
i
]
=
context
->
V
[
i
+
8
].
D
[
0
];
dispatch
->
FunctionEntry
=
RtlLookupFunctionEntry
(
pc
,
&
dispatch
->
ImageBase
,
dispatch
->
HistoryTable
);
if
(
RtlVirtualUnwind2
(
type
,
dispatch
->
ImageBase
,
pc
,
dispatch
->
FunctionEntry
,
&
context
->
AMD64_Context
,
NULL
,
&
dispatch
->
HandlerData
,
&
dispatch
->
EstablisherFrame
,
NULL
,
NULL
,
NULL
,
&
dispatch
->
LanguageHandler
,
0
))
{
WARN
(
"exception data not found for pc %p
\n
"
,
(
void
*
)
pc
);
return
STATUS_INVALID_DISPOSITION
;
}
return
STATUS_SUCCESS
;
}
/***********************************************************************
* call_seh_handler
*/
static
DWORD
__attribute__
((
naked
))
call_seh_handler
(
EXCEPTION_RECORD
*
rec
,
ULONG_PTR
frame
,
CONTEXT
*
context
,
void
*
dispatch
,
PEXCEPTION_ROUTINE
handler
)
{
asm
(
".seh_proc call_seh_handler
\n\t
"
"stp x29, x30, [sp, #-16]!
\n\t
"
".seh_save_fplr_x 16
\n\t
"
".seh_endprologue
\n\t
"
".seh_handler nested_exception_handler, @except
\n\t
"
"mov x11, x4
\n\t
"
/* handler */
"adr x10, $iexit_thunk$cdecl$i8$i8i8i8i8
\n\t
"
"adrp x16, __os_arm64x_dispatch_icall
\n\t
"
"ldr x16, [x16, #:lo12:__os_arm64x_dispatch_icall]
\n\t
"
"blr x16
\n\t
"
"blr x11
\n\t
"
"ldp x29, x30, [sp], #16
\n\t
"
"ret
\n\t
"
".seh_endproc"
);
}
/**********************************************************************
* call_seh_handlers
*
* Call the SEH handlers.
*/
NTSTATUS
call_seh_handlers
(
EXCEPTION_RECORD
*
rec
,
CONTEXT
*
orig_context
)
{
EXCEPTION_REGISTRATION_RECORD
*
teb_frame
=
NtCurrentTeb
()
->
Tib
.
ExceptionList
;
DISPATCHER_CONTEXT_NONVOLREG_ARM64
nonvol_regs
;
UNWIND_HISTORY_TABLE
table
;
DISPATCHER_CONTEXT_ARM64EC
dispatch
;
ARM64EC_NT_CONTEXT
context
;
NTSTATUS
status
;
ULONG_PTR
frame
;
DWORD
res
;
context
.
AMD64_Context
=
*
orig_context
;
context
.
ContextFlags
&=
~
0x40
;
/* Clear xstate flag. */
dispatch
.
TargetPc
=
0
;
dispatch
.
ContextRecord
=
&
context
.
AMD64_Context
;
dispatch
.
HistoryTable
=
&
table
;
dispatch
.
NonVolatileRegisters
=
nonvol_regs
.
Buffer
;
for
(;;)
{
status
=
virtual_unwind
(
UNW_FLAG_EHANDLER
,
&
dispatch
,
&
context
);
if
(
status
!=
STATUS_SUCCESS
)
return
status
;
unwind_done:
if
(
!
dispatch
.
EstablisherFrame
)
break
;
if
(
!
is_valid_arm64ec_frame
(
dispatch
.
EstablisherFrame
))
{
ERR
(
"invalid frame %I64x (%p-%p)
\n
"
,
dispatch
.
EstablisherFrame
,
NtCurrentTeb
()
->
Tib
.
StackLimit
,
NtCurrentTeb
()
->
Tib
.
StackBase
);
rec
->
ExceptionFlags
|=
EXCEPTION_STACK_INVALID
;
break
;
}
if
(
dispatch
.
LanguageHandler
)
{
TRACE
(
"calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)
\n
"
,
dispatch
.
LanguageHandler
,
rec
,
dispatch
.
EstablisherFrame
,
orig_context
,
&
dispatch
);
res
=
call_seh_handler
(
rec
,
dispatch
.
EstablisherFrame
,
orig_context
,
&
dispatch
,
dispatch
.
LanguageHandler
);
rec
->
ExceptionFlags
&=
EXCEPTION_NONCONTINUABLE
;
TRACE
(
"handler at %p returned %lu
\n
"
,
dispatch
.
LanguageHandler
,
res
);
switch
(
res
)
{
case
ExceptionContinueExecution
:
if
(
rec
->
ExceptionFlags
&
EXCEPTION_NONCONTINUABLE
)
return
STATUS_NONCONTINUABLE_EXCEPTION
;
return
STATUS_SUCCESS
;
case
ExceptionContinueSearch
:
break
;
case
ExceptionNestedException
:
rec
->
ExceptionFlags
|=
EXCEPTION_NESTED_CALL
;
TRACE
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
context
.
AMD64_Context
,
&
dispatch
.
HandlerData
,
&
frame
,
NULL
);
goto
unwind_done
;
default:
return
STATUS_INVALID_DISPOSITION
;
}
}
/* hack: call wine handlers registered in the tib list */
else
while
(
is_valid_frame
(
(
ULONG_PTR
)
teb_frame
)
&&
(
ULONG64
)
teb_frame
<
context
.
Sp
)
{
TRACE
(
"calling TEB handler %p (rec=%p frame=%p context=%p dispatch=%p) sp=%I64x
\n
"
,
teb_frame
->
Handler
,
rec
,
teb_frame
,
orig_context
,
&
dispatch
,
context
.
Sp
);
res
=
call_seh_handler
(
rec
,
(
ULONG_PTR
)
teb_frame
,
orig_context
,
&
dispatch
,
(
PEXCEPTION_ROUTINE
)
teb_frame
->
Handler
);
TRACE
(
"TEB handler at %p returned %lu
\n
"
,
teb_frame
->
Handler
,
res
);
switch
(
res
)
{
case
ExceptionContinueExecution
:
if
(
rec
->
ExceptionFlags
&
EXCEPTION_NONCONTINUABLE
)
return
STATUS_NONCONTINUABLE_EXCEPTION
;
return
STATUS_SUCCESS
;
case
ExceptionContinueSearch
:
break
;
case
ExceptionNestedException
:
rec
->
ExceptionFlags
|=
EXCEPTION_NESTED_CALL
;
TRACE
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
RtlVirtualUnwind
(
UNW_FLAG_NHANDLER
,
dispatch
.
ImageBase
,
dispatch
.
ControlPc
,
dispatch
.
FunctionEntry
,
&
context
.
AMD64_Context
,
&
dispatch
.
HandlerData
,
&
frame
,
NULL
);
teb_frame
=
teb_frame
->
Prev
;
goto
unwind_done
;
default:
return
STATUS_INVALID_DISPOSITION
;
}
teb_frame
=
teb_frame
->
Prev
;
}
if
(
context
.
Sp
==
(
ULONG64
)
NtCurrentTeb
()
->
Tib
.
StackBase
)
break
;
}
return
STATUS_UNHANDLED_EXCEPTION
;
}
/*******************************************************************
* KiUserExceptionDispatcher (NTDLL.@)
*/
...
...
dlls/ntdll/tests/exception.c
View file @
e6ce5d5d
...
...
@@ -3275,8 +3275,40 @@ static DWORD WINAPI rtlraiseexception_teb_handler( EXCEPTION_RECORD *rec,
}
static
DWORD
WINAPI
rtlraiseexception_handler
(
EXCEPTION_RECORD
*
rec
,
void
*
frame
,
CONTEXT
*
context
,
void
*
dispatcher
)
CONTEXT
*
context
,
DISPATCHER_CONTEXT
*
dispatcher
)
{
if
(
is_arm64ec
)
{
ARM64EC_NT_CONTEXT
*
ec_ctx
=
(
ARM64EC_NT_CONTEXT
*
)
context
;
DISPATCHER_CONTEXT_NONVOLREG_ARM64
*
nonvol_regs
;
int
i
;
nonvol_regs
=
(
void
*
)((
DISPATCHER_CONTEXT_ARM64
*
)
dispatcher
)
->
NonVolatileRegisters
;
ok
(
nonvol_regs
->
GpNvRegs
[
0
]
==
ec_ctx
->
X19
,
"wrong non volatile reg x19 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
0
],
ec_ctx
->
X19
);
ok
(
nonvol_regs
->
GpNvRegs
[
1
]
==
ec_ctx
->
X20
,
"wrong non volatile reg x20 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
1
],
ec_ctx
->
X20
);
ok
(
nonvol_regs
->
GpNvRegs
[
2
]
==
ec_ctx
->
X21
,
"wrong non volatile reg x21 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
2
],
ec_ctx
->
X21
);
ok
(
nonvol_regs
->
GpNvRegs
[
3
]
==
ec_ctx
->
X22
,
"wrong non volatile reg x22 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
3
],
ec_ctx
->
X22
);
ok
(
nonvol_regs
->
GpNvRegs
[
4
]
==
0
,
"wrong non volatile reg x23 %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
4
]
);
ok
(
nonvol_regs
->
GpNvRegs
[
5
]
==
0
,
"wrong non volatile reg x24 %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
5
]
);
ok
(
nonvol_regs
->
GpNvRegs
[
6
]
==
ec_ctx
->
X25
,
"wrong non volatile reg x25 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
6
],
ec_ctx
->
X25
);
ok
(
nonvol_regs
->
GpNvRegs
[
7
]
==
ec_ctx
->
X26
,
"wrong non volatile reg x26 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
7
],
ec_ctx
->
X26
);
ok
(
nonvol_regs
->
GpNvRegs
[
8
]
==
ec_ctx
->
X27
,
"wrong non volatile reg x27 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
8
],
ec_ctx
->
X27
);
ok
(
nonvol_regs
->
GpNvRegs
[
9
]
==
0
,
"wrong non volatile reg x28 %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
9
]
);
ok
(
nonvol_regs
->
GpNvRegs
[
10
]
>
ec_ctx
->
Fp
,
/* previous frame */
"wrong non volatile reg x29 %I64x / %I64x
\n
"
,
nonvol_regs
->
GpNvRegs
[
10
],
ec_ctx
->
Fp
);
for
(
i
=
0
;
i
<
NONVOL_FP_NUMREG_ARM64
;
i
++
)
ok
(
nonvol_regs
->
FpNvRegs
[
i
]
==
ec_ctx
->
V
[
i
+
8
].
D
[
0
],
"wrong non volatile reg d%u %g / %g
\n
"
,
i
+
8
,
nonvol_regs
->
FpNvRegs
[
i
]
,
ec_ctx
->
V
[
i
+
8
].
D
[
0
]
);
}
rtlraiseexception_handler_called
=
1
;
rtlraiseexception_handler_
(
rec
,
frame
,
context
,
dispatcher
,
FALSE
);
return
ExceptionContinueSearch
;
...
...
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