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
0dd37b02
Commit
0dd37b02
authored
Nov 02, 2021
by
Paul Gofman
Committed by
Alexandre Julliard
Nov 03, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Store module dependencies in DDAG structure.
Signed-off-by:
Paul Gofman
<
pgofman@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
06f925c5
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
152 additions
and
65 deletions
+152
-65
module.c
dlls/kernel32/tests/module.c
+6
-6
loader.c
dlls/ntdll/loader.c
+144
-57
winternl.h
include/winternl.h
+2
-2
No files found.
dlls/kernel32/tests/module.c
View file @
0dd37b02
...
...
@@ -1376,14 +1376,14 @@ static void test_ddag_node(void)
ok
(
!
node
->
IncomingDependencies
.
Tail
,
"Expected empty incoming dependencies list.
\n
"
);
/* node->Dependencies.Tail is NULL on Windows 10 1507-1607 32 bit test, maybe due to broken structure layout. */
todo_wine
ok
(
!!
node
->
Dependencies
.
Tail
||
broken
(
sizeof
(
void
*
)
==
4
&&
!
node
->
Dependencies
.
Tail
),
ok
(
!!
node
->
Dependencies
.
Tail
||
broken
(
sizeof
(
void
*
)
==
4
&&
!
node
->
Dependencies
.
Tail
),
"Expected nonempty dependencies list.
\n
"
);
if
(
!
node
->
Dependencies
.
Tail
)
{
skip
(
"Empty dependencies list.
\n
"
);
win_
skip
(
"Empty dependencies list.
\n
"
);
return
;
}
ok
(
node
->
LoadCount
==
-
1
,
"Got unexpected LoadCount %d.
\n
"
,
node
->
LoadCount
);
todo_wine
ok
(
node
->
LoadCount
==
-
1
,
"Got unexpected LoadCount %d.
\n
"
,
node
->
LoadCount
);
prev_node
=
NULL
;
se
=
node
->
Dependencies
.
Tail
;
...
...
@@ -1409,7 +1409,7 @@ static void test_ddag_node(void)
}
mod2
=
CONTAINING_RECORD
(
dep_node
->
Modules
.
Flink
,
LDR_DATA_TABLE_ENTRY
,
NodeModuleLink
);
ok
(
!
lstrcmpW
(
mod2
->
BaseDllName
.
Buffer
,
expected_exe_dependencies
[
i
].
dllname
),
todo_wine
ok
(
!
lstrcmpW
(
mod2
->
BaseDllName
.
Buffer
,
expected_exe_dependencies
[
i
].
dllname
),
"Got unexpected module %s.
\n
"
,
debugstr_w
(
mod2
->
BaseDllName
.
Buffer
));
se2
=
dep_node
->
IncomingDependencies
.
Tail
;
...
...
@@ -1422,13 +1422,13 @@ static void test_ddag_node(void)
while
(
dep2
!=
dep
&&
se2
!=
dep_node
->
IncomingDependencies
.
Tail
);
ok
(
dep2
==
dep
,
"Dependency not found in incoming deps list.
\n
"
);
ok
(
dep_node
->
LoadCount
>
0
||
broken
(
!
dep_node
->
LoadCount
)
/* Win8 */
,
todo_wine
ok
(
dep_node
->
LoadCount
>
0
||
broken
(
!
dep_node
->
LoadCount
)
/* Win8 */
,
"Got unexpected LoadCount %d.
\n
"
,
dep_node
->
LoadCount
);
winetest_pop_context
();
prev_node
=
dep_node
;
}
ok
(
se
==
node
->
Dependencies
.
Tail
,
"Expected end of the list.
\n
"
);
todo_wine
ok
(
se
==
node
->
Dependencies
.
Tail
,
"Expected end of the list.
\n
"
);
}
START_TEST
(
module
)
...
...
dlls/ntdll/loader.c
View file @
0dd37b02
...
...
@@ -133,9 +133,6 @@ typedef struct _wine_modref
{
LDR_DATA_TABLE_ENTRY
ldr
;
struct
file_id
id
;
int
alloc_deps
;
int
nDeps
;
struct
_wine_modref
**
deps
;
ULONG
CheckSum
;
}
WINE_MODREF
;
...
...
@@ -588,26 +585,112 @@ static WINE_MODREF *find_fileid_module( const struct file_id *id )
return
NULL
;
}
/**********************************************************************
* insert_single_list_tail
*/
static
void
insert_single_list_after
(
LDRP_CSLIST
*
list
,
SINGLE_LIST_ENTRY
*
prev
,
SINGLE_LIST_ENTRY
*
entry
)
{
if
(
!
list
->
Tail
)
{
assert
(
!
prev
);
entry
->
Next
=
entry
;
list
->
Tail
=
entry
;
return
;
}
if
(
!
prev
)
{
/* Insert at head. */
entry
->
Next
=
list
->
Tail
->
Next
;
list
->
Tail
->
Next
=
entry
;
return
;
}
entry
->
Next
=
prev
->
Next
;
prev
->
Next
=
entry
;
if
(
prev
==
list
->
Tail
)
list
->
Tail
=
entry
;
}
/**********************************************************************
***
*
grow_module_deps
/**********************************************************************
*
remove_single_list_entry
*/
static
WINE_MODREF
**
grow_module_deps
(
WINE_MODREF
*
wm
,
int
count
)
static
void
remove_single_list_entry
(
LDRP_CSLIST
*
list
,
SINGLE_LIST_ENTRY
*
entry
)
{
WINE_MODREF
**
deps
;
SINGLE_LIST_ENTRY
*
prev
;
if
(
wm
->
alloc_deps
)
deps
=
RtlReAllocateHeap
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
wm
->
deps
,
(
wm
->
alloc_deps
+
count
)
*
sizeof
(
*
deps
)
);
else
deps
=
RtlAllocateHeap
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
count
*
sizeof
(
*
deps
)
);
assert
(
list
->
Tail
);
if
(
deps
)
if
(
entry
->
Next
==
entry
)
{
wm
->
deps
=
deps
;
wm
->
alloc_deps
+=
count
;
assert
(
list
->
Tail
==
entry
);
list
->
Tail
=
NULL
;
return
;
}
return
deps
;
prev
=
list
->
Tail
->
Next
;
while
(
prev
->
Next
!=
entry
&&
prev
!=
list
->
Tail
)
prev
=
prev
->
Next
;
assert
(
prev
->
Next
==
entry
);
prev
->
Next
=
entry
->
Next
;
if
(
list
->
Tail
==
entry
)
list
->
Tail
=
prev
;
entry
->
Next
=
NULL
;
}
/**********************************************************************
* add_module_dependency_after
*/
static
BOOL
add_module_dependency_after
(
LDR_DDAG_NODE
*
from
,
LDR_DDAG_NODE
*
to
,
SINGLE_LIST_ENTRY
*
dep_after
)
{
LDR_DEPENDENCY
*
dep
;
if
(
!
(
dep
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
sizeof
(
*
dep
)
)))
return
FALSE
;
dep
->
dependency_from
=
from
;
insert_single_list_after
(
&
from
->
Dependencies
,
dep_after
,
&
dep
->
dependency_to_entry
);
dep
->
dependency_to
=
to
;
insert_single_list_after
(
&
to
->
IncomingDependencies
,
NULL
,
&
dep
->
dependency_from_entry
);
return
TRUE
;
}
/**********************************************************************
* add_module_dependency
*/
static
BOOL
add_module_dependency
(
LDR_DDAG_NODE
*
from
,
LDR_DDAG_NODE
*
to
)
{
return
add_module_dependency_after
(
from
,
to
,
from
->
Dependencies
.
Tail
);
}
/**********************************************************************
* remove_module_dependency
*/
static
void
remove_module_dependency
(
LDR_DEPENDENCY
*
dep
)
{
remove_single_list_entry
(
&
dep
->
dependency_to
->
IncomingDependencies
,
&
dep
->
dependency_from_entry
);
remove_single_list_entry
(
&
dep
->
dependency_from
->
Dependencies
,
&
dep
->
dependency_to_entry
);
RtlFreeHeap
(
GetProcessHeap
(),
0
,
dep
);
}
/**********************************************************************
* walk_node_dependencies
*/
static
NTSTATUS
walk_node_dependencies
(
LDR_DDAG_NODE
*
node
,
void
*
context
,
NTSTATUS
(
*
callback
)(
LDR_DDAG_NODE
*
,
void
*
))
{
SINGLE_LIST_ENTRY
*
entry
;
LDR_DEPENDENCY
*
dep
;
NTSTATUS
status
;
if
(
!
(
entry
=
node
->
Dependencies
.
Tail
))
return
STATUS_SUCCESS
;
do
{
entry
=
entry
->
Next
;
dep
=
CONTAINING_RECORD
(
entry
,
LDR_DEPENDENCY
,
dependency_to_entry
);
assert
(
dep
->
dependency_from
==
node
);
if
((
status
=
callback
(
dep
->
dependency_to
,
context
)))
break
;
}
while
(
entry
!=
node
->
Dependencies
.
Tail
);
return
status
;
}
/*************************************************************************
...
...
@@ -645,8 +728,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
{
if
(
!
imports_fixup_done
&&
current_modref
)
{
WINE_MODREF
**
deps
=
grow_module_deps
(
current_modref
,
1
);
if
(
deps
)
deps
[
current_modref
->
nDeps
++
]
=
wm
;
add_module_dependency
(
current_modref
->
ldr
.
DdagNode
,
wm
->
ldr
.
DdagNode
);
}
else
if
(
process_attach
(
wm
->
ldr
.
DdagNode
,
NULL
)
!=
STATUS_SUCCESS
)
{
...
...
@@ -1125,12 +1207,12 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
if
(
!
(
wm
->
ldr
.
Flags
&
LDR_DONT_RESOLVE_REFS
))
return
STATUS_SUCCESS
;
/* already done */
wm
->
ldr
.
Flags
&=
~
LDR_DONT_RESOLVE_REFS
;
if
(
!
grow_module_deps
(
wm
,
1
))
return
STATUS_NO_MEMORY
;
wm
->
nDeps
=
1
;
prev
=
current_modref
;
current_modref
=
wm
;
if
(
!
(
status
=
load_dll
(
load_path
,
L"mscoree.dll"
,
NULL
,
0
,
&
imp
)))
wm
->
deps
[
0
]
=
imp
;
assert
(
!
wm
->
ldr
.
DdagNode
->
Dependencies
.
Tail
);
if
(
!
(
status
=
load_dll
(
load_path
,
L"mscoree.dll"
,
NULL
,
0
,
&
imp
))
&&
!
add_module_dependency_after
(
wm
->
ldr
.
DdagNode
,
imp
->
ldr
.
DdagNode
,
NULL
))
status
=
STATUS_NO_MEMORY
;
current_modref
=
prev
;
if
(
status
)
{
...
...
@@ -1156,9 +1238,10 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
*/
static
NTSTATUS
fixup_imports
(
WINE_MODREF
*
wm
,
LPCWSTR
load_path
)
{
int
i
,
dep
,
nb_imports
;
const
IMAGE_IMPORT_DESCRIPTOR
*
imports
;
SINGLE_LIST_ENTRY
*
dep_after
;
WINE_MODREF
*
prev
,
*
imp
;
int
i
,
nb_imports
;
DWORD
size
;
NTSTATUS
status
;
ULONG_PTR
cookie
;
...
...
@@ -1176,7 +1259,6 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
while
(
imports
[
nb_imports
].
Name
&&
imports
[
nb_imports
].
FirstThunk
)
nb_imports
++
;
if
(
!
nb_imports
)
return
STATUS_SUCCESS
;
/* no imports */
if
(
!
grow_module_deps
(
wm
,
nb_imports
))
return
STATUS_NO_MEMORY
;
if
(
!
create_module_activation_context
(
&
wm
->
ldr
))
RtlActivateActivationContext
(
0
,
wm
->
ldr
.
ActivationContext
,
&
cookie
);
...
...
@@ -1189,14 +1271,13 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
status
=
STATUS_SUCCESS
;
for
(
i
=
0
;
i
<
nb_imports
;
i
++
)
{
dep
=
wm
->
nDeps
++
;
dep_after
=
wm
->
ldr
.
DdagNode
->
Dependencies
.
Tail
;
if
(
!
import_dll
(
wm
->
ldr
.
DllBase
,
&
imports
[
i
],
load_path
,
&
imp
))
{
imp
=
NULL
;
status
=
STATUS_DLL_NOT_FOUND
;
}
wm
->
deps
[
dep
]
=
imp
;
else
add_module_dependency_after
(
wm
->
ldr
.
DdagNode
,
imp
->
ldr
.
DdagNode
,
dep_after
)
;
}
current_modref
=
prev
;
if
(
wm
->
ldr
.
ActivationContext
)
RtlDeactivateActivationContext
(
0
,
cookie
);
...
...
@@ -1444,7 +1525,6 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
LDR_DATA_TABLE_ENTRY
*
mod
;
ULONG_PTR
cookie
;
WINE_MODREF
*
wm
;
int
i
;
if
(
process_detaching
)
return
status
;
...
...
@@ -1464,11 +1544,7 @@ static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
if
(
wm
->
ldr
.
ActivationContext
)
RtlActivateActivationContext
(
0
,
wm
->
ldr
.
ActivationContext
,
&
cookie
);
/* Recursively attach all DLLs this one depends on */
for
(
i
=
0
;
i
<
wm
->
nDeps
;
i
++
)
{
if
(
!
wm
->
deps
[
i
])
continue
;
if
((
status
=
process_attach
(
wm
->
deps
[
i
]
->
ldr
.
DdagNode
,
lpReserved
))
!=
STATUS_SUCCESS
)
break
;
}
walk_node_dependencies
(
node
,
lpReserved
,
process_attach
);
if
(
!
wm
->
ldr
.
InInitializationOrderLinks
.
Flink
)
InsertTailList
(
&
NtCurrentTeb
()
->
Peb
->
LdrData
->
InInitializationOrderModuleList
,
...
...
@@ -3528,11 +3604,28 @@ void WINAPI LdrShutdownThread(void)
*/
static
void
free_modref
(
WINE_MODREF
*
wm
)
{
SINGLE_LIST_ENTRY
*
entry
;
LDR_DEPENDENCY
*
dep
;
RemoveEntryList
(
&
wm
->
ldr
.
InLoadOrderLinks
);
RemoveEntryList
(
&
wm
->
ldr
.
InMemoryOrderLinks
);
if
(
wm
->
ldr
.
InInitializationOrderLinks
.
Flink
)
RemoveEntryList
(
&
wm
->
ldr
.
InInitializationOrderLinks
);
while
((
entry
=
wm
->
ldr
.
DdagNode
->
Dependencies
.
Tail
))
{
dep
=
CONTAINING_RECORD
(
entry
,
LDR_DEPENDENCY
,
dependency_to_entry
);
assert
(
dep
->
dependency_from
==
wm
->
ldr
.
DdagNode
);
remove_module_dependency
(
dep
);
}
while
((
entry
=
wm
->
ldr
.
DdagNode
->
IncomingDependencies
.
Tail
))
{
dep
=
CONTAINING_RECORD
(
entry
,
LDR_DEPENDENCY
,
dependency_from_entry
);
assert
(
dep
->
dependency_to
==
wm
->
ldr
.
DdagNode
);
remove_module_dependency
(
dep
);
}
RemoveEntryList
(
&
wm
->
ldr
.
NodeModuleLink
);
if
(
IsListEmpty
(
&
wm
->
ldr
.
DdagNode
->
Modules
))
RtlFreeHeap
(
GetProcessHeap
(),
0
,
wm
->
ldr
.
DdagNode
);
...
...
@@ -3548,7 +3641,6 @@ static void free_modref( WINE_MODREF *wm )
NtUnmapViewOfSection
(
NtCurrentProcess
(),
wm
->
ldr
.
DllBase
);
if
(
cached_modref
==
wm
)
cached_modref
=
NULL
;
RtlFreeUnicodeString
(
&
wm
->
ldr
.
FullDllName
);
RtlFreeHeap
(
GetProcessHeap
(),
0
,
wm
->
deps
);
RtlFreeHeap
(
GetProcessHeap
(),
0
,
wm
);
}
...
...
@@ -3591,15 +3683,19 @@ static void MODULE_FlushModrefs(void)
*
* The loader_section must be locked while calling this function.
*/
static
void
MODULE_DecRefCount
(
WINE_MODREF
*
wm
)
static
NTSTATUS
MODULE_DecRefCount
(
LDR_DDAG_NODE
*
node
,
void
*
context
)
{
int
i
;
LDR_DATA_TABLE_ENTRY
*
mod
;
WINE_MODREF
*
wm
;
mod
=
CONTAINING_RECORD
(
node
->
Modules
.
Flink
,
LDR_DATA_TABLE_ENTRY
,
NodeModuleLink
);
wm
=
CONTAINING_RECORD
(
mod
,
WINE_MODREF
,
ldr
);
if
(
wm
->
ldr
.
Flags
&
LDR_UNLOAD_IN_PROGRESS
)
return
;
return
STATUS_SUCCESS
;
if
(
wm
->
ldr
.
LoadCount
<=
0
)
return
;
return
STATUS_SUCCESS
;
--
wm
->
ldr
.
LoadCount
;
TRACE
(
"(%s) ldr.LoadCount: %d
\n
"
,
debugstr_w
(
wm
->
ldr
.
BaseDllName
.
Buffer
),
wm
->
ldr
.
LoadCount
);
...
...
@@ -3607,15 +3703,11 @@ static void MODULE_DecRefCount( WINE_MODREF *wm )
if
(
wm
->
ldr
.
LoadCount
==
0
)
{
wm
->
ldr
.
Flags
|=
LDR_UNLOAD_IN_PROGRESS
;
for
(
i
=
0
;
i
<
wm
->
nDeps
;
i
++
)
if
(
wm
->
deps
[
i
]
)
MODULE_DecRefCount
(
wm
->
deps
[
i
]
);
walk_node_dependencies
(
node
,
context
,
MODULE_DecRefCount
);
wm
->
ldr
.
Flags
&=
~
LDR_UNLOAD_IN_PROGRESS
;
module_push_unload_trace
(
wm
);
}
return
STATUS_SUCCESS
;
}
/******************************************************************
...
...
@@ -3640,7 +3732,7 @@ NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
TRACE
(
"(%s) - START
\n
"
,
debugstr_w
(
wm
->
ldr
.
BaseDllName
.
Buffer
));
/* Recursively decrement reference counts */
MODULE_DecRefCount
(
wm
);
MODULE_DecRefCount
(
wm
->
ldr
.
DdagNode
,
NULL
);
/* Call process detach notifications */
if
(
free_lib_count
<=
1
)
...
...
@@ -3855,7 +3947,6 @@ static void release_address_space(void)
void
WINAPI
LdrInitializeThunk
(
CONTEXT
*
context
,
ULONG_PTR
unknown2
,
ULONG_PTR
unknown3
,
ULONG_PTR
unknown4
)
{
static
int
attach_done
;
int
i
;
NTSTATUS
status
;
ULONG_PTR
cookie
;
WINE_MODREF
*
wm
;
...
...
@@ -3959,18 +4050,14 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
if
(
wm
->
ldr
.
ActivationContext
)
RtlActivateActivationContext
(
0
,
wm
->
ldr
.
ActivationContext
,
&
cookie
);
for
(
i
=
0
;
i
<
wm
->
nDeps
;
i
++
)
if
((
status
=
walk_node_dependencies
(
wm
->
ldr
.
DdagNode
,
context
,
process_attach
))
)
{
if
(
!
wm
->
deps
[
i
])
continue
;
if
((
status
=
process_attach
(
wm
->
deps
[
i
]
->
ldr
.
DdagNode
,
context
))
!=
STATUS_SUCCESS
)
{
if
(
last_failed_modref
)
ERR
(
"%s failed to initialize, aborting
\n
"
,
debugstr_w
(
last_failed_modref
->
ldr
.
BaseDllName
.
Buffer
)
+
1
);
ERR
(
"Initializing dlls for %s failed, status %x
\n
"
,
debugstr_w
(
NtCurrentTeb
()
->
Peb
->
ProcessParameters
->
ImagePathName
.
Buffer
),
status
);
NtTerminateProcess
(
GetCurrentProcess
(),
status
);
}
if
(
last_failed_modref
)
ERR
(
"%s failed to initialize, aborting
\n
"
,
debugstr_w
(
last_failed_modref
->
ldr
.
BaseDllName
.
Buffer
)
+
1
);
ERR
(
"Initializing dlls for %s failed, status %x
\n
"
,
debugstr_w
(
NtCurrentTeb
()
->
Peb
->
ProcessParameters
->
ImagePathName
.
Buffer
),
status
);
NtTerminateProcess
(
GetCurrentProcess
(),
status
);
}
release_address_space
();
if
(
wm
->
ldr
.
TlsIndex
!=
-
1
)
call_tls_callbacks
(
wm
->
ldr
.
DllBase
,
DLL_PROCESS_ATTACH
);
...
...
include/winternl.h
View file @
0dd37b02
...
...
@@ -3274,9 +3274,9 @@ typedef struct _LDRP_CSLIST
typedef
struct
_LDR_DEPENDENCY
{
LDRP_CSLIST
dependency_to_entry
;
SINGLE_LIST_ENTRY
dependency_to_entry
;
struct
_LDR_DDAG_NODE
*
dependency_to
;
LDRP_CSLIST
dependency_from_entry
;
SINGLE_LIST_ENTRY
dependency_from_entry
;
struct
_LDR_DDAG_NODE
*
dependency_from
;
}
LDR_DEPENDENCY
,
*
PLDR_DEPENDENCY
;
...
...
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