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
9f555cde
Commit
9f555cde
authored
Feb 22, 2024
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Handle leaf functions in RtlVirtualUnwind on ARM64.
parent
852e2ffc
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
109 additions
and
78 deletions
+109
-78
signal_arm64.c
dlls/ntdll/signal_arm64.c
+14
-24
unwind.c
dlls/ntdll/tests/unwind.c
+85
-52
unwind.c
dlls/ntdll/unwind.c
+10
-2
No files found.
dlls/ntdll/signal_arm64.c
View file @
9f555cde
...
...
@@ -147,33 +147,23 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext,
*/
static
NTSTATUS
virtual_unwind
(
ULONG
type
,
DISPATCHER_CONTEXT
*
dispatch
,
CONTEXT
*
context
)
{
NTSTATUS
status
;
DWORD64
pc
;
DWORD64
pc
=
context
->
Pc
;
dispatch
->
ImageBase
=
0
;
dispatch
->
ScopeIndex
=
0
;
dispatch
->
EstablisherFrame
=
0
;
dispatch
->
ControlPc
=
context
->
Pc
;
dispatch
->
ScopeIndex
=
0
;
dispatch
->
ControlPc
=
pc
;
dispatch
->
ControlPcIsUnwound
=
(
context
->
ContextFlags
&
CONTEXT_UNWOUND_TO_CALL
)
!=
0
;
pc
=
context
->
Pc
-
(
dispatch
->
ControlPcIsUnwound
?
4
:
0
)
;
if
(
dispatch
->
ControlPcIsUnwound
)
pc
-=
4
;
if
((
dispatch
->
FunctionEntry
=
RtlLookupFunctionEntry
(
pc
,
&
dispatch
->
ImageBase
,
dispatch
->
HistoryTable
)))
dispatch
->
FunctionEntry
=
RtlLookupFunctionEntry
(
pc
,
&
dispatch
->
ImageBase
,
dispatch
->
HistoryTable
);
dispatch
->
LanguageHandler
=
RtlVirtualUnwind
(
type
,
dispatch
->
ImageBase
,
pc
,
dispatch
->
FunctionEntry
,
context
,
&
dispatch
->
HandlerData
,
&
dispatch
->
EstablisherFrame
,
NULL
);
if
(
!
context
->
Pc
)
{
dispatch
->
LanguageHandler
=
RtlVirtualUnwind
(
type
,
dispatch
->
ImageBase
,
pc
,
dispatch
->
FunctionEntry
,
context
,
&
dispatch
->
HandlerData
,
&
dispatch
->
EstablisherFrame
,
NULL
);
return
STATUS_SUCCESS
;
WARN
(
"exception data not found for pc %p, lr %p
\n
"
,
(
void
*
)
pc
,
(
void
*
)
context
->
Lr
);
return
STATUS_INVALID_DISPOSITION
;
}
WARN
(
"exception data not found for pc %p, lr %p
\n
"
,
(
void
*
)
context
->
Pc
,
(
void
*
)
context
->
Lr
);
status
=
context
->
Pc
!=
context
->
Lr
?
STATUS_SUCCESS
:
STATUS_INVALID_DISPOSITION
;
dispatch
->
EstablisherFrame
=
context
->
Sp
;
dispatch
->
LanguageHandler
=
NULL
;
context
->
Pc
=
context
->
Lr
;
context
->
ContextFlags
|=
CONTEXT_UNWOUND_TO_CALL
;
return
status
;
return
STATUS_SUCCESS
;
}
...
...
@@ -383,7 +373,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
break
;
case
ExceptionNestedException
:
rec
->
ExceptionFlags
|=
EH_NESTED_CALL
;
TRACE
_
(
seh
)
(
"nested exception
\n
"
);
TRACE
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
{
ULONG64
frame
;
...
...
@@ -414,7 +404,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
break
;
case
ExceptionNestedException
:
rec
->
ExceptionFlags
|=
EH_NESTED_CALL
;
TRACE
_
(
seh
)
(
"nested exception
\n
"
);
TRACE
(
"nested exception
\n
"
);
break
;
case
ExceptionCollidedUnwind
:
{
ULONG64
frame
;
...
...
dlls/ntdll/tests/unwind.c
View file @
9f555cde
...
...
@@ -1494,7 +1494,7 @@ struct results_arm64
int
fp_offset
;
/* fp offset from stack pointer */
int
handler
;
/* expect handler to be set? */
ULONG_PTR
pc
;
/* expected final pc value */
int
frame
;
/* expected frame return value */
ULONG_PTR
frame
;
/* expected frame return value */
int
frame_offset
;
/* whether the frame return value is an offset or an absolute value */
ULONG_PTR
regs
[
48
][
2
];
/* expected values for registers */
};
...
...
@@ -1551,13 +1551,15 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
static
const
UINT
nb_regs
=
ARRAY_SIZE
(
test
->
results
[
i
].
regs
);
memcpy
(
(
char
*
)
code_mem
+
code_offset
,
test
->
function
,
test
->
function_size
);
memcpy
(
(
char
*
)
code_mem
+
unwind_offset
,
test
->
unwind_info
,
test
->
unwind_size
);
runtime_func
.
BeginAddress
=
code_offset
;
if
(
test
->
unwind_size
)
runtime_func
.
UnwindData
=
unwind_offset
;
else
memcpy
(
&
runtime_func
.
UnwindData
,
test
->
unwind_info
,
4
);
if
(
test
->
unwind_info
)
{
memcpy
(
(
char
*
)
code_mem
+
unwind_offset
,
test
->
unwind_info
,
test
->
unwind_size
);
runtime_func
.
BeginAddress
=
code_offset
;
if
(
test
->
unwind_size
)
runtime_func
.
UnwindData
=
unwind_offset
;
else
memcpy
(
&
runtime_func
.
UnwindData
,
test
->
unwind_info
,
4
);
}
for
(
i
=
0
;
i
<
test
->
nb_results
;
i
++
)
{
...
...
@@ -1579,8 +1581,14 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
trace
(
"pc=%p (%02x) fp=%p sp=%p
\n
"
,
(
void
*
)
orig_pc
,
*
(
UINT
*
)
orig_pc
,
(
void
*
)
orig_fp
,
(
void
*
)
context
.
Sp
);
data
=
(
void
*
)
0xdeadbeef
;
frame
=
0xdeadbeef
;
#ifdef __x86_64__
if
(
test
->
results
[
i
].
handler
==
-
2
)
continue
;
/* skip invalid leaf function test */
#else
if
(
test
->
results
[
i
].
handler
==
-
2
)
orig_pc
=
context
.
Lr
;
#endif
handler
=
RtlVirtualUnwind
(
UNW_FLAG_EHANDLER
,
(
ULONG64
)
code_mem
,
orig_pc
,
(
RUNTIME_FUNCTION
*
)
&
runtime_func
,
test
->
unwind_info
?
(
RUNTIME_FUNCTION
*
)
&
runtime_func
:
NULL
,
(
CONTEXT
*
)
&
context
,
&
data
,
&
frame
,
&
ctx_ptr
);
if
(
test
->
results
[
i
].
handler
>
0
)
{
...
...
@@ -1592,7 +1600,7 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
else
{
ok
(
handler
==
NULL
,
"handler %p instead of NULL
\n
"
,
handler
);
ok
(
data
==
(
test
->
results
[
i
].
handler
<
0
?
(
void
*
)
0xdeadbeef
:
NULL
),
ok
(
data
==
(
test
->
results
[
i
].
handler
<
-
1
?
(
void
*
)
0xdeadbeef
:
NULL
),
"handler data set to %p/%p
\n
"
,
data
,
(
test
->
results
[
i
].
handler
<
0
?
(
void
*
)
0xdeadbeef
:
NULL
)
);
}
...
...
@@ -1601,27 +1609,35 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
(
void
*
)
context
.
Pc
,
(
void
*
)
test
->
results
[
i
].
pc
);
ok
(
frame
==
(
test
->
results
[
i
].
frame_offset
?
(
ULONG64
)
fake_stack
:
0
)
+
test
->
results
[
i
].
frame
,
"wrong frame %p/%p
\n
"
,
(
void
*
)
frame
,
(
char
*
)(
test
->
results
[
i
].
frame_offset
?
fake_stack
:
NULL
)
+
test
->
results
[
i
].
frame
);
if
(
!
test
->
unwound_clear
||
i
<
test
->
unwound_clear
)
ok
(
context
.
ContextFlags
==
(
0xcccc
|
CONTEXT_ARM64_UNWOUND_TO_CALL
),
"wrong flags %lx
\n
"
,
context
.
ContextFlags
);
if
(
test
->
results
[
i
].
handler
==
-
2
)
/* invalid leaf function */
{
ok
(
context
.
ContextFlags
==
0xcccc
,
"wrong flags %lx
\n
"
,
context
.
ContextFlags
);
ok
(
context
.
Sp
==
(
ULONG_PTR
)
fake_stack
,
"wrong sp %p/%p
\n
"
,
(
void
*
)
context
.
Sp
,
fake_stack
);
}
else
ok
(
context
.
ContextFlags
==
0xcccc
,
"wrong flags %lx
\n
"
,
context
.
ContextFlags
);
sp_offset
=
0
;
for
(
k
=
0
;
k
<
nb_regs
;
k
++
)
{
if
(
test
->
results
[
i
].
regs
[
k
][
0
]
==
-
1
)
break
;
if
(
test
->
results
[
i
].
regs
[
k
][
0
]
==
sp
)
{
/* If sp is part of the registers list, treat it as an offset
* between the returned frame pointer and the sp register. */
sp_offset
=
test
->
results
[
i
].
regs
[
k
][
1
];
break
;
if
(
!
test
->
unwound_clear
||
i
<
test
->
unwound_clear
)
ok
(
context
.
ContextFlags
==
(
0xcccc
|
CONTEXT_ARM64_UNWOUND_TO_CALL
),
"wrong flags %lx
\n
"
,
context
.
ContextFlags
);
else
ok
(
context
.
ContextFlags
==
0xcccc
,
"wrong flags %lx
\n
"
,
context
.
ContextFlags
);
sp_offset
=
0
;
for
(
k
=
0
;
k
<
nb_regs
;
k
++
)
{
if
(
test
->
results
[
i
].
regs
[
k
][
0
]
==
-
1
)
break
;
if
(
test
->
results
[
i
].
regs
[
k
][
0
]
==
sp
)
{
/* If sp is part of the registers list, treat it as an offset
* between the returned frame pointer and the sp register. */
sp_offset
=
test
->
results
[
i
].
regs
[
k
][
1
];
break
;
}
}
ok
(
frame
-
sp_offset
==
context
.
Sp
,
"wrong sp %p/%p
\n
"
,
(
void
*
)(
frame
-
sp_offset
),
(
void
*
)
context
.
Sp
);
}
ok
(
frame
-
sp_offset
==
context
.
Sp
,
"wrong sp %p/%p
\n
"
,
(
void
*
)(
frame
-
sp_offset
),
(
void
*
)
context
.
Sp
);
#ifdef __x86_64__
for
(
j
=
0
;
j
<
sizeof
(
ctx_ptr
)
/
sizeof
(
void
*
);
j
++
)
...
...
@@ -1671,7 +1687,7 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
if
(
k
<
nb_regs
)
{
ok
(
regval
==
test
->
results
[
i
].
regs
[
k
][
1
],
"register %s wrong %
llx/%ll
x
\n
"
,
reg_names_arm64
[
j
],
regval
,
test
->
results
[
i
].
regs
[
k
][
1
]
);
"register %s wrong %
I64x/%I64
x
\n
"
,
reg_names_arm64
[
j
],
regval
,
test
->
results
[
i
].
regs
[
k
][
1
]
);
if
(
regptr
)
{
if
(
test
->
last_set_reg_ptr
&&
j
>
test
->
last_set_reg_ptr
&&
j
<=
30
)
...
...
@@ -1680,7 +1696,7 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
{
ok
(
regptr
!=
(
void
*
)
unset_reg
,
"register %s should have pointer set
\n
"
,
reg_names_arm64
[
j
]
);
if
(
regptr
!=
(
void
*
)
unset_reg
)
ok
(
*
regptr
==
regval
,
"register %s should have reg pointer to %
llx / %ll
x
\n
"
,
ok
(
*
regptr
==
regval
,
"register %s should have reg pointer to %
I64x / %I64
x
\n
"
,
reg_names_arm64
[
j
],
*
regptr
,
regval
);
}
}
...
...
@@ -1690,11 +1706,11 @@ static void call_virtual_unwind_arm64( void *code_mem, int testnum, const struct
ok
(
k
==
nb_regs
,
"register %s should be set
\n
"
,
reg_names_arm64
[
j
]
);
ok
(
!
regptr
||
regptr
==
(
void
*
)
unset_reg
,
"register %s should not have pointer set
\n
"
,
reg_names_arm64
[
j
]
);
if
(
j
==
lr
)
ok
(
context
.
Lr
==
ORIG_LR
,
"register lr wrong %
ll
x/unset
\n
"
,
context
.
Lr
);
ok
(
context
.
Lr
==
ORIG_LR
,
"register lr wrong %
I64
x/unset
\n
"
,
context
.
Lr
);
else
if
(
j
==
x29
)
ok
(
context
.
Fp
==
orig_fp
,
"register fp wrong %
ll
x/unset
\n
"
,
context
.
Fp
);
ok
(
context
.
Fp
==
orig_fp
,
"register fp wrong %
I64
x/unset
\n
"
,
context
.
Fp
);
else
ok
(
regval
==
unset_reg
,
"register %s wrong %
ll
x/unset
\n
"
,
reg_names_arm64
[
j
],
regval
);
ok
(
regval
==
unset_reg
,
"register %s wrong %
I64
x/unset
\n
"
,
reg_names_arm64
[
j
],
regval
);
}
}
winetest_pop_context
();
...
...
@@ -2473,28 +2489,45 @@ static void test_virtual_unwind_arm64(void)
{
0x0c
,
0x00
,
0
,
ORIG_LR
,
0x020
,
TRUE
,
{
{
-
1
,
-
1
}
}},
};
static
const
BYTE
function_18
[]
=
{
0x1f
,
0x20
,
0x03
,
0xd5
,
/* 00: nop */
0x1f
,
0x20
,
0x03
,
0xd5
,
/* 04: nop */
0xc0
,
0x03
,
0x5f
,
0xd6
,
/* 08: ret */
};
static
const
struct
results_arm64
results_18
[]
=
{
/* offset fp handler pc frame offset registers */
{
0x00
,
0x00
,
-
1
,
ORIG_LR
,
0x000
,
TRUE
,
{
{
-
1
,
-
1
}
}},
{
0x04
,
0x00
,
-
1
,
ORIG_LR
,
0x000
,
TRUE
,
{
{
-
1
,
-
1
}
}},
{
0x08
,
0x00
,
-
1
,
ORIG_LR
,
0x000
,
TRUE
,
{
{
-
1
,
-
1
}
}},
{
0x0c
,
0x00
,
-
2
,
0
,
0xdeadbeef
,
FALSE
,
{
{
-
1
,
-
1
}
}},
};
static
const
struct
unwind_test_arm64
tests
[]
=
{
#define TEST(func, unwind, unwind_packed, results, unwound_clear, last_ptr) \
{ func, sizeof(func), unwind, unwind_packed ? 0 : sizeof(unwind), results, ARRAY_SIZE(results), unwound_clear, last_ptr }
TEST
(
function_0
,
unwind_info_0
,
0
,
results_0
,
0
,
0
),
TEST
(
function_1
,
unwind_info_1
,
1
,
results_1
,
0
,
0
),
TEST
(
function_2
,
unwind_info_2
,
0
,
results_2
,
1
,
0
),
TEST
(
function_3
,
unwind_info_3
,
0
,
results_3
,
1
,
x28
),
TEST
(
function_4
,
unwind_info_4
,
0
,
results_4
,
0
,
0
),
TEST
(
function_5
,
unwind_info_5
,
0
,
results_5
,
0
,
0
),
TEST
(
function_6
,
unwind_info_6
,
1
,
results_6
,
0
,
0
),
TEST
(
function_7
,
unwind_info_7
,
1
,
results_7
,
0
,
0
),
TEST
(
function_8
,
unwind_info_8
,
1
,
results_8
,
0
,
0
),
TEST
(
function_9
,
unwind_info_9
,
1
,
results_9
,
0
,
0
),
TEST
(
function_10
,
unwind_info_10
,
1
,
results_10
,
0
,
0
),
TEST
(
function_11
,
unwind_info_11
,
1
,
results_11
,
0
,
0
),
TEST
(
function_12
,
unwind_info_12
,
1
,
results_12
,
0
,
0
),
TEST
(
function_13
,
unwind_info_13
,
1
,
results_13
,
0
,
0
),
TEST
(
function_14
,
unwind_info_14
,
0
,
results_14
,
0
,
0
),
TEST
(
function_15
,
unwind_info_15
,
0
,
results_15
,
0
,
0
),
TEST
(
function_16
,
unwind_info_16
,
0
,
results_16
,
1
,
x18
),
TEST
(
function_17
,
unwind_info_17
,
0
,
results_17
,
2
,
0
),
#define TEST(func, unwind, size, results, unwound_clear, last_ptr) \
{ func, sizeof(func), unwind, size, results, ARRAY_SIZE(results), unwound_clear, last_ptr }
TEST
(
function_0
,
unwind_info_0
,
sizeof
(
unwind_info_0
),
results_0
,
0
,
0
),
TEST
(
function_1
,
unwind_info_1
,
0
,
results_1
,
0
,
0
),
TEST
(
function_2
,
unwind_info_2
,
sizeof
(
unwind_info_2
),
results_2
,
1
,
0
),
TEST
(
function_3
,
unwind_info_3
,
sizeof
(
unwind_info_3
),
results_3
,
1
,
x28
),
TEST
(
function_4
,
unwind_info_4
,
sizeof
(
unwind_info_4
),
results_4
,
0
,
0
),
TEST
(
function_5
,
unwind_info_5
,
sizeof
(
unwind_info_5
),
results_5
,
0
,
0
),
TEST
(
function_6
,
unwind_info_6
,
0
,
results_6
,
0
,
0
),
TEST
(
function_7
,
unwind_info_7
,
0
,
results_7
,
0
,
0
),
TEST
(
function_8
,
unwind_info_8
,
0
,
results_8
,
0
,
0
),
TEST
(
function_9
,
unwind_info_9
,
0
,
results_9
,
0
,
0
),
TEST
(
function_10
,
unwind_info_10
,
0
,
results_10
,
0
,
0
),
TEST
(
function_11
,
unwind_info_11
,
0
,
results_11
,
0
,
0
),
TEST
(
function_12
,
unwind_info_12
,
0
,
results_12
,
0
,
0
),
TEST
(
function_13
,
unwind_info_13
,
0
,
results_13
,
0
,
0
),
TEST
(
function_14
,
unwind_info_14
,
sizeof
(
unwind_info_14
),
results_14
,
0
,
0
),
TEST
(
function_15
,
unwind_info_15
,
sizeof
(
unwind_info_15
),
results_15
,
0
,
0
),
TEST
(
function_16
,
unwind_info_16
,
sizeof
(
unwind_info_16
),
results_16
,
1
,
x18
),
TEST
(
function_17
,
unwind_info_17
,
sizeof
(
unwind_info_17
),
results_17
,
2
,
0
),
TEST
(
function_18
,
NULL
,
0
,
results_18
,
0
,
0
),
#undef TEST
};
unsigned
int
i
;
...
...
dlls/ntdll/unwind.c
View file @
9f555cde
...
...
@@ -779,12 +779,20 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc,
{
void
*
handler
;
TRACE
(
"type %lx pc %I64x sp %I64x func %I64x
\n
"
,
type
,
pc
,
context
->
Sp
,
base
+
func
->
BeginAddress
);
TRACE
(
"type %lx pc %I64x sp %I64x
\n
"
,
type
,
pc
,
context
->
Sp
);
if
(
!
func
&&
pc
==
context
->
Lr
)
/* invalid leaf function */
{
context
->
Pc
=
0
;
return
NULL
;
}
*
handler_data
=
NULL
;
context
->
ContextFlags
|=
CONTEXT_UNWOUND_TO_CALL
;
if
(
func
->
Flag
)
if
(
!
func
)
/* leaf function */
handler
=
NULL
;
else
if
(
func
->
Flag
)
handler
=
unwind_packed_data
(
base
,
pc
,
func
,
context
,
ctx_ptr
);
else
handler
=
unwind_full_data
(
base
,
pc
,
func
,
context
,
handler_data
,
ctx_ptr
);
...
...
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