Moved the 32-bit builtin loader and the remaining bits of the PE
loader into dlls/ntdll/loader.c.
This commit is contained in:
parent
ce85a90538
commit
97ad311e71
|
@ -124,6 +124,8 @@ int main_create_flags = 0;
|
|||
extern BOOL init_user_process_pmts( size_t, char*, size_t );
|
||||
extern BOOL build_command_line( char **argv );
|
||||
|
||||
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); /* FIXME */
|
||||
|
||||
extern void RELAY_InitDebugLists(void);
|
||||
extern void SHELL_LoadRegistry(void);
|
||||
extern void VERSION_Init( const char *appname );
|
||||
|
@ -276,6 +278,51 @@ static BOOL find_exe_file( const char *name, char *buffer, int buflen, HANDLE *h
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* load_pe_exe
|
||||
*
|
||||
* Load a PE format EXE file.
|
||||
*/
|
||||
static HMODULE load_pe_exe( HANDLE file )
|
||||
{
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
HANDLE mapping;
|
||||
void *module;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER size;
|
||||
DWORD len = 0;
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
attr.ObjectName = NULL;
|
||||
attr.Attributes = 0;
|
||||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
size.QuadPart = 0;
|
||||
|
||||
if (NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
|
||||
&attr, &size, 0, SEC_IMAGE, file ) != STATUS_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
module = NULL;
|
||||
if (NtMapViewOfSection( mapping, GetCurrentProcess(), &module, 0, 0, &size, &len,
|
||||
ViewShare, 0, PAGE_READONLY ) != STATUS_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
NtClose( mapping );
|
||||
|
||||
/* virus check */
|
||||
nt = RtlImageNtHeader( module );
|
||||
if (nt->OptionalHeader.AddressOfEntryPoint)
|
||||
{
|
||||
if (!RtlImageRvaToSection( nt, module, nt->OptionalHeader.AddressOfEntryPoint ))
|
||||
MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
|
||||
"outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
|
||||
nt->OptionalHeader.AddressOfEntryPoint );
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* process_init
|
||||
*
|
||||
|
@ -411,6 +458,7 @@ static void start_process( void *arg )
|
|||
LPTHREAD_START_ROUTINE entry;
|
||||
HANDLE main_file = main_exe_file;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
WINE_MODREF *wm;
|
||||
PEB *peb = NtCurrentTeb()->Peb;
|
||||
|
||||
if (main_file)
|
||||
|
@ -450,11 +498,13 @@ static void start_process( void *arg )
|
|||
SERVER_END_REQ;
|
||||
|
||||
/* create the main modref and load dependencies */
|
||||
if (!PE_CreateModule( peb->ImageBaseAddress, main_exe_name, 0, 0, FALSE )) goto error;
|
||||
|
||||
if (!(wm = MODULE_AllocModRef( peb->ImageBaseAddress, main_exe_name ))) goto error;
|
||||
if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */
|
||||
|
||||
MODULE_DllProcessAttach( NULL, (LPVOID)1 );
|
||||
if (MODULE_DllProcessAttach( NULL, (LPVOID)1 ) != STATUS_SUCCESS)
|
||||
{
|
||||
ERR( "Main exe initialization failed\n" );
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
DPRINTF( "%04lx:Starting process %s (entryproc=%p)\n",
|
||||
|
@ -523,7 +573,7 @@ void __wine_process_init( int argc, char *argv[] )
|
|||
{
|
||||
case BINARY_PE_EXE:
|
||||
TRACE( "starting Win32 binary %s\n", debugstr_a(main_exe_name) );
|
||||
if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 ))) goto found;
|
||||
if ((current_process.module = load_pe_exe( main_exe_file ))) goto found;
|
||||
MESSAGE( "%s: could not load '%s' as Win32 binary\n", argv0, main_exe_name );
|
||||
ExitProcess(1);
|
||||
case BINARY_PE_DLL:
|
||||
|
|
|
@ -14,7 +14,6 @@ C_SRCS = \
|
|||
$(TOPOBJDIR)/files/smb.c \
|
||||
$(TOPOBJDIR)/loader/loadorder.c \
|
||||
$(TOPOBJDIR)/loader/module.c \
|
||||
$(TOPOBJDIR)/loader/pe_image.c \
|
||||
$(TOPOBJDIR)/loader/task.c \
|
||||
$(TOPOBJDIR)/loader/ne/module.c \
|
||||
$(TOPOBJDIR)/memory/codepage.c \
|
||||
|
@ -28,7 +27,6 @@ C_SRCS = \
|
|||
$(TOPOBJDIR)/misc/registry.c \
|
||||
$(TOPOBJDIR)/misc/version.c \
|
||||
$(TOPOBJDIR)/msdos/dpmi.c \
|
||||
$(TOPOBJDIR)/relay32/builtin32.c \
|
||||
$(TOPOBJDIR)/relay32/relay386.c \
|
||||
$(TOPOBJDIR)/relay32/snoop.c \
|
||||
$(TOPOBJDIR)/scheduler/handle.c \
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "file.h"
|
||||
#include "wine/exception.h"
|
||||
#include "excpt.h"
|
||||
#include "snoop.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/server.h"
|
||||
#include "ntdll_misc.h"
|
||||
|
@ -78,6 +77,7 @@ static CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|||
|
||||
static WINE_MODREF *cached_modref;
|
||||
static WINE_MODREF *current_modref;
|
||||
static NTSTATUS last_builtin_status; /* use to gather all errors in callback */
|
||||
|
||||
static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
|
||||
static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
|
||||
|
@ -114,6 +114,55 @@ static WINE_MODREF *get_modref( HMODULE hmod )
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* find_module
|
||||
*
|
||||
* Find a (loaded) win32 module depending on path
|
||||
* LPCSTR path: [in] pathname of module/library to be found
|
||||
*
|
||||
* The loader_section must be locked while calling this function
|
||||
* RETURNS
|
||||
* the module handle if found
|
||||
* 0 if not
|
||||
*/
|
||||
static WINE_MODREF *find_module( LPCSTR path )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
PLIST_ENTRY mark, entry;
|
||||
PLDR_MODULE mod;
|
||||
char dllname[260], *p;
|
||||
|
||||
/* Append .DLL to name if no extension present */
|
||||
strcpy( dllname, path );
|
||||
if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
|
||||
strcat( dllname, ".DLL" );
|
||||
|
||||
if ((wm = cached_modref) != NULL)
|
||||
{
|
||||
if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
|
||||
}
|
||||
|
||||
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
|
||||
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
|
||||
{
|
||||
mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
|
||||
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
|
||||
|
||||
if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
|
||||
}
|
||||
if (entry == mark) wm = NULL;
|
||||
|
||||
cached_modref = wm;
|
||||
return wm;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* find_forwarded_export
|
||||
*
|
||||
|
@ -134,7 +183,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward )
|
|||
memcpy( mod_name, forward, end - forward );
|
||||
mod_name[end-forward] = 0;
|
||||
|
||||
if (!(wm = MODULE_FindModule( mod_name )))
|
||||
if (!(wm = find_module( mod_name )))
|
||||
{
|
||||
ERR("module not found for forward '%s' used by '%s'\n",
|
||||
forward, get_modref(module)->filename );
|
||||
|
@ -305,12 +354,12 @@ static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
|
|||
|
||||
|
||||
/****************************************************************
|
||||
* PE_fixup_imports
|
||||
* fixup_imports
|
||||
*
|
||||
* Fixup all imports of a given module.
|
||||
* The loader_section must be locked while calling this function.
|
||||
*/
|
||||
DWORD PE_fixup_imports( WINE_MODREF *wm )
|
||||
static NTSTATUS fixup_imports( WINE_MODREF *wm )
|
||||
{
|
||||
int i, nb_imports;
|
||||
IMAGE_IMPORT_DESCRIPTOR *imports;
|
||||
|
@ -319,7 +368,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
|
|||
|
||||
if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
|
||||
return 0;
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
nb_imports = size / sizeof(*imports);
|
||||
for (i = 0; i < nb_imports; i++)
|
||||
|
@ -330,7 +379,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!nb_imports) return 0; /* no imports */
|
||||
if (!nb_imports) return STATUS_SUCCESS; /* no imports */
|
||||
|
||||
/* Allocate module dependency list */
|
||||
wm->nDeps = nb_imports;
|
||||
|
@ -346,7 +395,8 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
|
|||
if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) break;
|
||||
}
|
||||
current_modref = prev;
|
||||
return (i < nb_imports);
|
||||
if (i < nb_imports) return STATUS_DLL_NOT_FOUND;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -634,6 +684,7 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
|||
LDR_MODULE, InLoadOrderModuleList),
|
||||
WINE_MODREF, ldr);
|
||||
wm->ldr.LoadCount = -1; /* can't unload main exe */
|
||||
if ((status = fixup_imports( wm )) != STATUS_SUCCESS) goto done;
|
||||
if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
|
||||
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
|
||||
}
|
||||
|
@ -809,55 +860,6 @@ NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
|
|||
return STATUS_NO_MORE_ENTRIES;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* MODULE_FindModule
|
||||
*
|
||||
* Find a (loaded) win32 module depending on path
|
||||
* LPCSTR path: [in] pathname of module/library to be found
|
||||
*
|
||||
* The loader_section must be locked while calling this function
|
||||
* RETURNS
|
||||
* the module handle if found
|
||||
* 0 if not
|
||||
*/
|
||||
WINE_MODREF *MODULE_FindModule(LPCSTR path)
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
PLIST_ENTRY mark, entry;
|
||||
PLDR_MODULE mod;
|
||||
char dllname[260], *p;
|
||||
|
||||
/* Append .DLL to name if no extension present */
|
||||
strcpy( dllname, path );
|
||||
if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
|
||||
strcat( dllname, ".DLL" );
|
||||
|
||||
if ((wm = cached_modref) != NULL)
|
||||
{
|
||||
if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
|
||||
}
|
||||
|
||||
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
|
||||
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
|
||||
{
|
||||
mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
|
||||
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
|
||||
|
||||
if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
|
||||
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
|
||||
}
|
||||
if (entry == mark) wm = NULL;
|
||||
|
||||
cached_modref = wm;
|
||||
return wm;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* LdrLockLoaderLock (NTDLL.@)
|
||||
*
|
||||
|
@ -906,7 +908,7 @@ NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE
|
|||
|
||||
/* FIXME: we should store module name information as unicode */
|
||||
RtlUnicodeStringToAnsiString( &str, name, TRUE );
|
||||
wm = MODULE_FindModule( str.Buffer );
|
||||
wm = find_module( str.Buffer );
|
||||
RtlFreeAnsiString( &str );
|
||||
|
||||
if (!wm)
|
||||
|
@ -956,6 +958,97 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_builtin_callback
|
||||
*
|
||||
* Load a library in memory; callback function for wine_dll_register
|
||||
*/
|
||||
static void load_builtin_callback( void *module, const char *filename )
|
||||
{
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
WINE_MODREF *wm;
|
||||
char *fullname;
|
||||
DWORD len;
|
||||
|
||||
if (!module)
|
||||
{
|
||||
ERR("could not map image for %s\n", filename ? filename : "main exe" );
|
||||
return;
|
||||
}
|
||||
if (!(nt = RtlImageNtHeader( module )))
|
||||
{
|
||||
ERR( "bad module for %s\n", filename ? filename : "main exe" );
|
||||
last_builtin_status = STATUS_INVALID_IMAGE_FORMAT;
|
||||
return;
|
||||
}
|
||||
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
{
|
||||
/* if we already have an executable, ignore this one */
|
||||
if (!NtCurrentTeb()->Peb->ImageBaseAddress)
|
||||
NtCurrentTeb()->Peb->ImageBaseAddress = module;
|
||||
return; /* don't create the modref here, will be done later on */
|
||||
}
|
||||
|
||||
if (find_module( filename ))
|
||||
MESSAGE( "Warning: loading builtin %s, but native version already present. "
|
||||
"Expect trouble.\n", filename );
|
||||
|
||||
/* create the MODREF */
|
||||
|
||||
len = GetSystemDirectoryA( NULL, 0 );
|
||||
if (!(fullname = RtlAllocateHeap( ntdll_get_process_heap(), 0, len + strlen(filename) + 1 )))
|
||||
{
|
||||
ERR( "can't load %s\n", filename );
|
||||
last_builtin_status = STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
GetSystemDirectoryA( fullname, len );
|
||||
strcat( fullname, "\\" );
|
||||
strcat( fullname, filename );
|
||||
|
||||
wm = MODULE_AllocModRef( module, fullname );
|
||||
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
|
||||
if (!wm)
|
||||
{
|
||||
ERR( "can't load %s\n", filename );
|
||||
last_builtin_status = STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
wm->ldr.Flags |= LDR_WINE_INTERNAL;
|
||||
|
||||
/* fixup imports */
|
||||
|
||||
if (fixup_imports( wm ) != STATUS_SUCCESS)
|
||||
{
|
||||
/* the module has only be inserted in the load & memory order lists */
|
||||
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
|
||||
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
|
||||
/* FIXME: free the modref */
|
||||
last_builtin_status = STATUS_DLL_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
TRACE( "loaded %s %p %p\n", filename, wm, module );
|
||||
|
||||
/* send the DLL load event */
|
||||
|
||||
SERVER_START_REQ( load_dll )
|
||||
{
|
||||
req->handle = 0;
|
||||
req->base = module;
|
||||
req->size = nt->OptionalHeader.SizeOfImage;
|
||||
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
|
||||
req->dbg_size = nt->FileHeader.NumberOfSymbols;
|
||||
req->name = &wm->filename;
|
||||
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
|
||||
wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
/* setup relay debugging entry points */
|
||||
if (TRACE_ON(relay)) RELAY_SetupDLL( module );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* allocate_lib_dir
|
||||
*
|
||||
|
@ -987,6 +1080,166 @@ static LPCSTR allocate_lib_dir(LPCSTR libname)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* load_native_dll (internal)
|
||||
*/
|
||||
static NTSTATUS load_native_dll( LPCSTR name, DWORD flags, WINE_MODREF** pwm )
|
||||
{
|
||||
void *module;
|
||||
HANDLE file, mapping;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER size;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
DWORD len = 0;
|
||||
WINE_MODREF *wm;
|
||||
NTSTATUS status;
|
||||
UINT drive_type;
|
||||
|
||||
file = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (file == 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;
|
||||
}
|
||||
|
||||
TRACE( "loading %s\n", debugstr_a(name) );
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
attr.ObjectName = NULL;
|
||||
attr.Attributes = 0;
|
||||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
size.QuadPart = 0;
|
||||
|
||||
status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
|
||||
&attr, &size, 0, SEC_IMAGE, file );
|
||||
if (status != STATUS_SUCCESS) goto done;
|
||||
|
||||
module = NULL;
|
||||
status = NtMapViewOfSection( mapping, GetCurrentProcess(),
|
||||
&module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
|
||||
NtClose( mapping );
|
||||
if (status != STATUS_SUCCESS) goto done;
|
||||
|
||||
/* create the MODREF */
|
||||
|
||||
if (!(wm = MODULE_AllocModRef( module, name )))
|
||||
{
|
||||
status = STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fixup imports */
|
||||
|
||||
if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
|
||||
{
|
||||
if ((status = fixup_imports(wm)) != STATUS_SUCCESS)
|
||||
{
|
||||
/* the module has only be inserted in the load & memory order lists */
|
||||
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
|
||||
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
|
||||
|
||||
/* FIXME: there are several more dangling references
|
||||
* left. Including dlls loaded by this dll before the
|
||||
* failed one. Unrolling is rather difficult with the
|
||||
* current structure and we can leave them lying
|
||||
* around with no problems, so we don't care.
|
||||
* As these might reference our wm, we don't free it.
|
||||
*/
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS;
|
||||
|
||||
/* send DLL load event */
|
||||
|
||||
nt = RtlImageNtHeader( module );
|
||||
drive_type = GetDriveTypeA( wm->filename );
|
||||
|
||||
SERVER_START_REQ( load_dll )
|
||||
{
|
||||
req->handle = file;
|
||||
req->base = module;
|
||||
req->size = nt->OptionalHeader.SizeOfImage;
|
||||
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
|
||||
req->dbg_size = nt->FileHeader.NumberOfSymbols;
|
||||
req->name = &wm->filename;
|
||||
/* don't keep the file handle open on removable media */
|
||||
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) req->handle = 0;
|
||||
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
|
||||
wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (TRACE_ON(snoop)) SNOOP_SetupDLL( module );
|
||||
|
||||
*pwm = wm;
|
||||
status = STATUS_SUCCESS;
|
||||
done:
|
||||
NtClose( file );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_builtin_dll
|
||||
*/
|
||||
static NTSTATUS load_builtin_dll( LPCSTR path, DWORD flags, WINE_MODREF** pwm )
|
||||
{
|
||||
char error[256], dllname[MAX_PATH], *p;
|
||||
int file_exists;
|
||||
LPCSTR name;
|
||||
void *handle;
|
||||
WINE_MODREF *wm;
|
||||
|
||||
/* Fix the name in case we have a full path and extension */
|
||||
name = path;
|
||||
if ((p = strrchr( name, '\\' ))) name = p + 1;
|
||||
if ((p = strrchr( name, '/' ))) name = p + 1;
|
||||
|
||||
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);
|
||||
|
||||
last_builtin_status = STATUS_SUCCESS;
|
||||
/* load_library will modify last_builtin_status. Note also that load_library can be
|
||||
* called several times, if the .so file we're loading has dependencies.
|
||||
* last_builtin_status will gather all the errors we may get while loading all these
|
||||
* libraries
|
||||
*/
|
||||
if (!(handle = wine_dll_load( dllname, error, sizeof(error), &file_exists )))
|
||||
{
|
||||
if (!file_exists)
|
||||
{
|
||||
/* The file does not exist -> WARN() */
|
||||
WARN("cannot open .so lib for builtin %s: %s\n", name, error);
|
||||
return STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
/* ERR() for all other errors (missing functions, ...) */
|
||||
ERR("failed to load .so lib for builtin %s: %s\n", name, error );
|
||||
return STATUS_PROCEDURE_NOT_FOUND;
|
||||
}
|
||||
if (last_builtin_status != STATUS_SUCCESS) return last_builtin_status;
|
||||
|
||||
if (!(wm = find_module( path ))) wm = find_module( dllname );
|
||||
if (!wm)
|
||||
{
|
||||
ERR( "loaded .so but dll %s still not found - 16-bit dll or version conflict.\n", dllname );
|
||||
/* wine_dll_unload( handle );*/
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
wm->dlhandle = handle;
|
||||
*pwm = wm;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_dll (internal)
|
||||
*
|
||||
|
@ -1049,7 +1302,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
|
|||
}
|
||||
|
||||
/* Check for already loaded module */
|
||||
if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
|
||||
if (!(*pwm = find_module(filename)) && !FILE_contains_path(libname))
|
||||
{
|
||||
LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
|
||||
if (fn)
|
||||
|
@ -1064,7 +1317,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
|
|||
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)
|
||||
if ((*pwm = find_module( fn )) != NULL)
|
||||
strcpy( filename, fn );
|
||||
RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
|
||||
}
|
||||
|
@ -1077,7 +1330,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
|
|||
!(flags & DONT_RESOLVE_DLL_REFERENCES))
|
||||
{
|
||||
(*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
|
||||
PE_fixup_imports( *pwm );
|
||||
fixup_imports( *pwm );
|
||||
}
|
||||
TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
|
||||
if (allocated_libdir)
|
||||
|
@ -1100,16 +1353,14 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
|
|||
{
|
||||
case LOADORDER_DLL:
|
||||
TRACE("Trying native dll '%s'\n", filename);
|
||||
nts = PE_LoadLibraryExA(filename, flags, pwm);
|
||||
nts = load_native_dll(filename, flags, pwm);
|
||||
filetype = "native";
|
||||
break;
|
||||
|
||||
case LOADORDER_BI:
|
||||
TRACE("Trying built-in '%s'\n", filename);
|
||||
nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
|
||||
nts = load_builtin_dll(filename, flags, pwm);
|
||||
filetype = "builtin";
|
||||
break;
|
||||
|
||||
default:
|
||||
nts = STATUS_INTERNAL_ERROR;
|
||||
break;
|
||||
|
@ -1505,3 +1756,24 @@ PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
|
|||
if (section) *section = sec;
|
||||
return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* BUILTIN32_Init
|
||||
*
|
||||
* Initialize loading callbacks and return HMODULE of main exe.
|
||||
* 'main' is the main exe in case it was already loaded from a PE file.
|
||||
*
|
||||
* FIXME: this should be done differently once kernel is properly separated.
|
||||
*/
|
||||
HMODULE BUILTIN32_LoadExeModule( HMODULE main )
|
||||
{
|
||||
NtCurrentTeb()->Peb->ImageBaseAddress = main;
|
||||
last_builtin_status = STATUS_SUCCESS;
|
||||
wine_dll_set_callback( load_builtin_callback );
|
||||
if (!NtCurrentTeb()->Peb->ImageBaseAddress)
|
||||
MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
|
||||
if (last_builtin_status != STATUS_SUCCESS)
|
||||
MESSAGE( "Error while processing initial modules\n");
|
||||
return NtCurrentTeb()->Peb->ImageBaseAddress;
|
||||
}
|
||||
|
|
|
@ -40,13 +40,12 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl
|
|||
const LARGE_INTEGER *timeout );
|
||||
|
||||
/* module handling */
|
||||
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
|
||||
|
||||
extern FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
|
||||
DWORD exp_size, FARPROC proc, const char *user );
|
||||
extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
|
||||
FARPROC origfun, DWORD ordinal );
|
||||
extern void RELAY_SetupDLL( const char *module );
|
||||
extern void SNOOP_SetupDLL( HMODULE hmod );
|
||||
|
||||
static inline HANDLE ntdll_get_process_heap(void)
|
||||
{
|
||||
|
|
|
@ -181,7 +181,6 @@ enum binary_type
|
|||
/* module.c */
|
||||
extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
|
||||
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
|
||||
extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
|
||||
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
|
||||
extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );
|
||||
extern void MODULE_WalkModref( DWORD id );
|
||||
|
@ -216,20 +215,12 @@ extern void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code );
|
|||
extern HRSRC PE_FindResourceW(HMODULE,LPCWSTR,LPCWSTR);
|
||||
extern HRSRC PE_FindResourceExW(HMODULE,LPCWSTR,LPCWSTR,WORD);
|
||||
|
||||
/* loader/pe_image.c */
|
||||
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 );
|
||||
extern DWORD PE_fixup_imports(WINE_MODREF *wm);
|
||||
|
||||
/* loader/loadorder.c */
|
||||
extern BOOL MODULE_GetBuiltinPath( const char *libname, const char *ext, char *filename, UINT size );
|
||||
extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BOOL win32 );
|
||||
extern void MODULE_AddLoadOrderOption( const char *option );
|
||||
|
||||
/* relay32/builtin.c */
|
||||
extern NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, WINE_MODREF**);
|
||||
extern HMODULE BUILTIN32_LoadExeModule( HMODULE main );
|
||||
|
||||
#endif /* __WINE_MODULE_H */
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include <module.h>
|
||||
|
||||
extern void SNOOP_RegisterDLL(HMODULE,LPCSTR,DWORD,DWORD);
|
||||
extern void SNOOP16_RegisterDLL(NE_MODULE*,LPCSTR);
|
||||
extern FARPROC16 SNOOP16_GetProcAddress16(HMODULE16,DWORD,FARPROC16);
|
||||
extern int SNOOP_ShowDebugmsgSnoop(const char *dll,int ord,const char *fname);
|
||||
|
|
|
@ -1,352 +0,0 @@
|
|||
/*
|
||||
* Copyright 1994 Eric Youndale & Erik Bos
|
||||
* Copyright 1995 Martin von Löwis
|
||||
* Copyright 1996-98 Marcus Meissner
|
||||
*
|
||||
* based on Eric Youndale's pe-test and:
|
||||
* ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/* Notes:
|
||||
* Before you start changing something in this file be aware of the following:
|
||||
*
|
||||
* - There are several functions called recursively. In a very subtle and
|
||||
* obscure way. DLLs can reference each other recursively etc.
|
||||
* - If you want to enhance, speed up or clean up something in here, think
|
||||
* twice WHY it is implemented in that strange way. There is usually a reason.
|
||||
* Though sometimes it might just be lazyness ;)
|
||||
* - In PE_MapImage, right before PE_fixup_imports() all external and internal
|
||||
* state MUST be correct since this function can be called with the SAME image
|
||||
* AGAIN. (Thats recursion for you.) That means MODREF.module and
|
||||
* NE_MODULE.module32.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "ntstatus.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "snoop.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
#include "ntdll_misc.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(win32);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(module);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
|
||||
/* convert PE image VirtualAddress to Real Address */
|
||||
inline static void *get_rva( HMODULE module, DWORD va )
|
||||
{
|
||||
return (void *)((char *)module + va);
|
||||
}
|
||||
|
||||
#define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
|
||||
|
||||
void dump_exports( HMODULE hModule )
|
||||
{
|
||||
char *Module;
|
||||
int i, j;
|
||||
WORD *ordinal;
|
||||
DWORD *function,*functions;
|
||||
DWORD *name;
|
||||
IMAGE_EXPORT_DIRECTORY *pe_exports;
|
||||
DWORD rva_start, size;
|
||||
|
||||
pe_exports = RtlImageDirectoryEntryToData( hModule, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
|
||||
rva_start = (char *)pe_exports - (char *)hModule;
|
||||
|
||||
Module = get_rva(hModule, pe_exports->Name);
|
||||
DPRINTF("*******EXPORT DATA*******\n");
|
||||
DPRINTF("Module name is %s, %ld functions, %ld names\n",
|
||||
Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
|
||||
|
||||
ordinal = get_rva(hModule, pe_exports->AddressOfNameOrdinals);
|
||||
functions = function = get_rva(hModule, pe_exports->AddressOfFunctions);
|
||||
name = get_rva(hModule, pe_exports->AddressOfNames);
|
||||
|
||||
DPRINTF(" Ord RVA Addr Name\n" );
|
||||
for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
|
||||
{
|
||||
if (!*function) continue; /* No such function */
|
||||
DPRINTF( "%4ld %08lx %p", i + pe_exports->Base, *function, get_rva(hModule, *function) );
|
||||
/* Check if we have a name for it */
|
||||
for (j = 0; j < pe_exports->NumberOfNames; j++)
|
||||
if (ordinal[j] == i)
|
||||
{
|
||||
DPRINTF( " %s", (char*)get_rva(hModule, name[j]) );
|
||||
break;
|
||||
}
|
||||
if ((*function >= rva_start) && (*function <= rva_start + size))
|
||||
DPRINTF(" (forwarded -> %s)", (char *)get_rva(hModule, *function));
|
||||
DPRINTF("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* PE_LoadImage
|
||||
* Load one PE format DLL/EXE into memory
|
||||
*
|
||||
* Unluckily we can't just mmap the sections where we want them, for
|
||||
* (at least) Linux does only support offsets which are page-aligned.
|
||||
*
|
||||
* BUT we have to map the whole image anyway, for Win32 programs sometimes
|
||||
* want to access them. (HMODULE points to the start of it)
|
||||
*/
|
||||
HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags )
|
||||
{
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
HMODULE hModule;
|
||||
HANDLE mapping;
|
||||
void *base = NULL;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER lg_int;
|
||||
DWORD len = 0;
|
||||
NTSTATUS nts;
|
||||
|
||||
TRACE_(module)( "loading %s\n", filename );
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
attr.ObjectName = NULL;
|
||||
attr.Attributes = 0;
|
||||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
|
||||
lg_int.QuadPart = 0;
|
||||
|
||||
if (NtCreateSection( &mapping,
|
||||
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
|
||||
&attr, &lg_int, 0, SEC_IMAGE, hFile ) != STATUS_SUCCESS)
|
||||
return 0;
|
||||
|
||||
nts = NtMapViewOfSection( mapping, GetCurrentProcess(),
|
||||
&base, 0, 0, &lg_int, &len, ViewShare, 0,
|
||||
PAGE_READONLY );
|
||||
|
||||
NtClose( mapping );
|
||||
if (nts != STATUS_SUCCESS) return 0;
|
||||
|
||||
/* virus check */
|
||||
|
||||
hModule = (HMODULE)base;
|
||||
nt = RtlImageNtHeader( hModule );
|
||||
|
||||
if (nt->OptionalHeader.AddressOfEntryPoint)
|
||||
{
|
||||
if (!RtlImageRvaToSection( nt, hModule, nt->OptionalHeader.AddressOfEntryPoint ))
|
||||
MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
|
||||
"outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
|
||||
nt->OptionalHeader.AddressOfEntryPoint );
|
||||
}
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* PE_CreateModule
|
||||
*
|
||||
* Create WINE_MODREF structure for loaded HMODULE, link it into
|
||||
* process modref_list, and fixup all imports.
|
||||
*
|
||||
* Note: hModule must point to a correctly allocated PE image,
|
||||
* with base relocations applied; the 16-bit dummy module
|
||||
* associated to hModule must already exist.
|
||||
*
|
||||
* Note: This routine must always be called in the context of the
|
||||
* process that is to own the module to be created.
|
||||
*
|
||||
* Note: Assumes that the process critical section is held
|
||||
*/
|
||||
WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags,
|
||||
HANDLE hFile, BOOL builtin )
|
||||
{
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
IMAGE_DATA_DIRECTORY *dir;
|
||||
IMAGE_EXPORT_DIRECTORY *pe_export = NULL;
|
||||
WINE_MODREF *wm;
|
||||
|
||||
/* Retrieve DataDirectory entries */
|
||||
|
||||
nt = RtlImageNtHeader(hModule);
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT;
|
||||
if (dir->Size) pe_export = get_rva(hModule, dir->VirtualAddress);
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION;
|
||||
if (dir->Size) FIXME("Exception directory ignored\n" );
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY;
|
||||
if (dir->Size) FIXME("Security directory ignored\n" );
|
||||
|
||||
/* IMAGE_DIRECTORY_ENTRY_BASERELOC handled in PE_LoadImage */
|
||||
/* IMAGE_DIRECTORY_ENTRY_DEBUG handled by debugger */
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR;
|
||||
if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" );
|
||||
|
||||
/* IMAGE_DIRECTORY_ENTRY_TLS handled in PE_TlsInit */
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
|
||||
if (dir->Size) FIXME("Load Configuration directory ignored\n" );
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT;
|
||||
if (dir->Size) TRACE("Bound Import directory ignored\n" );
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT;
|
||||
if (dir->Size) TRACE("Import Address Table directory ignored\n" );
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
|
||||
if (dir->Size)
|
||||
{
|
||||
TRACE("Delayed import, stub calls LoadLibrary\n" );
|
||||
/*
|
||||
* Nothing to do here.
|
||||
*/
|
||||
|
||||
#ifdef ImgDelayDescr
|
||||
/*
|
||||
* This code is useful to observe what the heck is going on.
|
||||
*/
|
||||
{
|
||||
ImgDelayDescr *pe_delay = NULL;
|
||||
pe_delay = get_rva(hModule, dir->VirtualAddress);
|
||||
TRACE("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs);
|
||||
TRACE("pe_delay->szName = %s\n", pe_delay->szName);
|
||||
TRACE("pe_delay->phmod = %08x\n", pe_delay->phmod);
|
||||
TRACE("pe_delay->pIAT = %08x\n", pe_delay->pIAT);
|
||||
TRACE("pe_delay->pINT = %08x\n", pe_delay->pINT);
|
||||
TRACE("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT);
|
||||
TRACE("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT);
|
||||
TRACE("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp);
|
||||
}
|
||||
#endif /* ImgDelayDescr */
|
||||
}
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR;
|
||||
if (dir->Size) FIXME("Unknown directory 14 ignored\n" );
|
||||
|
||||
dir = nt->OptionalHeader.DataDirectory+15;
|
||||
if (dir->Size) FIXME("Unknown directory 15 ignored\n" );
|
||||
|
||||
/* Allocate and fill WINE_MODREF */
|
||||
|
||||
if (!(wm = MODULE_AllocModRef( hModule, filename ))) return NULL;
|
||||
|
||||
if ( builtin )
|
||||
wm->ldr.Flags |= LDR_WINE_INTERNAL;
|
||||
else if ( flags & DONT_RESOLVE_DLL_REFERENCES )
|
||||
wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS;
|
||||
|
||||
/* Dump Exports */
|
||||
|
||||
if (pe_export && TRACE_ON(win32))
|
||||
dump_exports( hModule );
|
||||
|
||||
/* Fixup Imports */
|
||||
|
||||
if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
|
||||
PE_fixup_imports( wm ))
|
||||
{
|
||||
/* the module has only be inserted in the load & memory order lists */
|
||||
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
|
||||
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
|
||||
|
||||
/* FIXME: there are several more dangling references
|
||||
* left. Including dlls loaded by this dll before the
|
||||
* failed one. Unrolling is rather difficult with the
|
||||
* current structure and we can leave them lying
|
||||
* around with no problems, so we don't care.
|
||||
* As these might reference our wm, we don't free it.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!builtin && pe_export)
|
||||
SNOOP_RegisterDLL( hModule, wm->modname, pe_export->Base, pe_export->NumberOfFunctions );
|
||||
|
||||
/* Send DLL load event */
|
||||
/* we don't need to send a dll event for the main exe */
|
||||
|
||||
if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
|
||||
{
|
||||
if (hFile)
|
||||
{
|
||||
UINT drive_type = GetDriveTypeA( wm->short_filename );
|
||||
/* don't keep the file handle open on removable media */
|
||||
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) hFile = 0;
|
||||
}
|
||||
SERVER_START_REQ( load_dll )
|
||||
{
|
||||
req->handle = hFile;
|
||||
req->base = (void *)hModule;
|
||||
req->size = nt->OptionalHeader.SizeOfImage;
|
||||
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
|
||||
req->dbg_size = nt->FileHeader.NumberOfSymbols;
|
||||
req->name = &wm->filename;
|
||||
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
|
||||
wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
|
||||
return wm;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* The PE Library Loader frontend.
|
||||
* FIXME: handle the flags.
|
||||
*/
|
||||
NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm)
|
||||
{
|
||||
HMODULE hModule32;
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
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 STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/* Create 32-bit MODREF */
|
||||
if ( !(*pwm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
|
||||
{
|
||||
ERR( "can't load %s\n", name );
|
||||
CloseHandle( hFile );
|
||||
return STATUS_NO_MEMORY; /* FIXME */
|
||||
}
|
||||
|
||||
CloseHandle( hFile );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* Win32 builtin functions
|
||||
*
|
||||
* Copyright 1997 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wine/library.h"
|
||||
#include "module.h"
|
||||
#include "file.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(module);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
static HMODULE main_module;
|
||||
static NTSTATUS last_status; /* use to gather all errors in callback */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* load_library
|
||||
*
|
||||
* Load a library in memory; callback function for wine_dll_register
|
||||
*/
|
||||
static void load_library( void *base, const char *filename )
|
||||
{
|
||||
UNICODE_STRING wstr;
|
||||
HMODULE module = (HMODULE)base, ret;
|
||||
IMAGE_NT_HEADERS *nt;
|
||||
WINE_MODREF *wm;
|
||||
char *fullname;
|
||||
DWORD len;
|
||||
|
||||
if (!base)
|
||||
{
|
||||
ERR("could not map image for %s\n", filename ? filename : "main exe" );
|
||||
return;
|
||||
}
|
||||
if (!(nt = RtlImageNtHeader( module )))
|
||||
{
|
||||
ERR( "bad module for %s\n", filename ? filename : "main exe" );
|
||||
last_status = STATUS_INVALID_IMAGE_FORMAT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||
{
|
||||
/* if we already have an executable, ignore this one */
|
||||
if (!main_module) main_module = module;
|
||||
return; /* don't create the modref here, will be done later on */
|
||||
}
|
||||
|
||||
RtlCreateUnicodeStringFromAsciiz(&wstr, filename);
|
||||
if (LdrGetDllHandle(0, 0, &wstr, &ret) == STATUS_SUCCESS)
|
||||
MESSAGE( "Warning: loading builtin %s, but native version already present. "
|
||||
"Expect trouble.\n", filename );
|
||||
RtlFreeUnicodeString( &wstr );
|
||||
|
||||
len = GetSystemDirectoryA( NULL, 0 );
|
||||
if (!(fullname = RtlAllocateHeap( ntdll_get_process_heap(), 0, len + strlen(filename) + 1 )))
|
||||
{
|
||||
ERR( "can't load %s\n", filename );
|
||||
last_status = STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
GetSystemDirectoryA( fullname, len );
|
||||
strcat( fullname, "\\" );
|
||||
strcat( fullname, filename );
|
||||
|
||||
/* Create 32-bit MODREF */
|
||||
if (!(wm = PE_CreateModule( module, fullname, 0, 0, TRUE )))
|
||||
{
|
||||
ERR( "can't load %s\n", filename );
|
||||
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
|
||||
last_status = STATUS_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
TRACE( "loaded %s %p %p\n", fullname, wm, module );
|
||||
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
|
||||
|
||||
/* setup relay debugging entry points */
|
||||
if (TRACE_ON(relay)) RELAY_SetupDLL( (void *)module );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* BUILTIN32_LoadLibraryExA
|
||||
*
|
||||
* Partly copied from the original PE_ version.
|
||||
*
|
||||
*/
|
||||
NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, WINE_MODREF** pwm)
|
||||
{
|
||||
char error[256], dllname[MAX_PATH], *p;
|
||||
int file_exists;
|
||||
LPCSTR name;
|
||||
void *handle;
|
||||
|
||||
/* Fix the name in case we have a full path and extension */
|
||||
name = path;
|
||||
if ((p = strrchr( name, '\\' ))) name = p + 1;
|
||||
if ((p = strrchr( name, '/' ))) name = p + 1;
|
||||
|
||||
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);
|
||||
|
||||
last_status = STATUS_SUCCESS;
|
||||
/* load_library will modify last_status. Note also that load_library can be
|
||||
* called several times, if the .so file we're loading has dependencies.
|
||||
* last_status will gather all the errors we may get while loading all these
|
||||
* libraries
|
||||
*/
|
||||
if (!(handle = wine_dll_load( dllname, error, sizeof(error), &file_exists )))
|
||||
{
|
||||
if (!file_exists)
|
||||
{
|
||||
/* The file does not exist -> WARN() */
|
||||
WARN("cannot open .so lib for builtin %s: %s\n", name, error);
|
||||
return STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
/* ERR() for all other errors (missing functions, ...) */
|
||||
ERR("failed to load .so lib for builtin %s: %s\n", name, error );
|
||||
return STATUS_PROCEDURE_NOT_FOUND;
|
||||
}
|
||||
if (last_status != STATUS_SUCCESS) return last_status;
|
||||
|
||||
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 );*/
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
(*pwm)->dlhandle = handle;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* BUILTIN32_Init
|
||||
*
|
||||
* Initialize loading callbacks and return HMODULE of main exe.
|
||||
* 'main' is the main exe in case it was already loaded from a PE file.
|
||||
*/
|
||||
HMODULE BUILTIN32_LoadExeModule( HMODULE main )
|
||||
{
|
||||
main_module = main;
|
||||
last_status = STATUS_SUCCESS;
|
||||
wine_dll_set_callback( load_library );
|
||||
if (!main_module)
|
||||
MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
|
||||
if (last_status != STATUS_SUCCESS)
|
||||
MESSAGE( "Error while processing initial modules\n");
|
||||
|
||||
return main_module;
|
||||
}
|
|
@ -142,47 +142,51 @@ int SNOOP_ShowDebugmsgSnoop(const char *dll, int ord, const char *fname) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
SNOOP_RegisterDLL(HMODULE hmod,LPCSTR name,DWORD ordbase,DWORD nrofordinals) {
|
||||
SNOOP_DLL **dll = &(firstdll);
|
||||
char *s;
|
||||
void *addr;
|
||||
SIZE_T size;
|
||||
void SNOOP_SetupDLL(HMODULE hmod)
|
||||
{
|
||||
SNOOP_DLL **dll = &firstdll;
|
||||
char *p, *name;
|
||||
void *addr;
|
||||
SIZE_T size;
|
||||
IMAGE_EXPORT_DIRECTORY *exports;
|
||||
|
||||
TRACE("hmod=%p, name=%s, ordbase=%ld, nrofordinals=%ld\n",
|
||||
hmod, name, ordbase, nrofordinals);
|
||||
exports = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
|
||||
if (!exports) return;
|
||||
name = (char *)hmod + exports->Name;
|
||||
|
||||
if (!TRACE_ON(snoop)) return;
|
||||
while (*dll) {
|
||||
if ((*dll)->hmod == hmod)
|
||||
{
|
||||
/* another dll, loaded at the same address */
|
||||
addr = (*dll)->funs;
|
||||
size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
|
||||
NtFreeVirtualMemory(GetCurrentProcess(), &addr, &size, MEM_RELEASE);
|
||||
break;
|
||||
}
|
||||
dll = &((*dll)->next);
|
||||
}
|
||||
*dll = RtlReAllocateHeap(ntdll_get_process_heap(),
|
||||
HEAP_ZERO_MEMORY, *dll,
|
||||
sizeof(SNOOP_DLL) + strlen(name));
|
||||
(*dll)->hmod = hmod;
|
||||
(*dll)->ordbase = ordbase;
|
||||
(*dll)->nrofordinals = nrofordinals;
|
||||
strcpy( (*dll)->name, name );
|
||||
if ((s=strrchr((*dll)->name,'.')))
|
||||
*s='\0';
|
||||
size = nrofordinals * sizeof(SNOOP_FUN);
|
||||
NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size,
|
||||
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!addr) {
|
||||
RtlFreeHeap(ntdll_get_process_heap(),0,*dll);
|
||||
FIXME("out of memory\n");
|
||||
return;
|
||||
}
|
||||
(*dll)->funs = addr;
|
||||
memset((*dll)->funs,0,size);
|
||||
TRACE("hmod=%p, name=%s\n", hmod, name);
|
||||
|
||||
while (*dll) {
|
||||
if ((*dll)->hmod == hmod)
|
||||
{
|
||||
/* another dll, loaded at the same address */
|
||||
addr = (*dll)->funs;
|
||||
size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
|
||||
NtFreeVirtualMemory(GetCurrentProcess(), &addr, &size, MEM_RELEASE);
|
||||
break;
|
||||
}
|
||||
dll = &((*dll)->next);
|
||||
}
|
||||
*dll = RtlReAllocateHeap(ntdll_get_process_heap(),
|
||||
HEAP_ZERO_MEMORY, *dll,
|
||||
sizeof(SNOOP_DLL) + strlen(name));
|
||||
(*dll)->hmod = hmod;
|
||||
(*dll)->ordbase = exports->Base;
|
||||
(*dll)->nrofordinals = exports->NumberOfFunctions;
|
||||
strcpy( (*dll)->name, name );
|
||||
p = (*dll)->name + strlen((*dll)->name) - 4;
|
||||
if (p > (*dll)->name && !strcasecmp( p, ".dll" )) *p = 0;
|
||||
|
||||
size = exports->NumberOfFunctions * sizeof(SNOOP_FUN);
|
||||
NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size,
|
||||
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!addr) {
|
||||
RtlFreeHeap(ntdll_get_process_heap(),0,*dll);
|
||||
FIXME("out of memory\n");
|
||||
return;
|
||||
}
|
||||
(*dll)->funs = addr;
|
||||
memset((*dll)->funs,0,size);
|
||||
}
|
||||
|
||||
FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
|
||||
|
@ -432,9 +436,10 @@ __ASM_GLOBAL_FUNC( SNOOP_Return,
|
|||
".long " __ASM_NAME("SNOOP_DoReturn") ",0" );
|
||||
|
||||
#else /* !__i386__ */
|
||||
void SNOOP_RegisterDLL(HMODULE hmod,LPCSTR name,DWORD nrofordinals, DWORD dw) {
|
||||
if (!TRACE_ON(snoop)) return;
|
||||
FIXME("snooping works only on i386 for now.\n");
|
||||
|
||||
void SNOOP_SetupDLL(HMODULE hmod)
|
||||
{
|
||||
FIXME("snooping works only on i386 for now.\n");
|
||||
}
|
||||
|
||||
FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
|
||||
|
|
Loading…
Reference in New Issue