Commit 32872b1a authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- implementation of LdrLoadDll out of loader/module.c

- in impacted functions, ensure that we only use ntdll functions - for internal loading, start using NTDLL style for error reporting - making use of new LdrLoadDll
parent 4550b8b7
......@@ -44,6 +44,48 @@ static WINE_EXCEPTION_FILTER(page_fault)
}
/*************************************************************************
* MODULE_AllocModRef
*
* Allocate a WINE_MODREF structure and add it to the process list
* NOTE: Assumes that the process critical section is held!
*/
WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
{
WINE_MODREF *wm;
DWORD long_len = strlen( filename );
DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
sizeof(*wm) + long_len + short_len + 1 )))
{
wm->module = hModule;
wm->tlsindex = -1;
wm->filename = wm->data;
memcpy( wm->filename, filename, long_len + 1 );
if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
else wm->modname = wm->filename;
wm->short_filename = wm->filename + long_len + 1;
GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
else wm->short_modname = wm->short_filename;
wm->next = MODULE_modref_list;
if (wm->next) wm->next->prev = wm;
MODULE_modref_list = wm;
if (!(RtlImageNtHeader(hModule)->FileHeader.Characteristics & IMAGE_FILE_DLL))
{
if (!exe_modref) exe_modref = wm;
else FIXME( "Trying to load second .EXE file: %s\n", filename );
}
}
return wm;
}
/******************************************************************
* LdrDisableThreadCalloutsForDll (NTDLL.@)
*
......@@ -182,6 +224,245 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG or
}
/***********************************************************************
* allocate_lib_dir
*
* helper for MODULE_LoadLibraryExA. Allocate space to hold the directory
* portion of the provided name and put the name in it.
*
*/
static LPCSTR allocate_lib_dir(LPCSTR libname)
{
LPCSTR p, pmax;
LPSTR result;
int length;
pmax = libname;
if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty. MSDN says don't */
if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
length = pmax - libname;
result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
if (result)
{
strncpy (result, libname, length);
result [length] = '\0';
}
return result;
}
/***********************************************************************
* MODULE_LoadLibraryExA (internal)
*
* Load a PE style module according to the load order.
*
* libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
* on this function. When first called from LoadLibraryExA it will be
* NULL but thereafter it may point to a buffer containing the path
* portion of the library name. Note that the recursion all occurs
* within a Critical section (see LoadLibraryExA) so the use of a
* static is acceptable.
* (We have to use a static variable at some point anyway, to pass the
* information from BUILTIN32_dlopen through dlopen and the builtin's
* init function into load_library).
* allocated_libdir is TRUE in the stack frame that allocated libdir
*/
NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** pwm)
{
int i;
enum loadorder_type loadorder[LOADORDER_NTYPES];
LPSTR filename;
const char *filetype = "";
DWORD found;
BOOL allocated_libdir = FALSE;
static LPCSTR libdir = NULL; /* See above */
NTSTATUS nts = STATUS_SUCCESS;
*pwm = NULL;
if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
if ( !filename ) return STATUS_NO_MEMORY;
*filename = 0; /* Just in case we don't set it before goto error */
RtlEnterCriticalSection( &loader_section );
if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
{
if (!(libdir = allocate_lib_dir(libname)))
{
nts = STATUS_NO_MEMORY;
goto error;
}
allocated_libdir = TRUE;
}
if (!libdir || allocated_libdir)
found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
else
found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
/* build the modules filename */
if (!found)
{
if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
{
nts = STATUS_INTERNAL_ERROR;
goto error;
}
}
/* Check for already loaded module */
if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
{
LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
if (fn)
{
/* since the default loading mechanism uses a more detailed algorithm
* than SearchPath (like using PATH, which can even be modified between
* two attempts of loading the same DLL), the look-up above (with
* SearchPath) can have put the file in system directory, whereas it
* has already been loaded but with a different path. So do a specific
* look-up with filename (without any path)
*/
strcpy ( fn, libname );
/* if the filename doesn't have an extension append .DLL */
if (!strrchr( fn, '.')) strcat( fn, ".dll" );
if ((*pwm = MODULE_FindModule( fn )) != NULL)
strcpy( filename, fn );
RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
}
}
if (*pwm)
{
(*pwm)->refCount++;
if (((*pwm)->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
!(flags & DONT_RESOLVE_DLL_REFERENCES))
{
(*pwm)->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS;
PE_fixup_imports( *pwm );
}
TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->module, (*pwm)->refCount);
if (allocated_libdir)
{
RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
libdir = NULL;
}
RtlLeaveCriticalSection( &loader_section );
RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
return STATUS_SUCCESS;
}
MODULE_GetLoadOrder( loadorder, filename, TRUE);
for (i = 0; i < LOADORDER_NTYPES; i++)
{
if (loadorder[i] == LOADORDER_INVALID) break;
switch (loadorder[i])
{
case LOADORDER_DLL:
TRACE("Trying native dll '%s'\n", filename);
nts = PE_LoadLibraryExA(filename, flags, pwm);
filetype = "native";
break;
case LOADORDER_BI:
TRACE("Trying built-in '%s'\n", filename);
nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
filetype = "builtin";
break;
default:
nts = STATUS_INTERNAL_ERROR;
break;
}
if (nts == STATUS_SUCCESS)
{
/* Initialize DLL just loaded */
TRACE("Loaded module '%s' at %p\n", filename, (*pwm)->module);
if (!TRACE_ON(module))
TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
/* Set the refCount here so that an attach failure will */
/* decrement the dependencies through the MODULE_FreeLibrary call. */
(*pwm)->refCount = 1;
if (allocated_libdir)
{
RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
libdir = NULL;
}
RtlLeaveCriticalSection( &loader_section );
RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
return nts;
}
if (nts != STATUS_NO_SUCH_FILE)
{
WARN("Loading of %s DLL %s failed (status %ld).\n",
filetype, filename, nts);
break;
}
}
error:
if (allocated_libdir)
{
RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
libdir = NULL;
}
RtlLeaveCriticalSection( &loader_section );
WARN("Failed to load module '%s'; status=%ld\n", filename, nts);
RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
return nts;
}
/******************************************************************
* LdrLoadDll (NTDLL.@)
*/
NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
{
WINE_MODREF *wm;
NTSTATUS nts = STATUS_SUCCESS;
STRING str;
RtlUnicodeStringToAnsiString(&str, libname, TRUE);
RtlEnterCriticalSection( &loader_section );
switch (nts = MODULE_LoadLibraryExA( str.Buffer, flags, &wm ))
{
case STATUS_SUCCESS:
if ( !MODULE_DllProcessAttach( wm, NULL ) )
{
WARN_(module)("Attach failed for module '%s'.\n", str.Buffer);
LdrUnloadDll(wm->module);
nts = STATUS_DLL_INIT_FAILED;
wm = NULL;
}
break;
case STATUS_NO_SUCH_FILE:
nts = STATUS_DLL_NOT_FOUND;
break;
default: /* keep error code as it is (memory...) */
break;
}
*hModule = (wm) ? wm->module : NULL;
RtlLeaveCriticalSection( &loader_section );
RtlFreeAnsiString(&str);
return nts;
}
/******************************************************************
* LdrShutdownProcess (NTDLL.@)
*
......
......@@ -42,7 +42,7 @@
@ stdcall LdrGetDllHandle(long long ptr ptr) LdrGetDllHandle
@ stdcall LdrGetProcedureAddress(ptr ptr long ptr) LdrGetProcedureAddress
@ stub LdrInitializeThunk
@ stub LdrLoadDll
@ stdcall LdrLoadDll(wstr long ptr ptr) LdrLoadDll
@ stub LdrProcessRelocationBlock
@ stub LdrQueryImageFileExecutionOptions
@ stub LdrQueryProcessModuleInformation
......
......@@ -21,6 +21,7 @@
#include "winnt.h"
#include "winternl.h"
#include "module.h"
#include "thread.h"
/* debug helper */
......@@ -29,11 +30,12 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
/* module handling */
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
extern NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** );
static inline HANDLE ntdll_get_process_heap(void)
{
HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */
}
#endif
......@@ -25,6 +25,7 @@
#include "winbase.h"
#include "wine/windef16.h"
#include "wine/winbase16.h"
#include "winternl.h"
/* In-memory module structure. See 'Windows Internals' p. 219 */
typedef struct _NE_MODULE
......@@ -193,11 +194,9 @@ enum binary_type
};
/* module.c */
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved );
extern void MODULE_DllThreadAttach( LPVOID lpReserved );
extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags );
extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 );
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
......@@ -254,7 +253,7 @@ extern DWORD PE_SizeofResource(HRSRC);
extern HGLOBAL PE_LoadResource(HMODULE,HRSRC);
/* loader/pe_image.c */
extern WINE_MODREF *PE_LoadLibraryExA(LPCSTR, DWORD);
extern NTSTATUS PE_LoadLibraryExA(LPCSTR, DWORD, WINE_MODREF**);
extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags );
extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename,
DWORD flags, HANDLE hFile, BOOL builtin );
......@@ -268,7 +267,7 @@ extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BO
extern void MODULE_AddLoadOrderOption( const char *option );
/* relay32/builtin.c */
extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags);
extern NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, WINE_MODREF**);
extern HMODULE BUILTIN32_LoadExeModule( HMODULE main );
extern void *BUILTIN32_dlopen( const char *name );
extern int BUILTIN32_dlclose( void *handle );
......
......@@ -1141,7 +1141,7 @@ typedef struct _LDR_MODULE
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
void* BaseAddress;
ULONG EntryPoint;
void* EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
......@@ -1187,7 +1187,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE);
NTSTATUS WINAPI LdrFindEntryForAddress(void*, PLDR_MODULE*);
NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, PUNICODE_STRING, HMODULE*);
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, PANSI_STRING, ULONG, void**);
NTSTATUS WINAPI LdrLoadDll(LPCSTR, DWORD, PUNICODE_STRING, HMODULE*);
NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, PUNICODE_STRING, HMODULE*);
NTSTATUS WINAPI LdrShutdownThread(void);
NTSTATUS WINAPI LdrShutdownProcess(void);
NTSTATUS WINAPI LdrUnloadDll(HMODULE);
......
......@@ -257,7 +257,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
/* Allocate module dependency list */
wm->nDeps = i;
wm->deps = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) );
wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, i*sizeof(WINE_MODREF *) );
/* load the imported modules. They are automatically
* added to the modref list of the process.
......@@ -268,19 +268,24 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
IMAGE_IMPORT_BY_NAME *pe_name;
PIMAGE_THUNK_DATA import_list,thunk_list;
char *name = get_rva(wm->module, pe_imp->Name);
NTSTATUS nts;
if (characteristics_detection && !pe_imp->u.Characteristics)
break;
wmImp = MODULE_LoadLibraryExA( name, 0, 0 );
if (!wmImp) {
if(GetLastError() == ERROR_FILE_NOT_FOUND)
ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename);
else
ERR_(module)("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
name, wm->filename, GetLastError());
nts = MODULE_LoadLibraryExA( name, 0, &wmImp );
switch (nts)
{
case STATUS_SUCCESS:
break;
case STATUS_NO_SUCH_FILE:
ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename);
return 1;
default:
ERR_(module)("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
name, wm->filename, GetLastError());
return 1;
}
}
wm->deps[i++] = wmImp;
/* FIXME: forwarder entries ... */
......@@ -575,35 +580,38 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags,
* The PE Library Loader frontend.
* FIXME: handle the flags.
*/
WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags)
NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm)
{
HMODULE hModule32;
WINE_MODREF *wm;
HANDLE hFile;
hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0 );
if ( hFile == INVALID_HANDLE_VALUE ) return NULL;
if ( hFile == INVALID_HANDLE_VALUE )
{
/* keep it that way until we transform CreateFile into NtCreateFile */
return (GetLastError() == ERROR_FILE_NOT_FOUND) ?
STATUS_NO_SUCH_FILE : STATUS_INTERNAL_ERROR;
}
/* Load PE module */
hModule32 = PE_LoadImage( hFile, name, flags );
if (!hModule32)
{
CloseHandle( hFile );
return NULL;
return STATUS_INTERNAL_ERROR;
}
/* Create 32-bit MODREF */
if ( !(wm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
if ( !(*pwm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
{
ERR( "can't load %s\n", name );
CloseHandle( hFile );
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
return STATUS_NO_MEMORY; /* FIXME */
}
CloseHandle( hFile );
return wm;
return STATUS_SUCCESS;
}
......
......@@ -147,9 +147,8 @@ static void load_library( void *base, const char *filename )
* Partly copied from the original PE_ version.
*
*/
WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, WINE_MODREF** pwm)
{
WINE_MODREF *wm;
char dllname[20], *p;
LPCSTR name;
void *handle;
......@@ -159,29 +158,24 @@ WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags)
if ((p = strrchr( name, '\\' ))) name = p + 1;
if ((p = strrchr( name, '/' ))) name = p + 1;
if (strlen(name) >= sizeof(dllname)-4) goto error;
if (strlen(name) >= sizeof(dllname)-4) return STATUS_NO_SUCH_FILE;
strcpy( dllname, name );
p = strrchr( dllname, '.' );
if (!p) strcat( dllname, ".dll" );
for (p = dllname; *p; p++) *p = FILE_tolower(*p);
if (!(handle = BUILTIN32_dlopen( dllname ))) goto error;
if (!(handle = BUILTIN32_dlopen( dllname ))) return STATUS_NO_SUCH_FILE;
if (!(wm = MODULE_FindModule( path ))) wm = MODULE_FindModule( dllname );
if (!wm)
if (!((*pwm) = MODULE_FindModule( path ))) *pwm = MODULE_FindModule( dllname );
if (!*pwm)
{
ERR( "loaded .so but dll %s still not found - 16-bit dll or version conflict.\n", dllname );
/* wine_dll_unload( handle );*/
SetLastError( ERROR_BAD_EXE_FORMAT );
return NULL;
return STATUS_INVALID_IMAGE_FORMAT;
}
wm->dlhandle = handle;
return wm;
error:
SetLastError( ERROR_FILE_NOT_FOUND );
return NULL;
(*pwm)->dlhandle = handle;
return STATUS_SUCCESS;
}
/***********************************************************************
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment