loader.c 98.1 KB
Newer Older
1
/*
2 3
 * Loader functions
 *
4
 * Copyright 1995, 2003 Alexandre Julliard
5
 * Copyright 2002 Dmitry Timoshkov for CodeWeavers
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
22 23 24
#include "config.h"
#include "wine/port.h"

25
#include <assert.h>
26
#include <stdarg.h>
27 28 29
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
30

31 32 33
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

34 35
#include "ntstatus.h"
#define WIN32_NO_STATUS
36
#include "windef.h"
37
#include "winnt.h"
38
#include "winternl.h"
39

40
#include "wine/exception.h"
41
#include "wine/library.h"
42
#include "wine/unicode.h"
43
#include "wine/debug.h"
44 45
#include "wine/server.h"
#include "ntdll_misc.h"
46
#include "ddk/wdm.h"
47

48 49
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
50
WINE_DECLARE_DEBUG_CHANNEL(snoop);
51
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
52
WINE_DECLARE_DEBUG_CHANNEL(imports);
53

54 55 56 57
/* we don't want to include winuser.h */
#define RT_MANIFEST                         ((ULONG_PTR)24)
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)

58 59
typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);

60
static int process_detaching = 0;  /* set on process detach to avoid deadlocks with thread detach */
61
static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
62

63 64 65 66 67
static const char * const reason_names[] =
{
    "PROCESS_DETACH",
    "PROCESS_ATTACH",
    "THREAD_ATTACH",
68 69 70
    "THREAD_DETACH",
    NULL, NULL, NULL, NULL,
    "WINE_PREATTACH"
71 72
};

73 74 75
static const WCHAR dllW[] = {'.','d','l','l',0};

/* internal representation of 32bit modules. per process. */
76
typedef struct _wine_modref
77 78 79 80
{
    LDR_MODULE            ldr;
    int                   nDeps;
    struct _wine_modref **deps;
81
} WINE_MODREF;
82

83 84 85 86 87
/* info about the current builtin dll load */
/* used to keep track of things across the register_dll constructor call */
struct builtin_load_info
{
    const WCHAR *load_path;
88
    const WCHAR *filename;
89 90 91 92
    NTSTATUS     status;
    WINE_MODREF *wm;
};

93 94
static struct builtin_load_info default_load_info;
static struct builtin_load_info *builtin_load_info = &default_load_info;
95

96
static HANDLE main_exe_file;
97 98 99 100
static UINT tls_module_count;      /* number of modules with TLS directory */
static UINT tls_total_size;        /* total size of TLS storage */
static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */

101 102
static RTL_CRITICAL_SECTION loader_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
103 104 105
{
    0, 0, &loader_section,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
106
      0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
107
};
108
static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
109

110
static WINE_MODREF *cached_modref;
111
static WINE_MODREF *current_modref;
112
static WINE_MODREF *last_failed_modref;
113

114
static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm );
115
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
116 117
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
Eric Pouech's avatar
Eric Pouech committed
118
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
119
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
120 121

/* convert PE image VirtualAddress to Real Address */
122
static inline void *get_rva( HMODULE module, DWORD va )
123 124 125
{
    return (void *)((char *)module + va);
}
126

127
/* check whether the file name contains a path */
128
static inline int contains_path( LPCWSTR name )
129 130 131 132 133
{
    return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
}

/* convert from straight ASCII to Unicode without depending on the current codepage */
134
static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
135 136 137 138
{
    while (len--) *dst++ = (unsigned char)*src++;
}

139 140 141 142 143 144 145 146 147 148 149

/*************************************************************************
 *		call_dll_entry_point
 *
 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
 * their entry point, so we need a small asm wrapper.
 */
#ifdef __i386__
extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
__ASM_GLOBAL_FUNC(call_dll_entry_point,
                  "pushl %ebp\n\t"
150 151
                  __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                  __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
152
                  "movl %esp,%ebp\n\t"
153
                  __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
154
                  "pushl %ebx\n\t"
155
                  __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
156
                  "subl $8,%esp\n\t"
157 158 159 160 161 162 163
                  "pushl 20(%ebp)\n\t"
                  "pushl 16(%ebp)\n\t"
                  "pushl 12(%ebp)\n\t"
                  "movl 8(%ebp),%eax\n\t"
                  "call *%eax\n\t"
                  "leal -4(%ebp),%esp\n\t"
                  "popl %ebx\n\t"
164
                  __ASM_CFI(".cfi_same_value %ebx\n\t")
165
                  "popl %ebp\n\t"
166 167
                  __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
                  __ASM_CFI(".cfi_same_value %ebp\n\t")
168
                  "ret" )
169 170 171 172 173 174 175 176 177
#else /* __i386__ */
static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
                                         UINT reason, void *reserved )
{
    return proc( module, reason, reserved );
}
#endif /* __i386__ */


178
#if defined(__i386__) || defined(__x86_64__)
179 180 181 182 183
/*************************************************************************
 *		stub_entry_point
 *
 * Entry point for stub functions.
 */
184
static void stub_entry_point( const char *dll, const char *name, void *ret_addr )
185 186 187 188 189 190
{
    EXCEPTION_RECORD rec;

    rec.ExceptionCode           = EXCEPTION_WINE_STUB;
    rec.ExceptionFlags          = EH_NONCONTINUABLE;
    rec.ExceptionRecord         = NULL;
191
    rec.ExceptionAddress        = ret_addr;
192
    rec.NumberParameters        = 2;
193 194
    rec.ExceptionInformation[0] = (ULONG_PTR)dll;
    rec.ExceptionInformation[1] = (ULONG_PTR)name;
195 196 197 198
    for (;;) RtlRaiseException( &rec );
}


199
#include "pshpack1.h"
200
#ifdef __i386__
201 202 203 204 205 206
struct stub
{
    BYTE        pushl1;     /* pushl $name */
    const char *name;
    BYTE        pushl2;     /* pushl $dll */
    const char *dll;
207
    BYTE        call;       /* call stub_entry_point */
208 209
    DWORD       entry;
};
210 211 212 213 214 215 216 217 218 219 220 221 222
#else
struct stub
{
    BYTE movq_rdi[2];      /* movq $dll,%rdi */
    const char *dll;
    BYTE movq_rsi[2];      /* movq $name,%rsi */
    const char *name;
    BYTE movq_rsp_rdx[4];  /* movq (%rsp),%rdx */
    BYTE movq_rax[2];      /* movq $entry, %rax */
    const void* entry;
    BYTE jmpq_rax[2];      /* jmp %rax */
};
#endif
223
#include "poppack.h"
224 225 226 227 228 229

/*************************************************************************
 *		allocate_stub
 *
 * Allocate a stub entry point.
 */
230
static ULONG_PTR allocate_stub( const char *dll, const char *name )
231 232 233 234 235 236
{
#define MAX_SIZE 65536
    static struct stub *stubs;
    static unsigned int nb_stubs;
    struct stub *stub;

237
    if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
238 239 240

    if (!stubs)
    {
241
        SIZE_T size = MAX_SIZE;
242
        if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
243
                                     MEM_COMMIT, PAGE_EXECUTE_WRITECOPY ) != STATUS_SUCCESS)
244
            return 0xdeadbeef;
245 246
    }
    stub = &stubs[nb_stubs++];
247
#ifdef __i386__
248 249 250 251
    stub->pushl1    = 0x68;  /* pushl $name */
    stub->name      = name;
    stub->pushl2    = 0x68;  /* pushl $dll */
    stub->dll       = dll;
252
    stub->call      = 0xe8;  /* call stub_entry_point */
253
    stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
#else
    stub->movq_rdi[0]     = 0x48;  /* movq $dll,%rdi */
    stub->movq_rdi[1]     = 0xbf;
    stub->dll             = dll;
    stub->movq_rsi[0]     = 0x48;  /* movq $name,%rsi */
    stub->movq_rsi[1]     = 0xbe;
    stub->name            = name;
    stub->movq_rsp_rdx[0] = 0x48;  /* movq (%rsp),%rdx */
    stub->movq_rsp_rdx[1] = 0x8b;
    stub->movq_rsp_rdx[2] = 0x14;
    stub->movq_rsp_rdx[3] = 0x24;
    stub->movq_rax[0]     = 0x48;  /* movq $entry, %rax */
    stub->movq_rax[1]     = 0xb8;
    stub->entry           = stub_entry_point;
    stub->jmpq_rax[0]     = 0xff;  /* jmp %rax */
    stub->jmpq_rax[1]     = 0xe0;
#endif
271
    return (ULONG_PTR)stub;
272 273 274
}

#else  /* __i386__ */
275
static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
276 277 278
#endif  /* __i386__ */


279
/*************************************************************************
280 281 282 283
 *		get_modref
 *
 * Looks for the referenced HMODULE in the current process
 * The loader_section must be locked while calling this function.
284
 */
285
static WINE_MODREF *get_modref( HMODULE hmod )
286
{
287 288
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
289

290
    if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
291

292 293
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
294
    {
295 296 297 298
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (mod->BaseAddress == hmod)
            return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        if (mod->BaseAddress > (void*)hmod) break;
299
    }
300
    return NULL;
301 302 303
}


304
/**********************************************************************
305
 *	    find_basename_module
306
 *
307
 * Find a module from its base name.
308 309
 * The loader_section must be locked while calling this function
 */
310
static WINE_MODREF *find_basename_module( LPCWSTR name )
311 312 313
{
    PLIST_ENTRY mark, entry;

314 315
    if (cached_modref && !strcmpiW( name, cached_modref->ldr.BaseDllName.Buffer ))
        return cached_modref;
316

317 318
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
319
    {
320 321 322 323 324 325
        LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        if (!strcmpiW( name, mod->BaseDllName.Buffer ))
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
326
    }
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    return NULL;
}


/**********************************************************************
 *	    find_fullname_module
 *
 * Find a module from its full path name.
 * The loader_section must be locked while calling this function
 */
static WINE_MODREF *find_fullname_module( LPCWSTR name )
{
    PLIST_ENTRY mark, entry;

    if (cached_modref && !strcmpiW( name, cached_modref->ldr.FullDllName.Buffer ))
        return cached_modref;
343 344 345 346

    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
347 348 349 350 351 352
        LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        if (!strcmpiW( name, mod->FullDllName.Buffer ))
        {
            cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
            return cached_modref;
        }
353
    }
354
    return NULL;
355 356 357
}


358 359 360 361 362 363
/*************************************************************************
 *		find_forwarded_export
 *
 * Find the final function pointer for a forwarded function.
 * The loader_section must be locked while calling this function.
 */
364
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
365
{
Eric Pouech's avatar
Eric Pouech committed
366
    const IMAGE_EXPORT_DIRECTORY *exports;
367 368
    DWORD exp_size;
    WINE_MODREF *wm;
369
    WCHAR mod_name[32];
370
    const char *end = strrchr(forward, '.');
371 372 373
    FARPROC proc = NULL;

    if (!end) return NULL;
374
    if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
375
    ascii_to_unicode( mod_name, forward, end - forward );
376 377 378 379 380 381
    mod_name[end - forward] = 0;
    if (!strchrW( mod_name, '.' ))
    {
        if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
        memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
    }
382

383
    if (!(wm = find_basename_module( mod_name )))
384
    {
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
        TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
        if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS &&
            !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
        {
            if (process_attach( wm, NULL ) != STATUS_SUCCESS)
            {
                LdrUnloadDll( wm->ldr.BaseAddress );
                wm = NULL;
            }
        }

        if (!wm)
        {
            ERR( "module not found for forward '%s' used by %s\n",
                 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
            return NULL;
        }
402 403 404
    }
    if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
                                                 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
405 406 407 408 409 410 411
    {
        const char *name = end + 1;
        if (*name == '#')  /* ordinal */
            proc = find_ordinal_export( wm->ldr.BaseAddress, exports, exp_size, atoi(name+1), load_path );
        else
            proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, name, -1, load_path );
    }
412 413 414

    if (!proc)
    {
415 416 417 418
        ERR("function not found for forward '%s' used by %s."
            " If you are using builtin %s, try using the native one instead.\n",
            forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
            debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
419 420 421 422 423 424 425 426 427 428 429 430
    }
    return proc;
}


/*************************************************************************
 *		find_ordinal_export
 *
 * Find an exported function by ordinal.
 * The exports base must have been subtracted from the ordinal already.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
431
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
432
                                    DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
433 434
{
    FARPROC proc;
Eric Pouech's avatar
Eric Pouech committed
435
    const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
436 437 438

    if (ordinal >= exports->NumberOfFunctions)
    {
439
        TRACE("	ordinal %d out of range!\n", ordinal + exports->Base );
440 441 442 443 444 445 446
        return NULL;
    }
    if (!functions[ordinal]) return NULL;

    proc = get_rva( module, functions[ordinal] );

    /* if the address falls into the export dir, it's a forward */
Eric Pouech's avatar
Eric Pouech committed
447 448
    if (((const char *)proc >= (const char *)exports) && 
        ((const char *)proc < (const char *)exports + exp_size))
449
        return find_forwarded_export( module, (const char *)proc, load_path );
450

451
    if (TRACE_ON(snoop))
452
    {
453 454
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
        proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
455
    }
456
    if (TRACE_ON(relay))
457
    {
458
        const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
459
        proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
460 461 462 463 464 465 466 467 468 469 470
    }
    return proc;
}


/*************************************************************************
 *		find_named_export
 *
 * Find an exported function by name.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
471
static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
472
                                  DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
473
{
Eric Pouech's avatar
Eric Pouech committed
474 475
    const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
    const DWORD *names = get_rva( module, exports->AddressOfNames );
476 477 478 479 480 481 482
    int min = 0, max = exports->NumberOfNames - 1;

    /* first check the hint */
    if (hint >= 0 && hint <= max)
    {
        char *ename = get_rva( module, names[hint] );
        if (!strcmp( ename, name ))
483
            return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
484 485 486 487 488 489 490 491
    }

    /* then do a binary search */
    while (min <= max)
    {
        int res, pos = (min + max) / 2;
        char *ename = get_rva( module, names[pos] );
        if (!(res = strcmp( ename, name )))
492
            return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
493 494 495
        if (res > 0) max = pos - 1;
        else min = pos + 1;
    }
496
    return NULL;
497 498 499 500 501 502 503 504 505 506

}


/*************************************************************************
 *		import_dll
 *
 * Import the dll specified by the given import descriptor.
 * The loader_section must be locked while calling this function.
 */
Eric Pouech's avatar
Eric Pouech committed
507
static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
508 509 510 511
{
    NTSTATUS status;
    WINE_MODREF *wmImp;
    HMODULE imp_mod;
Eric Pouech's avatar
Eric Pouech committed
512
    const IMAGE_EXPORT_DIRECTORY *exports;
513
    DWORD exp_size;
Eric Pouech's avatar
Eric Pouech committed
514 515
    const IMAGE_THUNK_DATA *import_list;
    IMAGE_THUNK_DATA *thunk_list;
516
    WCHAR buffer[32];
Eric Pouech's avatar
Eric Pouech committed
517
    const char *name = get_rva( module, descr->Name );
518
    DWORD len = strlen(name);
519
    PVOID protect_base;
520
    SIZE_T protect_size = 0;
521
    DWORD protect_old;
522

523 524 525 526 527 528
    thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
    if (descr->u.OriginalFirstThunk)
        import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
    else
        import_list = thunk_list;

529 530 531
    while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */

    if (len * sizeof(WCHAR) < sizeof(buffer))
532 533
    {
        ascii_to_unicode( buffer, name, len );
534
        buffer[len] = 0;
535
        status = load_dll( load_path, buffer, 0, &wmImp );
536 537 538
    }
    else  /* need to allocate a larger buffer */
    {
539
        WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
540 541
        if (!ptr) return NULL;
        ascii_to_unicode( ptr, name, len );
542
        ptr[len] = 0;
543
        status = load_dll( load_path, ptr, 0, &wmImp );
544 545
        RtlFreeHeap( GetProcessHeap(), 0, ptr );
    }
546 547 548

    if (status)
    {
549
        if (status == STATUS_DLL_NOT_FOUND)
550
            ERR("Library %s (which is needed by %s) not found\n",
551
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
552
        else
553
            ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
554
                name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
555
        return NULL;
556 557
    }

558 559 560 561 562
    /* unprotect the import address table since it can be located in
     * readonly section */
    while (import_list[protect_size].u1.Ordinal) protect_size++;
    protect_base = thunk_list;
    protect_size *= sizeof(*thunk_list);
563
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
564 565
                            &protect_size, PAGE_WRITECOPY, &protect_old );

566 567 568
    imp_mod = wmImp->ldr.BaseAddress;
    exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );

569 570 571 572 573 574 575
    if (!exports)
    {
        /* set all imported function to deadbeef */
        while (import_list->u1.Ordinal)
        {
            if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
            {
576 577
                int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
                WARN("No implementation for %s.%d", name, ordinal );
578
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
579 580 581 582
            }
            else
            {
                IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
583
                WARN("No implementation for %s.%s", name, pe_name->Name );
Mike McCormack's avatar
Mike McCormack committed
584
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
585
            }
586
            WARN(" imported from %s, allocating stub %p\n",
587 588
                 debugstr_w(current_modref->ldr.FullDllName.Buffer),
                 (void *)thunk_list->u1.Function );
589 590 591
            import_list++;
            thunk_list++;
        }
592
        goto done;
593
    }
594 595 596 597 598 599 600

    while (import_list->u1.Ordinal)
    {
        if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
        {
            int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);

601
            thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
602
                                                                      ordinal - exports->Base, load_path );
603 604
            if (!thunk_list->u1.Function)
            {
605
                thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
606
                WARN("No implementation for %s.%d imported from %s, setting to %p\n",
607 608
                     name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
609
            }
610
            TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
611 612 613 614 615
        }
        else  /* import by name */
        {
            IMAGE_IMPORT_BY_NAME *pe_name;
            pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
616
            thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
617 618
                                                                    (const char*)pe_name->Name,
                                                                    pe_name->Hint, load_path );
619 620
            if (!thunk_list->u1.Function)
            {
Mike McCormack's avatar
Mike McCormack committed
621
                thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
622
                WARN("No implementation for %s.%s imported from %s, setting to %p\n",
623 624
                     name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
                     (void *)thunk_list->u1.Function );
625
            }
626 627
            TRACE_(imports)("--- %s %s.%d = %p\n",
                            pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
628 629 630 631
        }
        import_list++;
        thunk_list++;
    }
632 633 634

done:
    /* restore old protection of the import address table */
635
    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
636 637 638 639
    return wmImp;
}


640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
/***********************************************************************
 *           create_module_activation_context
 */
static NTSTATUS create_module_activation_context( LDR_MODULE *module )
{
    NTSTATUS status;
    LDR_RESOURCE_INFO info;
    const IMAGE_RESOURCE_DATA_ENTRY *entry;

    info.Type = RT_MANIFEST;
    info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
    info.Language = 0;
    if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
    {
        ACTCTXW ctx;
        ctx.cbSize   = sizeof(ctx);
        ctx.lpSource = NULL;
        ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
        ctx.hModule  = module->BaseAddress;
        ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
        status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
    }
    return status;
}


666
/****************************************************************
667
 *       fixup_imports
668 669 670 671
 *
 * Fixup all imports of a given module.
 * The loader_section must be locked while calling this function.
 */
672
static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
673 674
{
    int i, nb_imports;
Eric Pouech's avatar
Eric Pouech committed
675
    const IMAGE_IMPORT_DESCRIPTOR *imports;
676
    WINE_MODREF *prev;
677
    DWORD size;
678
    NTSTATUS status;
679
    ULONG_PTR cookie;
680

681 682 683
    if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
    wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;

684 685
    if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
                                                  IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
686
        return STATUS_SUCCESS;
687

688 689 690
    nb_imports = 0;
    while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;

691
    if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
692

693 694 695
    if (!create_module_activation_context( &wm->ldr ))
        RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );

696 697
    /* Allocate module dependency list */
    wm->nDeps = nb_imports;
698
    wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
699 700 701 702

    /* load the imported modules. They are automatically
     * added to the modref list of the process.
     */
703 704
    prev = current_modref;
    current_modref = wm;
705
    status = STATUS_SUCCESS;
706 707
    for (i = 0; i < nb_imports; i++)
    {
708 709
        if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
            status = STATUS_DLL_NOT_FOUND;
710
    }
711
    current_modref = prev;
712
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
713
    return status;
714
}
715

716

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
/*************************************************************************
 *		is_dll_native_subsystem
 *
 * Check if dll is a proper native driver.
 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
 * while being perfectly normal DLLs.  This heuristic should catch such breakages.
 */
static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
{
    static const WCHAR ntdllW[]    = {'n','t','d','l','l','.','d','l','l',0};
    static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
    const IMAGE_IMPORT_DESCRIPTOR *imports;
    DWORD i, size;
    WCHAR buffer[16];

    if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
    if (nt->OptionalHeader.SectionAlignment < getpagesize()) return TRUE;

    if ((imports = RtlImageDirectoryEntryToData( module, TRUE,
                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
    {
        for (i = 0; imports[i].Name; i++)
        {
            const char *name = get_rva( module, imports[i].Name );
            DWORD len = strlen(name);
            if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
            ascii_to_unicode( buffer, name, len + 1 );
            if (!strcmpiW( buffer, ntdllW ) || !strcmpiW( buffer, kernel32W ))
            {
                TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
                return FALSE;
            }
        }
    }
    return TRUE;
}


755
/*************************************************************************
756
 *		alloc_module
757 758
 *
 * Allocate a WINE_MODREF structure and add it to the process list
759
 * The loader_section must be locked while calling this function.
760
 */
761
static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
762 763
{
    WINE_MODREF *wm;
Eric Pouech's avatar
Eric Pouech committed
764 765
    const WCHAR *p;
    const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
766 767
    PLIST_ENTRY entry, mark;

768
    if (!(wm = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm) ))) return NULL;
769

770 771 772 773
    wm->nDeps    = 0;
    wm->deps     = NULL;

    wm->ldr.BaseAddress   = hModule;
774
    wm->ldr.EntryPoint    = NULL;
775
    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
776
    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
777
    wm->ldr.LoadCount     = 1;
778 779 780 781
    wm->ldr.TlsIndex      = -1;
    wm->ldr.SectionHandle = NULL;
    wm->ldr.CheckSum      = 0;
    wm->ldr.TimeDateStamp = 0;
782
    wm->ldr.ActivationContext = 0;
783 784 785 786 787 788

    RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
    if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
    else p = wm->ldr.FullDllName.Buffer;
    RtlInitUnicodeString( &wm->ldr.BaseDllName, p );

789
    if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
790
    {
791 792 793
        wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
        if (nt->OptionalHeader.AddressOfEntryPoint)
            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
794 795
    }

796 797
    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
                   &wm->ldr.InLoadOrderModuleList);
798

799 800 801 802 803 804
    /* insert module in MemoryList, sorted in increasing base addresses */
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
        if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
            break;
805
    }
806 807 808 809 810 811 812 813
    entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
    wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
    wm->ldr.InMemoryOrderModuleList.Flink = entry;
    entry->Blink = &wm->ldr.InMemoryOrderModuleList;

    /* wait until init is called for inserting into this list */
    wm->ldr.InInitializationOrderModuleList.Flink = NULL;
    wm->ldr.InInitializationOrderModuleList.Blink = NULL;
814 815 816

    if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
    {
817
        ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
818
        WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
819
        NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
820
    }
821 822 823 824
    return wm;
}


825 826 827 828 829 830 831
/*************************************************************************
 *              alloc_process_tls
 *
 * Allocate the process-wide structure for module TLS storage.
 */
static NTSTATUS alloc_process_tls(void)
{
832 833
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
Eric Pouech's avatar
Eric Pouech committed
834
    const IMAGE_TLS_DIRECTORY *dir;
835 836
    ULONG size, i;

837 838
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
839
    {
840 841
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
842 843 844
                                                  IMAGE_DIRECTORY_ENTRY_TLS, &size )))
            continue;
        size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
845
        if (!size && !dir->AddressOfCallBacks) continue;
846 847 848 849 850 851 852
        tls_total_size += size;
        tls_module_count++;
    }
    if (!tls_module_count) return STATUS_SUCCESS;

    TRACE( "count %u size %u\n", tls_module_count, tls_total_size );

853
    tls_dirs = RtlAllocateHeap( GetProcessHeap(), 0, tls_module_count * sizeof(*tls_dirs) );
854 855
    if (!tls_dirs) return STATUS_NO_MEMORY;

856
    for (i = 0, entry = mark->Flink; entry != mark; entry = entry->Flink)
857
    {
858 859
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
        if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
860 861 862
                                                  IMAGE_DIRECTORY_ENTRY_TLS, &size )))
            continue;
        tls_dirs[i] = dir;
863
        *(DWORD *)dir->AddressOfIndex = i;
864 865
        mod->TlsIndex = i;
        mod->LoadCount = -1;  /* can't unload it */
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
        i++;
    }
    return STATUS_SUCCESS;
}


/*************************************************************************
 *              alloc_thread_tls
 *
 * Allocate the per-thread structure for module TLS storage.
 */
static NTSTATUS alloc_thread_tls(void)
{
    void **pointers;
    char *data;
    UINT i;

    if (!tls_module_count) return STATUS_SUCCESS;

885
    if (!(pointers = RtlAllocateHeap( GetProcessHeap(), 0,
886 887 888
                                      tls_module_count * sizeof(*pointers) )))
        return STATUS_NO_MEMORY;

889
    if (!(data = RtlAllocateHeap( GetProcessHeap(), 0, tls_total_size )))
890
    {
891
        RtlFreeHeap( GetProcessHeap(), 0, pointers );
892 893 894 895 896 897 898 899
        return STATUS_NO_MEMORY;
    }

    for (i = 0; i < tls_module_count; i++)
    {
        const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
        ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;

900
        TRACE( "thread %04x idx %d: %d/%d bytes from %p to %p\n",
901 902 903 904 905 906 907 908 909
               GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
               (void *)dir->StartAddressOfRawData, data );

        pointers[i] = data;
        memcpy( data, (void *)dir->StartAddressOfRawData, size );
        data += size;
        memset( data, 0, dir->SizeOfZeroFill );
        data += dir->SizeOfZeroFill;
    }
910
    NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
911 912 913 914
    return STATUS_SUCCESS;
}


915 916 917 918 919 920 921 922 923 924 925 926
/*************************************************************************
 *              call_tls_callbacks
 */
static void call_tls_callbacks( HMODULE module, UINT reason )
{
    const IMAGE_TLS_DIRECTORY *dir;
    const PIMAGE_TLS_CALLBACK *callback;
    ULONG dirsize;

    dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
    if (!dir || !dir->AddressOfCallBacks) return;

927
    for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
928 929
    {
        if (TRACE_ON(relay))
930
            DPRINTF("%04x:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
931
                    GetCurrentThreadId(), *callback, module, reason_names[reason] );
932 933 934 935
        __TRY
        {
            (*callback)( module, reason, NULL );
        }
936
        __EXCEPT_ALL
937 938 939 940 941 942 943
        {
            if (TRACE_ON(relay))
                DPRINTF("%04x:exception in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
                        GetCurrentThreadId(), callback, module, reason_names[reason] );
            return;
        }
        __ENDTRY
944
        if (TRACE_ON(relay))
945
            DPRINTF("%04x:Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
946 947 948 949 950
                    GetCurrentThreadId(), *callback, module, reason_names[reason] );
    }
}


951 952 953
/*************************************************************************
 *              MODULE_InitDLL
 */
954
static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
955
{
956
    WCHAR mod_name[32];
957
    NTSTATUS status = STATUS_SUCCESS;
958 959
    DLLENTRYPROC entry = wm->ldr.EntryPoint;
    void *module = wm->ldr.BaseAddress;
960
    BOOL retv = TRUE;
961 962 963

    /* Skip calls for modules loaded with special load flags */

964
    if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
965
    if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
966
    if (!entry) return STATUS_SUCCESS;
967 968

    if (TRACE_ON(relay))
969
    {
970
        size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
971 972
        memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
        mod_name[len / sizeof(WCHAR)] = 0;
973
        DPRINTF("%04x:Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
974 975
                GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
                reason_names[reason], lpReserved );
976
    }
977 978
    else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
               reason_names[reason], lpReserved );
979

980 981 982 983 984 985
    __TRY
    {
        retv = call_dll_entry_point( entry, module, reason, lpReserved );
        if (!retv)
            status = STATUS_DLL_INIT_FAILED;
    }
986
    __EXCEPT_ALL
987 988 989 990 991 992 993
    {
        if (TRACE_ON(relay))
            DPRINTF("%04x:exception in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
                    GetCurrentThreadId(), entry, module, reason_names[reason], lpReserved );
        status = GetExceptionCode();
    }
    __ENDTRY
994 995

    /* The state of the module list may have changed due to the call
996
       to the dll. We cannot assume that this module has not been
997
       deleted.  */
998
    if (TRACE_ON(relay))
999
        DPRINTF("%04x:Ret  PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1000 1001
                GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
                reason_names[reason], lpReserved, retv );
1002
    else TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1003

1004
    return status;
1005 1006 1007 1008
}


/*************************************************************************
1009
 *		process_attach
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
 *
 * Send the process attach notification to all DLLs the given module
 * depends on (recursively). This is somewhat complicated due to the fact that
 *
 * - we have to respect the module dependencies, i.e. modules implicitly
 *   referenced by another module have to be initialized before the module
 *   itself can be initialized
 *
 * - the initialization routine of a DLL can itself call LoadLibrary,
 *   thereby introducing a whole new set of dependencies (even involving
 *   the 'old' modules) at any time during the whole process
 *
 * (Note that this routine can be recursively entered not only directly
 *  from itself, but also via LoadLibrary from one of the called initialization
 *  routines.)
 *
 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
 * the process *detach* notifications to be sent in the correct order.
 * This must not only take into account module dependencies, but also
 * 'hidden' dependencies created by modules calling LoadLibrary in their
 * attach notification routine.
 *
 * The strategy is rather simple: we move a WINE_MODREF to the head of the
 * list after the attach notification has returned.  This implies that the
 * detach notifications are called in the reverse of the sequence the attach
 * notifications *returned*.
1036 1037
 *
 * The loader_section must be locked while calling this function.
1038
 */
1039
static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1040
{
1041
    NTSTATUS status = STATUS_SUCCESS;
1042
    ULONG_PTR cookie;
1043 1044
    int i;

1045 1046
    if (process_detaching) return status;

1047
    /* prevent infinite recursion in case of cyclical dependencies */
1048 1049
    if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
         || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1050
        return status;
1051

1052
    TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1053 1054

    /* Tag current MODREF to prevent recursive loop */
1055
    wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1056
    if (lpReserved) wm->ldr.LoadCount = -1;  /* pin it if imported by the main exe */
1057
    if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1058 1059

    /* Recursively attach all DLLs this one depends on */
1060 1061 1062
    for ( i = 0; i < wm->nDeps; i++ )
    {
        if (!wm->deps[i]) continue;
1063
        if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1064
    }
1065 1066

    /* Call DLL entry point */
1067
    if (status == STATUS_SUCCESS)
1068
    {
1069 1070
        WINE_MODREF *prev = current_modref;
        current_modref = wm;
1071 1072
        status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
        if (status == STATUS_SUCCESS)
1073 1074
            wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
        else
1075
        {
1076
            MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1077 1078 1079 1080
            /* point to the name so LdrInitializeThunk can print it */
            last_failed_modref = wm;
            WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
        }
1081
        current_modref = prev;
1082 1083
    }

1084 1085 1086
    if (!wm->ldr.InInitializationOrderModuleList.Flink)
        InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
                       &wm->ldr.InInitializationOrderModuleList);
1087

1088
    if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1089
    /* Remove recursion flag */
1090
    wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1091

1092
    TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1093
    return status;
1094 1095
}

1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124

/**********************************************************************
 *	    attach_implicitly_loaded_dlls
 *
 * Attach to the (builtin) dlls that have been implicitly loaded because
 * of a dependency at the Unix level, but not imported at the Win32 level.
 */
static void attach_implicitly_loaded_dlls( LPVOID reserved )
{
    for (;;)
    {
        PLIST_ENTRY mark, entry;

        mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
        for (entry = mark->Flink; entry != mark; entry = entry->Flink)
        {
            LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);

            if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue;
            TRACE( "found implicitly loaded %s, attaching to it\n",
                   debugstr_w(mod->BaseDllName.Buffer));
            process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved );
            break;  /* restart the search from the start */
        }
        if (entry == mark) break;  /* nothing found */
    }
}


1125
/*************************************************************************
1126
 *		process_detach
1127 1128
 *
 * Send DLL process detach notifications.  See the comment about calling
1129
 * sequence at process_attach.  Unless the bForceDetach flag
1130 1131
 * is set, only DLLs with zero refcount are notified.
 */
1132
static void process_detach( BOOL bForceDetach, LPVOID lpReserved )
1133
{
1134 1135
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
1136 1137 1138

    RtlEnterCriticalSection( &loader_section );
    if (bForceDetach) process_detaching = 1;
1139
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1140 1141
    do
    {
1142
        for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1143
        {
1144 1145
            mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                    InInitializationOrderModuleList);
1146
            /* Check whether to detach this DLL */
1147
            if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1148
                continue;
1149
            if ( mod->LoadCount && !bForceDetach )
1150 1151 1152
                continue;

            /* Call detach notification */
1153 1154 1155
            mod->Flags &= ~LDR_PROCESS_ATTACHED;
            MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
                            DLL_PROCESS_DETACH, lpReserved );
1156 1157 1158 1159 1160

            /* Restart at head of WINE_MODREF list, as entries might have
               been added and/or removed while performing the call ... */
            break;
        }
1161
    } while (entry != mark);
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172

    RtlLeaveCriticalSection( &loader_section );
}

/*************************************************************************
 *		MODULE_DllThreadAttach
 *
 * Send DLL thread attach notifications. These are sent in the
 * reverse sequence of process detach notification.
 *
 */
1173
NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
1174
{
1175 1176 1177
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
    NTSTATUS    status;
1178 1179

    /* don't do any attach calls if process is exiting */
1180
    if (process_detaching) return STATUS_SUCCESS;
1181 1182 1183 1184
    /* FIXME: there is still a race here */

    RtlEnterCriticalSection( &loader_section );

1185
    if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
1186

1187 1188
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1189
    {
1190 1191 1192
        mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                InInitializationOrderModuleList);
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1193
            continue;
1194
        if ( mod->Flags & LDR_NO_DLL_CALLS )
1195 1196
            continue;

1197 1198
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
                        DLL_THREAD_ATTACH, lpReserved );
1199 1200
    }

1201
done:
1202
    RtlLeaveCriticalSection( &loader_section );
1203
    return status;
1204 1205
}

1206 1207 1208 1209 1210
/******************************************************************
 *		LdrDisableThreadCalloutsForDll (NTDLL.@)
 *
 */
NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1211
{
1212 1213 1214 1215 1216
    WINE_MODREF *wm;
    NTSTATUS    ret = STATUS_SUCCESS;

    RtlEnterCriticalSection( &loader_section );

1217
    wm = get_modref( hModule );
1218
    if (!wm || wm->ldr.TlsIndex != -1)
1219
        ret = STATUS_DLL_NOT_FOUND;
1220
    else
1221
        wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1222 1223 1224 1225

    RtlLeaveCriticalSection( &loader_section );

    return ret;
1226
}
1227

1228 1229 1230 1231 1232
/******************************************************************
 *              LdrFindEntryForAddress (NTDLL.@)
 *
 * The loader_section must be locked while calling this function
 */
1233
NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
1234
{
1235 1236
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;
1237

1238 1239
    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1240
    {
1241
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
1242
        if (mod->BaseAddress <= addr &&
Eric Pouech's avatar
Eric Pouech committed
1243
            (const char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
1244
        {
1245
            *pmod = mod;
1246 1247
            return STATUS_SUCCESS;
        }
1248
        if (mod->BaseAddress > addr) break;
1249 1250 1251 1252
    }
    return STATUS_NO_MORE_ENTRIES;
}

1253 1254 1255 1256 1257 1258 1259 1260 1261
/******************************************************************
 *		LdrLockLoaderLock  (NTDLL.@)
 *
 * Note: flags are not implemented.
 * Flag 0x01 is used to raise exceptions on errors.
 * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
 */
NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
{
1262
    if (flags) FIXME( "flags %x not supported\n", flags );
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285

    if (result) *result = 1;
    if (!magic) return STATUS_INVALID_PARAMETER_3;
    RtlEnterCriticalSection( &loader_section );
    *magic = GetCurrentThreadId();
    return STATUS_SUCCESS;
}


/******************************************************************
 *		LdrUnlockLoaderUnlock  (NTDLL.@)
 */
NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
{
    if (magic)
    {
        if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
        RtlLeaveCriticalSection( &loader_section );
    }
    return STATUS_SUCCESS;
}


1286 1287
/******************************************************************
 *		LdrGetProcedureAddress  (NTDLL.@)
1288
 */
1289 1290
NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
                                       ULONG ord, PVOID *address)
1291
{
1292 1293 1294
    IMAGE_EXPORT_DIRECTORY *exports;
    DWORD exp_size;
    NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1295

1296
    RtlEnterCriticalSection( &loader_section );
1297

1298 1299 1300 1301
    /* check if the module itself is invalid to return the proper error */
    if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
    else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
                                                      IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1302
    {
1303 1304 1305
        LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
        void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
                          : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
1306 1307 1308 1309 1310 1311
        if (proc)
        {
            *address = proc;
            ret = STATUS_SUCCESS;
        }
    }
1312

1313 1314
    RtlLeaveCriticalSection( &loader_section );
    return ret;
1315
}
1316 1317


1318 1319 1320 1321 1322
/***********************************************************************
 *           is_fake_dll
 *
 * Check if a loaded native dll is a Wine fake dll.
 */
1323
static BOOL is_fake_dll( HANDLE handle )
1324 1325
{
    static const char fakedll_signature[] = "Wine placeholder DLL";
1326 1327 1328 1329
    char buffer[sizeof(IMAGE_DOS_HEADER) + sizeof(fakedll_signature)];
    const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)buffer;
    IO_STATUS_BLOCK io;
    LARGE_INTEGER offset;
1330

1331 1332 1333 1334
    offset.QuadPart = 0;
    if (NtReadFile( handle, 0, NULL, 0, &io, buffer, sizeof(buffer), &offset, NULL )) return FALSE;
    if (io.Information < sizeof(buffer)) return FALSE;
    if (dos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
1335 1336 1337 1338 1339 1340
    if (dos->e_lfanew >= sizeof(*dos) + sizeof(fakedll_signature) &&
        !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )) return TRUE;
    return FALSE;
}


1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
/***********************************************************************
 *           get_builtin_fullname
 *
 * Build the full pathname for a builtin dll.
 */
static WCHAR *get_builtin_fullname( const WCHAR *path, const char *filename )
{
    static const WCHAR soW[] = {'.','s','o',0};
    WCHAR *p, *fullname;
    size_t i, len = strlen(filename);

    /* check if path can correspond to the dll we have */
    if (path && (p = strrchrW( path, '\\' )))
    {
        p++;
        for (i = 0; i < len; i++)
            if (tolowerW(p[i]) != tolowerW( (WCHAR)filename[i]) ) break;
        if (i == len && (!p[len] || !strcmpiW( p + len, soW )))
        {
            /* the filename matches, use path as the full path */
            len += p - path;
            if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
            {
                memcpy( fullname, path, len * sizeof(WCHAR) );
                fullname[len] = 0;
            }
            return fullname;
        }
    }

    if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0,
                                     system_dir.MaximumLength + (len + 1) * sizeof(WCHAR) )))
    {
        memcpy( fullname, system_dir.Buffer, system_dir.Length );
        p = fullname + system_dir.Length / sizeof(WCHAR);
        if (p > fullname && p[-1] != '\\') *p++ = '\\';
        ascii_to_unicode( p, filename, len + 1 );
    }
    return fullname;
}


1383 1384 1385 1386 1387 1388 1389
/***********************************************************************
 *           load_builtin_callback
 *
 * Load a library in memory; callback function for wine_dll_register
 */
static void load_builtin_callback( void *module, const char *filename )
{
1390
    static const WCHAR emptyW[1];
1391 1392
    IMAGE_NT_HEADERS *nt;
    WINE_MODREF *wm;
1393
    WCHAR *fullname;
1394
    const WCHAR *load_path;
1395 1396 1397 1398 1399 1400 1401 1402 1403

    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" );
1404
        builtin_load_info->status = STATUS_INVALID_IMAGE_FORMAT;
1405 1406
        return;
    }
1407 1408

    virtual_create_builtin_view( module );
1409

1410 1411
    /* create the MODREF */

1412
    if (!(fullname = get_builtin_fullname( builtin_load_info->filename, filename )))
1413 1414
    {
        ERR( "can't load %s\n", filename );
1415
        builtin_load_info->status = STATUS_NO_MEMORY;
1416 1417 1418
        return;
    }

1419 1420
    wm = alloc_module( module, fullname );
    RtlFreeHeap( GetProcessHeap(), 0, fullname );
1421 1422 1423
    if (!wm)
    {
        ERR( "can't load %s\n", filename );
1424
        builtin_load_info->status = STATUS_NO_MEMORY;
1425 1426 1427 1428
        return;
    }
    wm->ldr.Flags |= LDR_WINE_INTERNAL;

1429 1430
    if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
        !NtCurrentTeb()->Peb->ImageBaseAddress)  /* if we already have an executable, ignore this one */
1431
    {
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
        NtCurrentTeb()->Peb->ImageBaseAddress = module;
    }
    else
    {
        /* fixup imports */

        load_path = builtin_load_info->load_path;
        if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
        if (!load_path) load_path = emptyW;
        if (fixup_imports( wm, load_path ) != 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 */
            builtin_load_info->status = STATUS_DLL_NOT_FOUND;
            return;
        }
1450
    }
1451

1452
    builtin_load_info->wm = wm;
1453 1454 1455 1456 1457 1458 1459
    TRACE( "loaded %s %p %p\n", filename, wm, module );

    /* send the DLL load event */

    SERVER_START_REQ( load_dll )
    {
        req->handle     = 0;
1460
        req->base       = wine_server_client_ptr( module );
1461 1462 1463
        req->size       = nt->OptionalHeader.SizeOfImage;
        req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
        req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1464
        req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1465
        wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
        wine_server_call( req );
    }
    SERVER_END_REQ;

    /* setup relay debugging entry points */
    if (TRACE_ON(relay)) RELAY_SetupDLL( module );
}


/******************************************************************************
 *	load_native_dll  (internal)
 */
1478 1479
static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
                                 DWORD flags, WINE_MODREF** pwm )
1480 1481
{
    void *module;
1482
    HANDLE mapping;
1483 1484
    LARGE_INTEGER size;
    IMAGE_NT_HEADERS *nt;
1485
    SIZE_T len = 0;
1486 1487 1488
    WINE_MODREF *wm;
    NTSTATUS status;

1489
    TRACE("Trying native dll %s\n", debugstr_w(name));
1490 1491 1492

    size.QuadPart = 0;
    status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1493
                              NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
1494
    if (status != STATUS_SUCCESS) return status;
1495 1496

    module = NULL;
1497
    status = NtMapViewOfSection( mapping, NtCurrentProcess(),
1498 1499
                                 &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
    NtClose( mapping );
1500
    if (status < 0) return status;
1501 1502 1503

    /* create the MODREF */

1504
    if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;
1505 1506 1507 1508 1509

    /* fixup imports */

    if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
    {
1510
        if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
        {
            /* 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.
             */
1523
            return status;
1524 1525 1526 1527 1528 1529 1530 1531 1532
        }
    }

    /* send DLL load event */

    nt = RtlImageNtHeader( module );

    SERVER_START_REQ( load_dll )
    {
1533
        req->handle     = wine_server_obj_handle( file );
1534
        req->base       = wine_server_client_ptr( module );
1535 1536 1537
        req->size       = nt->OptionalHeader.SizeOfImage;
        req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
        req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1538
        req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1539
        wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1540 1541 1542 1543
        wine_server_call( req );
    }
    SERVER_END_REQ;

1544
    if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( module );
1545

1546
    TRACE_(loaddll)( "Loaded %s at %p: native\n", debugstr_w(wm->ldr.FullDllName.Buffer), module );
1547

1548
    wm->ldr.LoadCount = 1;
1549
    *pwm = wm;
1550
    return STATUS_SUCCESS;
1551 1552 1553
}


1554 1555 1556
/***********************************************************************
 *           load_builtin_dll
 */
1557 1558
static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file,
                                  DWORD flags, WINE_MODREF** pwm )
1559
{
1560 1561 1562
    char error[256], dllname[MAX_PATH];
    const WCHAR *name, *p;
    DWORD len, i;
1563
    void *handle = NULL;
1564
    struct builtin_load_info info, *prev_info;
1565 1566 1567

    /* Fix the name in case we have a full path and extension */
    name = path;
1568 1569
    if ((p = strrchrW( name, '\\' ))) name = p + 1;
    if ((p = strrchrW( name, '/' ))) name = p + 1;
1570

1571
    /* load_library will modify info.status. Note also that load_library can be
1572
     * called several times, if the .so file we're loading has dependencies.
1573
     * info.status will gather all the errors we may get while loading all these
1574 1575
     * libraries
     */
1576
    info.load_path = load_path;
1577
    info.filename  = NULL;
1578 1579
    info.status    = STATUS_SUCCESS;
    info.wm        = NULL;
1580 1581 1582 1583 1584 1585

    if (file)  /* we have a real file, try to load it */
    {
        UNICODE_STRING nt_name;
        ANSI_STRING unix_name;

1586 1587
        TRACE("Trying built-in %s\n", debugstr_w(path));

1588 1589 1590
        if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL ))
            return STATUS_DLL_NOT_FOUND;

1591
        if (wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE ))
1592
        {
1593 1594
            RtlFreeUnicodeString( &nt_name );
            return STATUS_DLL_NOT_FOUND;
1595
        }
1596 1597 1598 1599 1600
        prev_info = builtin_load_info;
        info.filename = nt_name.Buffer + 4;  /* skip \??\ */
        builtin_load_info = &info;
        handle = wine_dlopen( unix_name.Buffer, RTLD_NOW, error, sizeof(error) );
        builtin_load_info = prev_info;
1601
        RtlFreeUnicodeString( &nt_name );
1602 1603 1604 1605 1606 1607
        RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
        if (!handle)
        {
            WARN( "failed to load .so lib for builtin %s: %s\n", debugstr_w(path), error );
            return STATUS_INVALID_IMAGE_FORMAT;
        }
1608 1609 1610
    }
    else
    {
1611 1612
        int file_exists;

1613 1614
        TRACE("Trying built-in %s\n", debugstr_w(name));

1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
        /* we don't want to depend on the current codepage here */
        len = strlenW( name ) + 1;
        if (len >= sizeof(dllname)) return STATUS_NAME_TOO_LONG;
        for (i = 0; i < len; i++)
        {
            if (name[i] > 127) return STATUS_DLL_NOT_FOUND;
            dllname[i] = (char)name[i];
            if (dllname[i] >= 'A' && dllname[i] <= 'Z') dllname[i] += 'a' - 'A';
        }

        prev_info = builtin_load_info;
        builtin_load_info = &info;
        handle = wine_dll_load( dllname, error, sizeof(error), &file_exists );
        builtin_load_info = prev_info;
1629
        if (!handle)
1630
        {
1631 1632 1633 1634 1635 1636 1637 1638 1639
            if (!file_exists)
            {
                /* The file does not exist -> WARN() */
                WARN("cannot open .so lib for builtin %s: %s\n", debugstr_w(name), error);
                return STATUS_DLL_NOT_FOUND;
            }
            /* ERR() for all other errors (missing functions, ...) */
            ERR("failed to load .so lib for builtin %s: %s\n", debugstr_w(name), error );
            return STATUS_PROCEDURE_NOT_FOUND;
1640 1641
        }
    }
1642

1643 1644 1645 1646 1647
    if (info.status != STATUS_SUCCESS)
    {
        wine_dll_unload( handle );
        return info.status;
    }
1648

1649 1650
    if (!info.wm)
    {
1651
        PLIST_ENTRY mark, entry;
1652

1653 1654
        /* The constructor wasn't called, this means the .so is already
         * loaded under a different name. Try to find the wm for it. */
1655

1656 1657
        mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
        for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1658
        {
1659 1660 1661 1662
            LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
            if (mod->Flags & LDR_WINE_INTERNAL && mod->SectionHandle == handle)
            {
                info.wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
1663 1664
                TRACE( "Found %s at %p for builtin %s\n",
                       debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress, debugstr_w(path) );
1665 1666
                break;
            }
1667
        }
1668
        wine_dll_unload( handle );  /* release the libdl refcount */
1669
        if (!info.wm) return STATUS_INVALID_IMAGE_FORMAT;
1670
        if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
1671 1672 1673
    }
    else
    {
1674
        TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
1675
        info.wm->ldr.LoadCount = 1;
1676
        info.wm->ldr.SectionHandle = handle;
1677
    }
1678

1679
    *pwm = info.wm;
1680 1681 1682 1683
    return STATUS_SUCCESS;
}


1684 1685 1686 1687 1688 1689 1690 1691
/***********************************************************************
 *	find_actctx_dll
 *
 * Find the full path (if any) of the dll from the activation context.
 */
static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
{
    static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
1692
    static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724

    ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
    ACTCTX_SECTION_KEYED_DATA data;
    UNICODE_STRING nameW;
    NTSTATUS status;
    SIZE_T needed, size = 1024;
    WCHAR *p;

    RtlInitUnicodeString( &nameW, libname );
    data.cbSize = sizeof(data);
    status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
                                                    ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
                                                    &nameW, &data );
    if (status != STATUS_SUCCESS) return status;

    for (;;)
    {
        if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
        {
            status = STATUS_NO_MEMORY;
            goto done;
        }
        status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
                                                       AssemblyDetailedInformationInActivationContext,
                                                       info, size, &needed );
        if (status == STATUS_SUCCESS) break;
        if (status != STATUS_BUFFER_TOO_SMALL) goto done;
        RtlFreeHeap( GetProcessHeap(), 0, info );
        size = needed;
        /* restart with larger buffer */
    }

1725 1726 1727 1728 1729 1730
    if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
    {
        status = STATUS_SXS_KEY_NOT_FOUND;
        goto done;
    }

1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
    if ((p = strrchrW( info->lpAssemblyManifestPath, '\\' )))
    {
        DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);

        p++;
        if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
        {
            /* manifest name does not match directory name, so it's not a global
             * windows/winsxs manifest; use the manifest directory name instead */
            dirlen = p - info->lpAssemblyManifestPath;
            needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
            if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
            {
                status = STATUS_NO_MEMORY;
                goto done;
            }
            memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
            p += dirlen;
            strcpyW( p, libname );
            goto done;
        }
    }

1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776
    needed = (windows_dir.Length + sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength +
              nameW.Length + 2*sizeof(WCHAR));

    if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
    {
        status = STATUS_NO_MEMORY;
        goto done;
    }
    memcpy( p, windows_dir.Buffer, windows_dir.Length );
    p += windows_dir.Length / sizeof(WCHAR);
    memcpy( p, winsxsW, sizeof(winsxsW) );
    p += sizeof(winsxsW) / sizeof(WCHAR);
    memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
    p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
    *p++ = '\\';
    strcpyW( p, libname );
done:
    RtlFreeHeap( GetProcessHeap(), 0, info );
    RtlReleaseActivationContext( data.hActCtx );
    return status;
}


1777 1778 1779 1780 1781 1782 1783 1784
/***********************************************************************
 *	find_dll_file
 *
 * Find the file (or already loaded module) for a given dll name.
 */
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
                               WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
{
1785 1786 1787
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK io;
    UNICODE_STRING nt_name;
1788
    WCHAR *file_part, *ext, *dllname;
1789 1790
    ULONG len;

1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
    /* first append .dll if needed */

    dllname = NULL;
    if (!(ext = strrchrW( libname, '.')) || strchrW( ext, '/' ) || strchrW( ext, '\\'))
    {
        if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
                                         (strlenW(libname) * sizeof(WCHAR)) + sizeof(dllW) )))
            return STATUS_NO_MEMORY;
        strcpyW( dllname, libname );
        strcatW( dllname, dllW );
        libname = dllname;
    }

1804
    nt_name.Buffer = NULL;
1805 1806 1807

    if (!contains_path( libname ))
    {
1808
        NTSTATUS status;
1809
        WCHAR *fullname = NULL;
1810

1811
        if ((*pwm = find_basename_module( libname )) != NULL) goto found;
1812 1813 1814 1815

        status = find_actctx_dll( libname, &fullname );
        if (status == STATUS_SUCCESS)
        {
1816
            TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
1817 1818 1819 1820 1821 1822 1823 1824
            RtlFreeHeap( GetProcessHeap(), 0, dllname );
            libname = dllname = fullname;
        }
        else if (status != STATUS_SXS_KEY_NOT_FOUND)
        {
            RtlFreeHeap( GetProcessHeap(), 0, dllname );
            return status;
        }
1825 1826
    }

1827 1828 1829
    if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
    {
        /* we need to search for it */
1830
        len = RtlDosSearchPath_U( load_path, libname, NULL, *size, filename, &file_part );
1831 1832
        if (len)
        {
1833
            if (len >= *size) goto overflow;
1834
            if ((*pwm = find_fullname_module( filename )) || !handle) goto found;
1835

1836
            if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, NULL, NULL ))
1837 1838
            {
                RtlFreeHeap( GetProcessHeap(), 0, dllname );
1839
                return STATUS_NO_MEMORY;
1840
            }
1841 1842 1843 1844 1845 1846
            attr.Length = sizeof(attr);
            attr.RootDirectory = 0;
            attr.Attributes = OBJ_CASE_INSENSITIVE;
            attr.ObjectName = &nt_name;
            attr.SecurityDescriptor = NULL;
            attr.SecurityQualityOfService = NULL;
1847
            if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, 0 )) *handle = 0;
1848
            goto found;
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
        }

        /* not found */

        if (!contains_path( libname ))
        {
            /* if libname doesn't contain a path at all, we simply return the name as is,
             * to be loaded as builtin */
            len = strlenW(libname) * sizeof(WCHAR);
            if (len >= *size) goto overflow;
            strcpyW( filename, libname );
1860
            goto found;
1861 1862 1863 1864 1865
        }
    }

    /* absolute path name, or relative path name but not found above */

1866
    if (!RtlDosPathNameToNtPathName_U( libname, &nt_name, &file_part, NULL ))
1867 1868
    {
        RtlFreeHeap( GetProcessHeap(), 0, dllname );
1869
        return STATUS_NO_MEMORY;
1870
    }
1871
    len = nt_name.Length - 4*sizeof(WCHAR);  /* for \??\ prefix */
1872
    if (len >= *size) goto overflow;
1873
    memcpy( filename, nt_name.Buffer + 4, len + sizeof(WCHAR) );
1874
    if (!(*pwm = find_fullname_module( filename )) && handle)
1875 1876 1877 1878 1879 1880 1881
    {
        attr.Length = sizeof(attr);
        attr.RootDirectory = 0;
        attr.Attributes = OBJ_CASE_INSENSITIVE;
        attr.ObjectName = &nt_name;
        attr.SecurityDescriptor = NULL;
        attr.SecurityQualityOfService = NULL;
1882
        if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, 0 )) *handle = 0;
1883
    }
1884
found:
1885
    RtlFreeUnicodeString( &nt_name );
1886
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
1887 1888 1889
    return STATUS_SUCCESS;

overflow:
1890
    RtlFreeUnicodeString( &nt_name );
1891
    RtlFreeHeap( GetProcessHeap(), 0, dllname );
1892 1893 1894 1895 1896
    *size = len + sizeof(WCHAR);
    return STATUS_BUFFER_TOO_SMALL;
}


1897
/***********************************************************************
1898
 *	load_dll  (internal)
1899 1900
 *
 * Load a PE style module according to the load order.
1901
 * The loader_section must be locked while calling this function.
1902
 */
1903
static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
1904
{
1905
    enum loadorder loadorder;
1906 1907 1908
    WCHAR buffer[32];
    WCHAR *filename;
    ULONG size;
1909
    WINE_MODREF *main_exe;
1910
    HANDLE handle = 0;
1911
    NTSTATUS nts;
1912

1913
    TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
1914

1915
    *pwm = NULL;
1916 1917 1918
    filename = buffer;
    size = sizeof(buffer);
    for (;;)
1919
    {
1920 1921 1922 1923 1924 1925
        nts = find_dll_file( load_path, libname, filename, &size, pwm, &handle );
        if (nts == STATUS_SUCCESS) break;
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        if (nts != STATUS_BUFFER_TOO_SMALL) return nts;
        /* grow the buffer and retry */
        if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
1926
    }
1927 1928

    if (*pwm)  /* found already loaded module */
1929
    {
1930 1931
        if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;

1932 1933
        if (!(flags & DONT_RESOLVE_DLL_REFERENCES)) fixup_imports( *pwm, load_path );

1934
        TRACE("Found %s for %s at %p, count=%d\n",
1935 1936 1937 1938
              debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
              (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        return STATUS_SUCCESS;
1939 1940
    }

1941
    main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
1942
    loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename );
1943

1944 1945 1946 1947 1948 1949 1950
    if (handle && is_fake_dll( handle ))
    {
        TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) );
        NtClose( handle );
        handle = 0;
    }

1951
    switch(loadorder)
1952
    {
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
    case LO_INVALID:
        nts = STATUS_NO_MEMORY;
        break;
    case LO_DISABLED:
        nts = STATUS_DLL_NOT_FOUND;
        break;
    case LO_NATIVE:
    case LO_NATIVE_BUILTIN:
        if (!handle) nts = STATUS_DLL_NOT_FOUND;
        else
1963
        {
1964
            nts = load_native_dll( load_path, filename, handle, flags, pwm );
1965 1966 1967
            if (nts == STATUS_INVALID_FILE_FOR_SECTION)
                /* not in PE format, maybe it's a builtin */
                nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
1968
        }
1969
        if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN)
1970 1971
            nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
        break;
1972 1973 1974
    case LO_BUILTIN:
    case LO_BUILTIN_NATIVE:
    case LO_DEFAULT:  /* default is builtin,native */
1975 1976 1977
        nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
        if (!handle) break;  /* nothing else we can try */
        /* file is not a builtin library, try without using the specified file */
1978 1979 1980
        if (nts != STATUS_SUCCESS)
            nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
        if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
1981
            (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
1982 1983 1984 1985 1986 1987
        {
            /* stub-only dll, try native */
            TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_w(filename) );
            LdrUnloadDll( (*pwm)->ldr.BaseAddress );
            nts = STATUS_DLL_NOT_FOUND;
        }
1988
        if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN)
1989 1990 1991
            nts = load_native_dll( load_path, filename, handle, flags, pwm );
        break;
    }
1992

1993 1994 1995 1996 1997 1998 1999 2000 2001
    if (nts == STATUS_SUCCESS)
    {
        /* Initialize DLL just loaded */
        TRACE("Loaded module %s (%s) at %p\n", debugstr_w(filename),
              ((*pwm)->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native",
              (*pwm)->ldr.BaseAddress);
        if (handle) NtClose( handle );
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        return nts;
2002 2003
    }

2004
    WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
2005
    if (handle) NtClose( handle );
2006
    if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
2007
    return nts;
2008 2009 2010 2011 2012
}

/******************************************************************
 *		LdrLoadDll (NTDLL.@)
 */
2013 2014
NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags,
                           const UNICODE_STRING *libname, HMODULE* hModule)
2015 2016
{
    WINE_MODREF *wm;
2017
    NTSTATUS nts;
2018 2019 2020

    RtlEnterCriticalSection( &loader_section );

2021 2022
    if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
    nts = load_dll( path_name, libname->Buffer, flags, &wm );
2023 2024

    if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
2025
    {
2026
        nts = process_attach( wm, NULL );
2027
        if (nts != STATUS_SUCCESS)
2028
        {
2029
            LdrUnloadDll(wm->ldr.BaseAddress);
2030 2031 2032
            wm = NULL;
        }
    }
2033
    *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
2034

2035
    RtlLeaveCriticalSection( &loader_section );
2036 2037 2038
    return nts;
}

2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062

/******************************************************************
 *		LdrGetDllHandle (NTDLL.@)
 */
NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
{
    NTSTATUS status;
    WCHAR buffer[128];
    WCHAR *filename;
    ULONG size;
    WINE_MODREF *wm;

    RtlEnterCriticalSection( &loader_section );

    if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;

    filename = buffer;
    size = sizeof(buffer);
    for (;;)
    {
        status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, NULL );
        if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
        if (status != STATUS_BUFFER_TOO_SMALL) break;
        /* grow the buffer and retry */
2063 2064 2065 2066 2067
        if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size )))
        {
            status = STATUS_NO_MEMORY;
            break;
        }
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081
    }

    if (status == STATUS_SUCCESS)
    {
        if (wm) *base = wm->ldr.BaseAddress;
        else status = STATUS_DLL_NOT_FOUND;
    }

    RtlLeaveCriticalSection( &loader_section );
    TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
    return status;
}


2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105
/******************************************************************
 *		LdrAddRefDll (NTDLL.@)
 */
NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
{
    NTSTATUS ret = STATUS_SUCCESS;
    WINE_MODREF *wm;

    if (flags) FIXME( "%p flags %x not implemented\n", module, flags );

    RtlEnterCriticalSection( &loader_section );

    if ((wm = get_modref( module )))
    {
        if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
        TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
    }
    else ret = STATUS_INVALID_PARAMETER;

    RtlLeaveCriticalSection( &loader_section );
    return ret;
}


2106 2107 2108 2109 2110 2111
/***********************************************************************
 *           LdrProcessRelocationBlock  (NTDLL.@)
 *
 * Apply relocations to a given page of a mapped PE image.
 */
IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
2112
                                                          USHORT *relocs, INT_PTR delta )
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130
{
    while (count--)
    {
        USHORT offset = *relocs & 0xfff;
        int type = *relocs >> 12;
        switch(type)
        {
        case IMAGE_REL_BASED_ABSOLUTE:
            break;
        case IMAGE_REL_BASED_HIGH:
            *(short *)((char *)page + offset) += HIWORD(delta);
            break;
        case IMAGE_REL_BASED_LOW:
            *(short *)((char *)page + offset) += LOWORD(delta);
            break;
        case IMAGE_REL_BASED_HIGHLOW:
            *(int *)((char *)page + offset) += delta;
            break;
2131
#ifdef __x86_64__
2132 2133 2134 2135
        case IMAGE_REL_BASED_DIR64:
            *(INT_PTR *)((char *)page + offset) += delta;
            break;
#endif
2136 2137 2138 2139 2140 2141 2142 2143 2144 2145
        default:
            FIXME("Unknown/unsupported fixup type %x.\n", type);
            return NULL;
        }
        relocs++;
    }
    return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
}


2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
/******************************************************************
 *		LdrQueryProcessModuleInformation
 *
 */
NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi, 
                                                 ULONG buf_size, ULONG* req_size)
{
    SYSTEM_MODULE*      sm = &smi->Modules[0];
    ULONG               size = sizeof(ULONG);
    NTSTATUS            nts = STATUS_SUCCESS;
    ANSI_STRING         str;
    char*               ptr;
2158 2159
    PLIST_ENTRY         mark, entry;
    PLDR_MODULE         mod;
2160
    WORD id = 0;
2161 2162 2163 2164

    smi->ModulesCount = 0;

    RtlEnterCriticalSection( &loader_section );
2165 2166
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2167
    {
2168
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
2169 2170 2171 2172 2173
        size += sizeof(*sm);
        if (size <= buf_size)
        {
            sm->Reserved1 = 0; /* FIXME */
            sm->Reserved2 = 0; /* FIXME */
2174 2175 2176
            sm->ImageBaseAddress = mod->BaseAddress;
            sm->ImageSize = mod->SizeOfImage;
            sm->Flags = mod->Flags;
2177
            sm->Id = id++;
2178 2179 2180 2181
            sm->Rank = 0; /* FIXME */
            sm->Unknown = 0; /* FIXME */
            str.Length = 0;
            str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
Mike McCormack's avatar
Mike McCormack committed
2182
            str.Buffer = (char*)sm->Name;
2183
            RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
Mike McCormack's avatar
Mike McCormack committed
2184 2185
            ptr = strrchr(str.Buffer, '\\');
            sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198

            smi->ModulesCount++;
            sm++;
        }
        else nts = STATUS_INFO_LENGTH_MISMATCH;
    }
    RtlLeaveCriticalSection( &loader_section );

    if (req_size) *req_size = size;

    return nts;
}

2199

2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299
static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, ULONG *value )
{
    NTSTATUS status;
    UNICODE_STRING str;
    ULONG size;
    WCHAR buffer[64];
    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;

    RtlInitUnicodeString( &str, name );

    size = sizeof(buffer) - sizeof(WCHAR);
    if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
        return status;

    if (info->Type != REG_DWORD)
    {
        buffer[size / sizeof(WCHAR)] = 0;
        *value = strtoulW( (WCHAR *)info->Data, 0, 16 );
    }
    else memcpy( value, info->Data, sizeof(*value) );
    return status;
}

static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
                                     void *data, ULONG in_size, ULONG *out_size )
{
    NTSTATUS status;
    UNICODE_STRING str;
    ULONG size;
    char *buffer;
    KEY_VALUE_PARTIAL_INFORMATION *info;
    static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );

    RtlInitUnicodeString( &str, name );

    size = info_size + in_size;
    if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
    info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
    status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
    if (!status || status == STATUS_BUFFER_OVERFLOW)
    {
        if (out_size) *out_size = info->DataLength;
        if (data && !status) memcpy( data, info->Data, info->DataLength );
    }
    RtlFreeHeap( GetProcessHeap(), 0, buffer );
    return status;
}


/******************************************************************
 *		LdrQueryImageFileExecutionOptions  (NTDLL.@)
 */
NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
                                                   void *data, ULONG in_size, ULONG *out_size )
{
    static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
                                     'S','o','f','t','w','a','r','e','\\',
                                     'M','i','c','r','o','s','o','f','t','\\',
                                     'W','i','n','d','o','w','s',' ','N','T','\\',
                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                     'I','m','a','g','e',' ','F','i','l','e',' ',
                                     'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
    WCHAR path[MAX_PATH + sizeof(optionsW)/sizeof(WCHAR)];
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING name_str;
    HANDLE hkey;
    NTSTATUS status;
    ULONG len;
    WCHAR *p;

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.ObjectName = &name_str;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    if ((p = memrchrW( key->Buffer, '\\', key->Length / sizeof(WCHAR) ))) p++;
    else p = key->Buffer;
    len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
    name_str.Buffer = path;
    name_str.Length = sizeof(optionsW) + len;
    name_str.MaximumLength = name_str.Length;
    memcpy( path, optionsW, sizeof(optionsW) );
    memcpy( path + sizeof(optionsW)/sizeof(WCHAR), p, len );
    if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;

    if (type == REG_DWORD)
    {
        if (out_size) *out_size = sizeof(ULONG);
        if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
        else status = STATUS_BUFFER_OVERFLOW;
    }
    else status = query_string_option( hkey, value, type, data, in_size, out_size );

    NtClose( hkey );
    return status;
}


2300 2301 2302 2303 2304 2305 2306 2307 2308
/******************************************************************
 *		RtlDllShutdownInProgress  (NTDLL.@)
 */
BOOLEAN WINAPI RtlDllShutdownInProgress(void)
{
    return process_detaching;
}


2309 2310 2311 2312
/******************************************************************
 *		LdrShutdownProcess (NTDLL.@)
 *
 */
2313
void WINAPI LdrShutdownProcess(void)
2314 2315
{
    TRACE("()\n");
2316
    process_detach( TRUE, (LPVOID)1 );
2317 2318 2319 2320 2321 2322
}

/******************************************************************
 *		LdrShutdownThread (NTDLL.@)
 *
 */
2323
void WINAPI LdrShutdownThread(void)
2324
{
2325 2326 2327
    PLIST_ENTRY mark, entry;
    PLDR_MODULE mod;

2328 2329 2330
    TRACE("()\n");

    /* don't do any detach calls if process is exiting */
2331
    if (process_detaching) return;
2332 2333 2334 2335
    /* FIXME: there is still a race here */

    RtlEnterCriticalSection( &loader_section );

2336 2337
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = entry->Blink)
2338
    {
2339 2340 2341
        mod = CONTAINING_RECORD(entry, LDR_MODULE, 
                                InInitializationOrderModuleList);
        if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
2342
            continue;
2343
        if ( mod->Flags & LDR_NO_DLL_CALLS )
2344 2345
            continue;

2346 2347
        MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
                        DLL_THREAD_DETACH, NULL );
2348 2349 2350
    }

    RtlLeaveCriticalSection( &loader_section );
2351
    RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer );
2352 2353
}

2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373

/***********************************************************************
 *           free_modref
 *
 */
static void free_modref( WINE_MODREF *wm )
{
    RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
    RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
    if (wm->ldr.InInitializationOrderModuleList.Flink)
        RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);

    TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
    if (!TRACE_ON(module))
        TRACE_(loaddll)("Unloaded module %s : %s\n",
                        debugstr_w(wm->ldr.FullDllName.Buffer),
                        (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );

    SERVER_START_REQ( unload_dll )
    {
2374
        req->base = wine_server_client_ptr( wm->ldr.BaseAddress );
2375 2376 2377 2378
        wine_server_call( req );
    }
    SERVER_END_REQ;

2379
    RtlReleaseActivationContext( wm->ldr.ActivationContext );
2380 2381 2382 2383 2384 2385 2386 2387
    NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
    if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
    if (cached_modref == wm) cached_modref = NULL;
    RtlFreeUnicodeString( &wm->ldr.FullDllName );
    RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
    RtlFreeHeap( GetProcessHeap(), 0, wm );
}

2388 2389 2390 2391 2392
/***********************************************************************
 *           MODULE_FlushModrefs
 *
 * Remove all unused modrefs and call the internal unloading routines
 * for the library type.
2393 2394
 *
 * The loader_section must be locked while calling this function.
2395 2396 2397
 */
static void MODULE_FlushModrefs(void)
{
2398 2399 2400
    PLIST_ENTRY mark, entry, prev;
    PLDR_MODULE mod;
    WINE_MODREF*wm;
2401

2402 2403
    mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
2404
    {
2405
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InInitializationOrderModuleList);
2406 2407
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
2408 2409
        if (!mod->LoadCount) free_modref( wm );
    }
2410

2411 2412 2413 2414 2415 2416 2417 2418
    /* check load order list too for modules that haven't been initialized yet */
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Blink; entry != mark; entry = prev)
    {
        mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
        wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
        prev = entry->Blink;
        if (!mod->LoadCount) free_modref( wm );
2419 2420 2421 2422 2423 2424
    }
}

/***********************************************************************
 *           MODULE_DecRefCount
 *
2425
 * The loader_section must be locked while calling this function.
2426 2427 2428 2429 2430
 */
static void MODULE_DecRefCount( WINE_MODREF *wm )
{
    int i;

2431
    if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
2432 2433
        return;

2434
    if ( wm->ldr.LoadCount <= 0 )
2435 2436
        return;

2437
    --wm->ldr.LoadCount;
2438
    TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
2439

2440
    if ( wm->ldr.LoadCount == 0 )
2441
    {
2442
        wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
2443 2444 2445 2446 2447

        for ( i = 0; i < wm->nDeps; i++ )
            if ( wm->deps[i] )
                MODULE_DecRefCount( wm->deps[i] );

2448
        wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
    }
}

/******************************************************************
 *		LdrUnloadDll (NTDLL.@)
 *
 *
 */
NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
{
    NTSTATUS retv = STATUS_SUCCESS;

    TRACE("(%p)\n", hModule);

    RtlEnterCriticalSection( &loader_section );

    /* if we're stopping the whole process (and forcing the removal of all
     * DLLs) the library will be freed anyway
     */
    if (!process_detaching)
    {
        WINE_MODREF *wm;

        free_lib_count++;
2473
        if ((wm = get_modref( hModule )) != NULL)
2474
        {
2475
            TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
2476 2477 2478 2479 2480 2481 2482

            /* Recursively decrement reference counts */
            MODULE_DecRefCount( wm );

            /* Call process detach notifications */
            if ( free_lib_count <= 1 )
            {
2483
                process_detach( FALSE, NULL );
2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499
                MODULE_FlushModrefs();
            }

            TRACE("END\n");
        }
        else
            retv = STATUS_DLL_NOT_FOUND;

        free_lib_count--;
    }

    RtlLeaveCriticalSection( &loader_section );

    return retv;
}

2500 2501 2502 2503 2504
/***********************************************************************
 *           RtlImageNtHeader   (NTDLL.@)
 */
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
{
2505
    IMAGE_NT_HEADERS *ret;
2506

2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517
    __TRY
    {
        IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;

        ret = NULL;
        if (dos->e_magic == IMAGE_DOS_SIGNATURE)
        {
            ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
            if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
        }
    }
2518
    __EXCEPT_PAGE_FAULT
2519
    {
2520
        return NULL;
2521
    }
2522
    __ENDTRY
2523 2524 2525 2526
    return ret;
}


2527 2528 2529 2530 2531 2532 2533 2534 2535
/***********************************************************************
 *           attach_process_dlls
 *
 * Initial attach to all the dlls loaded by the process.
 */
static NTSTATUS attach_process_dlls( void *wm )
{
    NTSTATUS status;

2536
    pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
2537

2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551
    RtlEnterCriticalSection( &loader_section );
    if ((status = process_attach( wm, (LPVOID)1 )) != STATUS_SUCCESS)
    {
        if (last_failed_modref)
            ERR( "%s failed to initialize, aborting\n",
                 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
        return status;
    }
    attach_implicitly_loaded_dlls( (LPVOID)1 );
    RtlLeaveCriticalSection( &loader_section );
    return status;
}


2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
/***********************************************************************
 *           load_global_options
 */
static void load_global_options(void)
{
    static const WCHAR sessionW[] = {'M','a','c','h','i','n','e','\\',
                                     'S','y','s','t','e','m','\\',
                                     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
                                     'C','o','n','t','r','o','l','\\',
                                     'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
    static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
    static const WCHAR critsectW[] = {'C','r','i','t','i','c','a','l','S','e','c','t','i','o','n','T','i','m','e','o','u','t',0};
    static const WCHAR heapresW[] = {'H','e','a','p','S','e','g','m','e','n','t','R','e','s','e','r','v','e',0};
    static const WCHAR heapcommitW[] = {'H','e','a','p','S','e','g','m','e','n','t','C','o','m','m','i','t',0};
    static const WCHAR decommittotalW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','T','o','t','a','l','F','r','e','e','T','h','r','e','s','h','o','l','d',0};
    static const WCHAR decommitfreeW[] = {'H','e','a','p','D','e','C','o','m','m','i','t','F','r','e','e','B','l','o','c','k','T','h','r','e','s','h','o','l','d',0};

    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING name_str;
    HANDLE hkey;
    ULONG value;

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.ObjectName = &name_str;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitUnicodeString( &name_str, sessionW );

    if (NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) return;

    query_dword_option( hkey, globalflagW, &NtCurrentTeb()->Peb->NtGlobalFlag );

    query_dword_option( hkey, critsectW, &value );
    NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart = (ULONGLONG)value * -10000000;

    query_dword_option( hkey, heapresW, &value );
    NtCurrentTeb()->Peb->HeapSegmentReserve = value;

    query_dword_option( hkey, heapcommitW, &value );
    NtCurrentTeb()->Peb->HeapSegmentCommit = value;

    query_dword_option( hkey, decommittotalW, &value );
    NtCurrentTeb()->Peb->HeapDeCommitTotalFreeThreshold = value;

    query_dword_option( hkey, decommitfreeW, &value );
    NtCurrentTeb()->Peb->HeapDeCommitFreeBlockThreshold = value;

    NtClose( hkey );
}


2605 2606 2607 2608 2609 2610 2611 2612
/***********************************************************************
 *           start_process
 */
static void start_process( void *kernel_start )
{
    call_thread_entry_point( kernel_start, NtCurrentTeb()->Peb );
}

2613 2614 2615 2616
/******************************************************************
 *		LdrInitializeThunk (NTDLL.@)
 *
 */
2617 2618
void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
                                ULONG_PTR unknown3, ULONG_PTR unknown4 )
2619
{
2620
    static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
2621 2622
    NTSTATUS status;
    WINE_MODREF *wm;
2623
    LPCWSTR load_path;
2624 2625 2626
    PEB *peb = NtCurrentTeb()->Peb;
    IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );

2627 2628
    if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */

2629
    /* allocate the modref for the main exe (if not already done) */
2630 2631 2632
    wm = get_modref( peb->ImageBaseAddress );
    assert( wm );
    if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
2633
    {
2634 2635
        ERR("%s is a dll, not an executable\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
        exit(1);
2636
    }
2637

2638
    peb->LoaderLock = &loader_section;
2639
    peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
2640 2641
    if (!peb->ProcessParameters->WindowTitle.Buffer)
        peb->ProcessParameters->WindowTitle = wm->ldr.FullDllName;
2642
    version_init( wm->ldr.FullDllName.Buffer );
2643

2644 2645 2646
    LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
                                       REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );

2647 2648 2649 2650
    /* the main exe needs to be the first in the load order list */
    RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
    InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );

2651
    if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;
2652
    if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
2653

2654
    actctx_init();
2655 2656
    load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
    if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
2657 2658
    if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
    if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
2659
    heap_set_debug_flags( GetProcessHeap() );
2660

2661 2662
    status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
    if (status != STATUS_SUCCESS) goto error;
2663

2664
    virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );
2665
    virtual_clear_thread_stack();
2666
    wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
2667 2668

error:
2669
    ERR( "Main exe initialization for %s failed, status %x\n",
2670
         debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), status );
2671
    NtTerminateProcess( GetCurrentProcess(), status );
2672 2673 2674
}


2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688
/***********************************************************************
 *           RtlImageDirectoryEntryToData   (NTDLL.@)
 */
PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
{
    const IMAGE_NT_HEADERS *nt;
    DWORD addr;

    if ((ULONG_PTR)module & 1)  /* mapped as data file */
    {
        module = (HMODULE)((ULONG_PTR)module & ~1);
        image = FALSE;
    }
    if (!(nt = RtlImageNtHeader( module ))) return NULL;
2689 2690
    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
2691
        const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
2692 2693 2694 2695 2696 2697 2698 2699

        if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
        if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
        *size = nt64->OptionalHeader.DataDirectory[dir].Size;
        if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
    }
    else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
    {
2700
        const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
2701 2702 2703 2704 2705 2706 2707

        if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
        if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
        *size = nt32->OptionalHeader.DataDirectory[dir].Size;
        if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
    }
    else return NULL;
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720

    /* not mapped as image, need to find the section containing the virtual address */
    return RtlImageRvaToVa( nt, module, addr, NULL );
}


/***********************************************************************
 *           RtlImageRvaToSection   (NTDLL.@)
 */
PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
                                                   HMODULE module, DWORD rva )
{
    int i;
Eric Pouech's avatar
Eric Pouech committed
2721 2722 2723 2724
    const IMAGE_SECTION_HEADER *sec;

    sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
                                        nt->FileHeader.SizeOfOptionalHeader);
2725 2726 2727
    for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
    {
        if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
Eric Pouech's avatar
Eric Pouech committed
2728
            return (PIMAGE_SECTION_HEADER)sec;
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
    }
    return NULL;
}


/***********************************************************************
 *           RtlImageRvaToVa   (NTDLL.@)
 */
PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
                              DWORD rva, IMAGE_SECTION_HEADER **section )
{
    IMAGE_SECTION_HEADER *sec;

    if (section && *section)  /* try this section first */
    {
        sec = *section;
        if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
            goto found;
    }
    if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
 found:
    if (section) *section = sec;
    return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
}
2753 2754


2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770
/***********************************************************************
 *           RtlPcToFileHeader   (NTDLL.@)
 */
PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
{
    LDR_MODULE *module;
    PVOID ret = NULL;

    RtlEnterCriticalSection( &loader_section );
    if (!LdrFindEntryForAddress( pc, &module )) ret = module->BaseAddress;
    RtlLeaveCriticalSection( &loader_section );
    *address = ret;
    return ret;
}


2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792
/***********************************************************************
 *           NtLoadDriver   (NTDLL.@)
 *           ZwLoadDriver   (NTDLL.@)
 */
NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *DriverServiceName )
{
    FIXME("(%p), stub!\n",DriverServiceName);
    return STATUS_NOT_IMPLEMENTED;
}


/***********************************************************************
 *           NtUnloadDriver   (NTDLL.@)
 *           ZwUnloadDriver   (NTDLL.@)
 */
NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
{
    FIXME("(%p), stub!\n",DriverServiceName);
    return STATUS_NOT_IMPLEMENTED;
}


2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
/******************************************************************
 *		DllMain   (NTDLL.@)
 */
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
{
    if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
    return TRUE;
}


2803 2804 2805 2806 2807
/******************************************************************
 *		__wine_init_windows_dir   (NTDLL.@)
 *
 * Windows and system dir initialization once kernel32 has been loaded.
 */
2808
void CDECL __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir )
2809 2810 2811 2812
{
    PLIST_ENTRY mark, entry;
    LPWSTR buffer, p;

2813
    DIR_init_windows_dir( windir, sysdir );
2814
    strcpyW( user_shared_data->NtSystemRoot, windir );
2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836

    /* prepend the system dir to the name of the already created modules */
    mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
    {
        LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );

        assert( mod->Flags & LDR_WINE_INTERNAL );

        buffer = RtlAllocateHeap( GetProcessHeap(), 0,
                                  system_dir.Length + mod->FullDllName.Length + 2*sizeof(WCHAR) );
        if (!buffer) continue;
        strcpyW( buffer, system_dir.Buffer );
        p = buffer + strlenW( buffer );
        if (p > buffer && p[-1] != '\\') *p++ = '\\';
        strcpyW( p, mod->FullDllName.Buffer );
        RtlInitUnicodeString( &mod->FullDllName, buffer );
        RtlInitUnicodeString( &mod->BaseDllName, p );
    }
}


2837
/***********************************************************************
2838
 *           __wine_process_init
2839
 */
2840
void __wine_process_init(void)
2841
{
2842
    static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
2843

2844 2845 2846
    WINE_MODREF *wm;
    NTSTATUS status;
    ANSI_STRING func_name;
2847
    void (* DECLSPEC_NORETURN CDECL init_func)(void);
2848
    extern mode_t FILE_umask;
2849

2850
    main_exe_file = thread_init();
2851

2852 2853 2854 2855
    /* retrieve current umask */
    FILE_umask = umask(0777);
    umask( FILE_umask );

2856 2857
    load_global_options();

2858
    /* setup the load callback and create ntdll modref */
2859
    wine_dll_set_callback( load_builtin_callback );
2860

2861
    if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS)
2862
    {
2863
        MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
2864 2865
        exit(1);
    }
2866 2867 2868
    RtlInitAnsiString( &func_name, "UnhandledExceptionFilter" );
    LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name, 0, (void **)&unhandled_exception_filter );

2869 2870 2871 2872
    RtlInitAnsiString( &func_name, "__wine_kernel_init" );
    if ((status = LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name,
                                          0, (void **)&init_func )) != STATUS_SUCCESS)
    {
2873
        MESSAGE( "wine: could not find __wine_kernel_init in kernel32.dll, status %x\n", status );
2874 2875 2876
        exit(1);
    }
    init_func();
2877
}