add access(2) call before dlopening files
[platform/upstream/coreclr.git] / src / pal / src / loader / module.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     module.c
12
13 Abstract:
14
15     Implementation of module related functions in the Win32 API
16
17
18
19 --*/
20
21 #include "pal/dbgmsg.h"
22 SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do this first
23
24 #include "pal/thread.hpp"
25 #include "pal/malloc.hpp"
26 #include "pal/file.hpp"
27 #include "pal/palinternal.h"
28 #include "pal/module.h"
29 #include "pal/cs.hpp"
30 #include "pal/process.h"
31 #include "pal/file.h"
32 #include "pal/utils.h"
33 #include "pal/init.h"
34 #include "pal/modulename.h"
35 #include "pal/environ.h"
36 #include "pal/virtual.h"
37 #include "pal/map.hpp"
38 #include "pal/stackstring.hpp"
39
40 #include <sys/param.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <limits.h>
44 #if NEED_DLCOMPAT
45 #include "dlcompat.h"
46 #else   // NEED_DLCOMPAT
47 #include <dlfcn.h>
48 #endif  // NEED_DLCOMPAT
49 #include <stdlib.h>
50
51 #ifdef __APPLE__
52 #include <mach-o/dyld.h>
53 #include <mach-o/loader.h>
54 #endif // __APPLE__
55
56 #include <sys/types.h>
57 #include <sys/mman.h>
58
59 #if HAVE_GNU_LIBNAMES_H
60 #include <gnu/lib-names.h>
61 #endif
62
63 using namespace CorUnix;
64
65 // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
66 // defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
67 // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(LOADER)
68 #include <safemath.h>
69
70 /* macro definitions **********************************************************/
71
72 /* get the full name of a module if available, and the short name otherwise*/
73 #define MODNAME(x) ((x)->lib_name)
74
75 /* Which path should FindLibrary search? */
76 #if defined(__APPLE__)
77 #define LIBSEARCHPATH "DYLD_LIBRARY_PATH"
78 #else
79 #define LIBSEARCHPATH "LD_LIBRARY_PATH"
80 #endif
81
82 #define LIBC_NAME_WITHOUT_EXTENSION "libc"
83
84 /* static variables ***********************************************************/
85
86 /* critical section that regulates access to the module list */
87 CRITICAL_SECTION module_critsec;
88
89 /* always the first, in the in-load-order list */
90 MODSTRUCT exe_module;
91 MODSTRUCT *pal_module = nullptr;
92
93 char * g_szCoreCLRPath = nullptr;
94
95 int MaxWCharToAcpLength = 3;
96
97 /* static function declarations ***********************************************/
98
99 template<class TChar> static bool LOADVerifyLibraryPath(const TChar *libraryPath);
100 static bool LOADConvertLibraryPathWideStringToMultibyteString(
101     LPCWSTR wideLibraryPath,
102     LPSTR multibyteLibraryPath,
103     INT *multibyteLibraryPathLengthRef);
104 static BOOL LOADValidateModule(MODSTRUCT *module);
105 static LPWSTR LOADGetModuleFileName(MODSTRUCT *module);
106 static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath);
107 static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath);
108 static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain);
109 static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic);
110 static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic);
111 static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved);
112
113 /* API function definitions ***************************************************/
114
115 /*++
116 Function:
117   LoadLibraryA
118
119 See MSDN doc.
120 --*/
121 HMODULE
122 PALAPI
123 LoadLibraryA(
124     IN LPCSTR lpLibFileName)
125 {
126     return LoadLibraryExA(lpLibFileName, nullptr, 0);
127 }
128
129 /*++
130 Function:
131   LoadLibraryW
132
133 See MSDN doc.
134 --*/
135 HMODULE
136 PALAPI
137 LoadLibraryW(
138     IN LPCWSTR lpLibFileName)
139 {
140     return LoadLibraryExW(lpLibFileName, nullptr, 0);
141 }
142
143 /*++
144 Function:
145 LoadLibraryExA
146
147 See MSDN doc.
148 --*/
149 HMODULE
150 PALAPI
151 LoadLibraryExA(
152     IN LPCSTR lpLibFileName,
153     IN /*Reserved*/ HANDLE hFile,
154     IN DWORD dwFlags)
155 {
156     if (dwFlags != 0)
157     {
158         // UNIXTODO: Implement this!
159         ASSERT("Needs Implementation!!!");
160         return nullptr;
161     }
162
163     LPSTR lpstr = nullptr;
164     HMODULE hModule = nullptr;
165
166     PERF_ENTRY(LoadLibraryA);
167     ENTRY("LoadLibraryExA (lpLibFileName=%p (%s)) \n",
168           (lpLibFileName) ? lpLibFileName : "NULL",
169           (lpLibFileName) ? lpLibFileName : "NULL");
170
171     if (!LOADVerifyLibraryPath(lpLibFileName))
172     {
173         goto Done;
174     }
175
176     /* do the Dos/Unix conversion on our own copy of the name */
177     lpstr = strdup(lpLibFileName);
178     if (!lpstr)
179     {
180         ERROR("strdup failure!\n");
181         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
182         goto Done;
183     }
184     FILEDosToUnixPathA(lpstr);
185
186     hModule = LOADLoadLibrary(lpstr, TRUE);
187
188     /* let LOADLoadLibrary call SetLastError */
189  Done:
190     if (lpstr != nullptr)
191     {
192         free(lpstr);
193     }
194
195     LOGEXIT("LoadLibraryExA returns HMODULE %p\n", hModule);
196     PERF_EXIT(LoadLibraryExA);
197     return hModule;
198
199 }
200
201 /*++
202 Function:
203 LoadLibraryExW
204
205 See MSDN doc.
206 --*/
207 HMODULE
208 PALAPI
209 LoadLibraryExW(
210     IN LPCWSTR lpLibFileName,
211     IN /*Reserved*/ HANDLE hFile,
212     IN DWORD dwFlags)
213 {
214     if (dwFlags != 0)
215     {
216         // UNIXTODO: Implement this!
217         ASSERT("Needs Implementation!!!");
218         return nullptr;
219     }
220
221     CHAR * lpstr;
222     INT name_length;
223     PathCharString pathstr;
224     HMODULE hModule = nullptr;
225
226     PERF_ENTRY(LoadLibraryExW);
227     ENTRY("LoadLibraryExW (lpLibFileName=%p (%S)) \n",
228           lpLibFileName ? lpLibFileName : W16_NULLSTRING,
229           lpLibFileName ? lpLibFileName : W16_NULLSTRING);
230
231     if (!LOADVerifyLibraryPath(lpLibFileName))
232     {
233         goto done;
234     }
235
236     lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
237     if (nullptr == lpstr)
238     {
239         goto done;
240     }
241     if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
242     {
243         goto done;
244     }
245
246     /* do the Dos/Unix conversion on our own copy of the name */
247     FILEDosToUnixPathA(lpstr);
248     pathstr.CloseBuffer(name_length);
249
250     /* let LOADLoadLibrary call SetLastError in case of failure */
251     hModule = LOADLoadLibrary(lpstr, TRUE);
252
253 done:
254     LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
255     PERF_EXIT(LoadLibraryExW);
256     return hModule;
257 }
258
259 /*++
260 Function:
261   GetProcAddress
262
263 See MSDN doc.
264 --*/
265 FARPROC
266 PALAPI
267 GetProcAddress(
268     IN HMODULE hModule,
269     IN LPCSTR lpProcName)
270 {
271     MODSTRUCT *module;
272     FARPROC ProcAddress = nullptr;
273     LPCSTR symbolName = lpProcName;
274
275     PERF_ENTRY(GetProcAddress);
276     ENTRY("GetProcAddress (hModule=%p, lpProcName=%p (%s))\n",
277           hModule, lpProcName ? lpProcName : "NULL", lpProcName ? lpProcName : "NULL");
278
279     LockModuleList();
280
281     module = (MODSTRUCT *) hModule;
282
283     /* try to assert on attempt to locate symbol by ordinal */
284     /* this can't be an exact test for HIWORD((DWORD)lpProcName) == 0
285        because of the address range reserved for ordinals contain can
286        be a valid string address on non-Windows systems
287     */
288     if ((DWORD_PTR)lpProcName < GetVirtualPageSize())
289     {
290         ASSERT("Attempt to locate symbol by ordinal?!\n");
291     }
292
293     /* parameter validation */
294
295     if ((lpProcName == nullptr) || (*lpProcName == '\0'))
296     {
297         TRACE("No function name given\n");
298         SetLastError(ERROR_INVALID_PARAMETER);
299         goto done;
300     }
301
302     if (!LOADValidateModule(module))
303     {
304         TRACE("Invalid module handle %p\n", hModule);
305         SetLastError(ERROR_INVALID_HANDLE);
306         goto done;
307     }
308
309     // Get the symbol's address.
310
311     // If we're looking for a symbol inside the PAL, we try the PAL_ variant
312     // first because otherwise we run the risk of having the non-PAL_
313     // variant preferred over the PAL's implementation.
314     if (pal_module && module->dl_handle == pal_module->dl_handle)
315     {
316         int iLen = 4 + strlen(lpProcName) + 1;
317         LPSTR lpPALProcName = (LPSTR) alloca(iLen);
318
319         if (strcpy_s(lpPALProcName, iLen, "PAL_") != SAFECRT_SUCCESS)
320         {
321             ERROR("strcpy_s failed!\n");
322             SetLastError(ERROR_INSUFFICIENT_BUFFER);
323             goto done;
324         }
325
326         if (strcat_s(lpPALProcName, iLen, lpProcName) != SAFECRT_SUCCESS)
327         {
328             ERROR("strcat_s failed!\n");
329             SetLastError(ERROR_INSUFFICIENT_BUFFER);
330             goto done;
331         }
332
333         ProcAddress = (FARPROC) dlsym(module->dl_handle, lpPALProcName);
334         symbolName = lpPALProcName;
335     }
336
337     // If we aren't looking inside the PAL or we didn't find a PAL_ variant
338     // inside the PAL, fall back to a normal search.
339     if (ProcAddress == nullptr)
340     {
341         ProcAddress = (FARPROC) dlsym(module->dl_handle, lpProcName);
342     }
343
344     if (ProcAddress)
345     {
346         TRACE("Symbol %s found at address %p in module %p (named %S)\n",
347               lpProcName, ProcAddress, module, MODNAME(module));
348
349         /* if we don't know the module's full name yet, this is our chance to obtain it */
350         if (!module->lib_name && module->dl_handle)
351         {
352             const char* libName = PAL_dladdr((LPVOID)ProcAddress);
353             if (libName)
354             {
355                 module->lib_name = UTIL_MBToWC_Alloc(libName, -1);
356                 if (nullptr == module->lib_name)
357                 {
358                     ERROR("MBToWC failure; can't save module's full name\n");
359                 }
360                 else
361                 {
362                     TRACE("Saving full path of module %p as %s\n",
363                           module, libName);
364                 }
365             }
366         }
367     }
368     else
369     {
370         TRACE("Symbol %s not found in module %p (named %S)\n",
371               lpProcName, module, MODNAME(module));
372         SetLastError(ERROR_PROC_NOT_FOUND);
373     }
374 done:
375     UnlockModuleList();
376     LOGEXIT("GetProcAddress returns FARPROC %p\n", ProcAddress);
377     PERF_EXIT(GetProcAddress);
378     return ProcAddress;
379 }
380
381 /*++
382 Function:
383   FreeLibrary
384
385 See MSDN doc.
386 --*/
387 BOOL
388 PALAPI
389 FreeLibrary(
390     IN OUT HMODULE hLibModule)
391 {
392     BOOL retval = FALSE;
393
394     PERF_ENTRY(FreeLibrary);
395     ENTRY("FreeLibrary (hLibModule=%p)\n", hLibModule);
396
397     retval = LOADFreeLibrary((MODSTRUCT *)hLibModule, TRUE /* fCallDllMain */);
398
399     LOGEXIT("FreeLibrary returns BOOL %d\n", retval);
400     PERF_EXIT(FreeLibrary);
401     return retval;
402 }
403
404 /*++
405 Function:
406   FreeLibraryAndExitThread
407
408 See MSDN doc.
409
410 --*/
411 PALIMPORT
412 VOID
413 PALAPI
414 FreeLibraryAndExitThread(
415     IN HMODULE hLibModule,
416     IN DWORD dwExitCode)
417 {
418     PERF_ENTRY(FreeLibraryAndExitThread);
419     ENTRY("FreeLibraryAndExitThread()\n");
420     FreeLibrary(hLibModule);
421     ExitThread(dwExitCode);
422     LOGEXIT("FreeLibraryAndExitThread\n");
423     PERF_EXIT(FreeLibraryAndExitThread);
424 }
425
426 /*++
427 Function:
428   GetModuleFileNameA
429
430 See MSDN doc.
431
432 Notes :
433     because of limitations in the dlopen() mechanism, this will only return the
434     full path name if a relative or absolute path was given to LoadLibrary, or
435     if the module was used in a GetProcAddress call. otherwise, this will return
436     the short name as given to LoadLibrary. The exception is if hModule is
437     NULL : in this case, the full path of the executable is always returned.
438 --*/
439 DWORD
440 PALAPI
441 GetModuleFileNameA(
442     IN HMODULE hModule,
443     OUT LPSTR lpFileName,
444     IN DWORD nSize)
445 {
446     INT name_length;
447     DWORD retval = 0;
448     LPWSTR wide_name = nullptr;
449
450     PERF_ENTRY(GetModuleFileNameA);
451     ENTRY("GetModuleFileNameA (hModule=%p, lpFileName=%p, nSize=%u)\n",
452           hModule, lpFileName, nSize);
453
454     LockModuleList();
455     if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
456     {
457         TRACE("Can't find name for invalid module handle %p\n", hModule);
458         SetLastError(ERROR_INVALID_HANDLE);
459         goto done;
460     }
461     wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
462
463     if (!wide_name)
464     {
465         ASSERT("Can't find name for valid module handle %p\n", hModule);
466         SetLastError(ERROR_INTERNAL_ERROR);
467         goto done;
468     }
469
470     /* Convert module name to Ascii, place it in the supplied buffer */
471
472     name_length = WideCharToMultiByte(CP_ACP, 0, wide_name, -1, lpFileName,
473                                       nSize, nullptr, nullptr);
474     if (name_length == 0)
475     {
476         TRACE("Buffer too small to copy module's file name.\n");
477         SetLastError(ERROR_INSUFFICIENT_BUFFER);
478         goto done;
479     }
480
481     TRACE("File name of module %p is %s\n", hModule, lpFileName);
482     retval = name_length;
483 done:
484     UnlockModuleList();
485     LOGEXIT("GetModuleFileNameA returns DWORD %d\n", retval);
486     PERF_EXIT(GetModuleFileNameA);
487     return retval;
488 }
489
490 /*++
491 Function:
492   GetModuleFileNameW
493
494 See MSDN doc.
495
496 Notes :
497     because of limitations in the dlopen() mechanism, this will only return the
498     full path name if a relative or absolute path was given to LoadLibrary, or
499     if the module was used in a GetProcAddress call. otherwise, this will return
500     the short name as given to LoadLibrary. The exception is if hModule is
501     NULL : in this case, the full path of the executable is always returned.
502 --*/
503 DWORD
504 PALAPI
505 GetModuleFileNameW(
506     IN HMODULE hModule,
507     OUT LPWSTR lpFileName,
508     IN DWORD nSize)
509 {
510     INT name_length;
511     DWORD retval = 0;
512     LPWSTR wide_name = nullptr;
513
514     PERF_ENTRY(GetModuleFileNameW);
515     ENTRY("GetModuleFileNameW (hModule=%p, lpFileName=%p, nSize=%u)\n",
516           hModule, lpFileName, nSize);
517
518     LockModuleList();
519
520     wcscpy_s(lpFileName, nSize, W(""));
521
522     if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
523     {
524         TRACE("Can't find name for invalid module handle %p\n", hModule);
525         SetLastError(ERROR_INVALID_HANDLE);
526         goto done;
527     }
528     wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
529
530     if (!wide_name)
531     {
532         TRACE("Can't find name for valid module handle %p\n", hModule);
533         SetLastError(ERROR_INTERNAL_ERROR);
534         goto done;
535     }
536
537     /* Copy module name into supplied buffer */
538
539     name_length = PAL_wcslen(wide_name);
540     if (name_length >= (INT)nSize)
541     {
542         TRACE("Buffer too small (%u) to copy module's file name (%u).\n", nSize, name_length);
543         retval = (INT)nSize;
544         SetLastError(ERROR_INSUFFICIENT_BUFFER);
545         goto done;
546     }
547
548     wcscpy_s(lpFileName, nSize, wide_name);
549
550     TRACE("file name of module %p is %S\n", hModule, lpFileName);
551     retval = (DWORD)name_length;
552 done:
553     UnlockModuleList();
554     LOGEXIT("GetModuleFileNameW returns DWORD %u\n", retval);
555     PERF_EXIT(GetModuleFileNameW);
556     return retval;
557 }
558
559 LPCSTR FixLibCName(LPCSTR shortAsciiName)
560 {
561     // Check whether we have been requested to load 'libc'. If that's the case, then:
562     // * For Linux, use the full name of the library that is defined in <gnu/lib-names.h> by the
563     //   LIBC_SO constant. The problem is that calling dlopen("libc.so") will fail for libc even
564     //   though it works for other libraries. The reason is that libc.so is just linker script
565     //   (i.e. a test file).
566     //   As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
567     // * For macOS, use constant value absolute path "/usr/lib/libc.dylib".
568     // * For FreeBSD, use constant value "libc.so.7".
569     // * For rest of Unices, use constant value "libc.so".
570     if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
571     {
572 #if defined(__APPLE__)
573         return "/usr/lib/libc.dylib";
574 #elif defined(__FreeBSD__)
575         return "libc.so.7";
576 #elif defined(LIBC_SO)
577         return LIBC_SO;
578 #else
579         return "libc.so";
580 #endif
581     }
582
583     return shortAsciiName;
584 }
585
586 /*
587 Function:
588   PAL_LoadLibraryDirect
589
590   Loads a library using a system call, without registering the library with the module list.
591
592   Returns the system handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
593 */
594 NATIVE_LIBRARY_HANDLE
595 PALAPI
596 PAL_LoadLibraryDirect(
597     IN LPCWSTR lpLibFileName)
598 {
599     PathCharString pathstr;
600     CHAR * lpstr = nullptr;
601     LPCSTR lpcstr = nullptr;
602     INT name_length;
603     NATIVE_LIBRARY_HANDLE dl_handle = nullptr;
604
605     PERF_ENTRY(LoadLibraryDirect);
606     ENTRY("LoadLibraryDirect (lpLibFileName=%p (%S)) \n",
607           lpLibFileName ? lpLibFileName : W16_NULLSTRING,
608           lpLibFileName ? lpLibFileName : W16_NULLSTRING);
609
610     if (!LOADVerifyLibraryPath(lpLibFileName))
611     {
612         goto done;
613     }
614
615     lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
616     if (nullptr == lpstr)
617     {
618         goto done;
619     }
620     if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
621     {
622         goto done;
623     }
624
625     /* do the Dos/Unix conversion on our own copy of the name */
626     FILEDosToUnixPathA(lpstr);
627     pathstr.CloseBuffer(name_length);
628     lpcstr = FixLibCName(lpstr);
629
630     dl_handle = LOADLoadLibraryDirect(lpcstr);
631
632 done:
633     LOGEXIT("LoadLibraryDirect returns NATIVE_LIBRARY_HANDLE %p\n", dl_handle);
634     PERF_EXIT(LoadLibraryDirect);
635     return dl_handle;
636 }
637
638 /*
639 Function:
640   PAL_FreeLibraryDirect
641
642   Free a loaded library
643
644   Returns true on success, false on failure.
645 */
646 BOOL
647 PALAPI
648 PAL_FreeLibraryDirect(
649         IN NATIVE_LIBRARY_HANDLE dl_handle)
650 {
651     BOOL retValue = 0;
652     PERF_ENTRY(PAL_FreeLibraryDirect);
653     ENTRY("PAL_FreeLibraryDirect (dl_handle=%p) \n", dl_handle);
654
655     retValue = dlclose(dl_handle) == 0;
656
657     LOGEXIT("PAL_FreeLibraryDirect returns BOOL %p\n", retValue);
658     PERF_EXIT(PAL_FreeLibraryDirect);
659     return retValue;
660 }
661
662 /*
663 Function:
664   PAL_GetProcAddressDirect
665
666   Get the address corresponding to a symbol in a loaded native library.
667
668   Returns the address of the sumbol loaded in memory.
669 */
670 FARPROC
671 PALAPI
672 PAL_GetProcAddressDirect(
673         IN NATIVE_LIBRARY_HANDLE dl_handle,
674         IN LPCSTR lpProcName)
675 {
676     INT name_length;
677     FARPROC address = nullptr;
678
679     PERF_ENTRY(PAL_GetProcAddressDirect);
680     ENTRY("PAL_GetProcAddressDirect (lpLibFileName=%p (%S)) \n",
681           lpProcName ? lpProcName : "NULL",
682           lpProcName ? lpProcName : "NULL");
683
684     address = (FARPROC) dlsym(dl_handle, lpProcName);
685
686     LOGEXIT("PAL_GetProcAddressDirect returns FARPROC %p\n", address);
687     PERF_EXIT(PAL_GetProcAddressDirect);
688     return address;
689 }
690
691 /*++
692 Function:
693   PAL_RegisterModule
694
695   Register the module with the target module and return a module handle in
696   the target module's context. Doesn't call the DllMain because it is used
697   as part of calling DllMain in the calling module.
698
699 --*/
700 HINSTANCE
701 PALAPI
702 PAL_RegisterModule(
703     IN LPCSTR lpLibFileName)
704 {
705     HINSTANCE hinstance = nullptr;
706
707     int err = PAL_InitializeDLL();
708     if (err == 0)
709     {
710         PERF_ENTRY(PAL_RegisterModule);
711         ENTRY("PAL_RegisterModule(%s)\n", lpLibFileName ? lpLibFileName : "");
712
713         LockModuleList();
714
715         NATIVE_LIBRARY_HANDLE dl_handle = LOADLoadLibraryDirect(lpLibFileName);
716         if (dl_handle)
717         {
718             // This only creates/adds the module handle and doesn't call DllMain
719             hinstance = LOADAddModule(dl_handle, lpLibFileName);
720         }
721
722         UnlockModuleList();
723
724         LOGEXIT("PAL_RegisterModule returns HINSTANCE %p\n", hinstance);
725         PERF_EXIT(PAL_RegisterModule);
726     }
727
728     return hinstance;
729 }
730
731 /*++
732 Function:
733   PAL_UnregisterModule
734
735   Used to cleanup the module HINSTANCE from PAL_RegisterModule.
736 --*/
737 VOID
738 PALAPI
739 PAL_UnregisterModule(
740     IN HINSTANCE hInstance)
741 {
742     PERF_ENTRY(PAL_UnregisterModule);
743     ENTRY("PAL_UnregisterModule(hInstance=%p)\n", hInstance);
744
745     LOADFreeLibrary((MODSTRUCT *)hInstance, FALSE /* fCallDllMain */);
746
747     LOGEXIT("PAL_UnregisterModule returns\n");
748     PERF_EXIT(PAL_UnregisterModule);
749 }
750
751 /*++
752     PAL_LOADLoadPEFile
753
754     Map a PE format file into memory like Windows LoadLibrary() would do.
755     Doesn't apply base relocations if the function is relocated.
756
757 Parameters:
758     IN hFile - file to map
759
760 Return value:
761     non-NULL - the base address of the mapped image
762     NULL - error, with last error set.
763 --*/
764 PVOID
765 PALAPI
766 PAL_LOADLoadPEFile(HANDLE hFile)
767 {
768     ENTRY("PAL_LOADLoadPEFile (hFile=%p)\n", hFile);
769
770     void * loadedBase = MAPMapPEFile(hFile);
771
772 #ifdef _DEBUG
773     if (loadedBase != nullptr)
774     {
775         char* envVar = EnvironGetenv("PAL_ForcePEMapFailure");
776         if (envVar)
777         {
778             if (strlen(envVar) > 0)
779             {
780                 TRACE("Forcing failure of PE file map, and retry\n");
781                 PAL_LOADUnloadPEFile(loadedBase); // unload it
782                 loadedBase = MAPMapPEFile(hFile); // load it again
783             }
784
785             free(envVar);
786         }
787     }
788 #endif // _DEBUG
789
790     LOGEXIT("PAL_LOADLoadPEFile returns %p\n", loadedBase);
791     return loadedBase;
792 }
793
794 /*++
795     PAL_LOADUnloadPEFile
796
797     Unload a PE file that was loaded by PAL_LOADLoadPEFile().
798
799 Parameters:
800     IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
801
802 Return value:
803     TRUE - success
804     FALSE - failure (incorrect ptr, etc.)
805 --*/
806 BOOL
807 PALAPI
808 PAL_LOADUnloadPEFile(PVOID ptr)
809 {
810     BOOL retval = FALSE;
811
812     ENTRY("PAL_LOADUnloadPEFile (ptr=%p)\n", ptr);
813
814     if (nullptr == ptr)
815     {
816         ERROR( "Invalid pointer value\n" );
817     }
818     else
819     {
820         retval = MAPUnmapPEFile(ptr);
821     }
822
823     LOGEXIT("PAL_LOADUnloadPEFile returns %d\n", retval);
824     return retval;
825 }
826
827 /*++
828     PAL_GetSymbolModuleBase
829
830     Get base address of the module containing a given symbol
831
832 Parameters:
833     void *symbol - address of symbol
834
835 Return value:
836     module base address
837 --*/
838 LPCVOID
839 PALAPI
840 PAL_GetSymbolModuleBase(PVOID symbol)
841 {
842     LPCVOID retval = nullptr;
843
844     PERF_ENTRY(PAL_GetPalModuleBase);
845     ENTRY("PAL_GetPalModuleBase\n");
846
847     if (symbol == nullptr)
848     {
849         TRACE("Can't get base address. Argument symbol == nullptr\n");
850         SetLastError(ERROR_INVALID_DATA);
851     }
852     else
853     {
854         Dl_info info;
855         if (dladdr(symbol, &info) != 0)
856         {
857             retval = info.dli_fbase;
858         }
859         else
860         {
861             TRACE("Can't get base address of the current module\n");
862             SetLastError(ERROR_INVALID_DATA);
863         }
864     }
865
866     LOGEXIT("PAL_GetPalModuleBase returns %p\n", retval);
867     PERF_EXIT(PAL_GetPalModuleBase);
868     return retval;
869 }
870
871 /*++
872     PAL_GetLoadLibraryError
873
874     Wrapper for dlerror() to be used by PAL functions
875
876 Return value:
877
878 A LPCSTR containing the output of dlerror()
879
880 --*/
881 PALIMPORT
882 LPCSTR
883 PALAPI
884 PAL_GetLoadLibraryError()
885 {
886
887     PERF_ENTRY(PAL_GetLoadLibraryError);
888     ENTRY("PAL_GetLoadLibraryError");
889
890     LPCSTR last_error = dlerror();
891
892     LOGEXIT("PAL_GetLoadLibraryError returns %p\n", last_error);
893     PERF_EXIT(PAL_GetLoadLibraryError);
894     return last_error;
895 }
896
897
898 /* Internal PAL functions *****************************************************/
899
900 /*++
901 Function :
902     LOADInitializeModules
903
904     Initialize the process-wide list of modules
905
906 Parameters :
907     None
908
909 Return value :
910     TRUE  if initialization succeedded
911     FALSE otherwise
912
913 --*/
914 extern "C"
915 BOOL LOADInitializeModules()
916 {
917     _ASSERTE(exe_module.prev == nullptr);
918
919     InternalInitializeCriticalSection(&module_critsec);
920
921     // Initialize module for main executable
922     TRACE("Initializing module for main executable\n");
923
924     exe_module.self = (HMODULE)&exe_module;
925     exe_module.dl_handle = dlopen(nullptr, RTLD_LAZY);
926     if (exe_module.dl_handle == nullptr)
927     {
928         ERROR("Executable module will be broken : dlopen(nullptr) failed\n");
929         return FALSE;
930     }
931     exe_module.lib_name = nullptr;
932     exe_module.refcount = -1;
933     exe_module.next = &exe_module;
934     exe_module.prev = &exe_module;
935     exe_module.pDllMain = nullptr;
936     exe_module.hinstance = nullptr;
937     exe_module.threadLibCalls = TRUE;
938     return TRUE;
939 }
940
941 /*++
942 Function :
943     LOADSetExeName
944
945     Set the exe name path
946
947 Parameters :
948     LPWSTR man exe path and name
949
950 Return value :
951     TRUE  if initialization succeedded
952     FALSE otherwise
953
954 --*/
955 extern "C"
956 BOOL LOADSetExeName(LPWSTR name)
957 {
958 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
959     LPSTR pszExeName = nullptr;
960 #endif
961     BOOL result = FALSE;
962
963     LockModuleList();
964
965     // Save the exe path in the exe module struct
966     free(exe_module.lib_name);
967     exe_module.lib_name = name;
968
969     // For platforms where we can't trust the handle to be constant, we need to
970     // store the inode/device pairs for the modules we just initialized.
971 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
972     {
973         struct stat stat_buf;
974         pszExeName = UTIL_WCToMB_Alloc(name, -1);
975         if (nullptr == pszExeName)
976         {
977             ERROR("WCToMB failure, unable to get full name of exe\n");
978             goto exit;
979         }
980         if (-1 == stat(pszExeName, &stat_buf))
981         {
982             SetLastError(ERROR_MOD_NOT_FOUND);
983             goto exit;
984         }
985         TRACE("Executable has inode %d and device %d\n", stat_buf.st_ino, stat_buf.st_dev);
986
987         exe_module.inode = stat_buf.st_ino;
988         exe_module.device = stat_buf.st_dev;
989     }
990 #endif
991     result = TRUE;
992
993 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
994 exit:
995     if (pszExeName)
996     {
997         free(pszExeName);
998     }
999 #endif
1000     UnlockModuleList();
1001     return result;
1002 }
1003
1004 /*++
1005 Function :
1006     LOADCallDllMain
1007
1008     Call DllMain for all modules (that have one) with the given "fwReason"
1009
1010 Parameters :
1011     DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1012         DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1013
1014     LPVOID lpReserved : parameter to pass down to DllMain
1015         If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1016         If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1017             and non-NULL if DllMain has been called during process termination.
1018
1019 (no return value)
1020
1021 Notes :
1022     This is used to send DLL_THREAD_*TACH messages to modules
1023 --*/
1024 extern "C"
1025 void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
1026 {
1027     MODSTRUCT *module = nullptr;
1028     BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */
1029     CPalThread *pThread;
1030
1031     pThread = InternalGetCurrentThread();
1032     if (UserCreatedThread != pThread->GetThreadType())
1033     {
1034         return;
1035     }
1036
1037     /* Validate dwReason */
1038     switch(dwReason)
1039     {
1040     case DLL_PROCESS_ATTACH:
1041         ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n");
1042         break;
1043     case DLL_PROCESS_DETACH:
1044         ASSERT("got called with DLL_PROCESS_DETACH parameter! Why?\n");
1045         InLoadOrder = FALSE;
1046         break;
1047     case DLL_THREAD_ATTACH:
1048         TRACE("Calling DllMain(DLL_THREAD_ATTACH) on all known modules.\n");
1049         break;
1050     case DLL_THREAD_DETACH:
1051         TRACE("Calling DllMain(DLL_THREAD_DETACH) on all known modules.\n");
1052         InLoadOrder = FALSE;
1053         break;
1054     default:
1055         ASSERT("LOADCallDllMain called with unknown parameter %d!\n", dwReason);
1056         return;
1057     }
1058
1059     LockModuleList();
1060
1061     module = &exe_module;
1062
1063     do
1064     {
1065         if (!InLoadOrder)
1066             module = module->prev;
1067
1068         if (module->threadLibCalls)
1069         {
1070             if (module->pDllMain)
1071             {
1072                 LOADCallDllMainSafe(module, dwReason, lpReserved);
1073             }
1074         }
1075
1076         if (InLoadOrder)
1077             module = module->next;
1078
1079     } while (module != &exe_module);
1080
1081     UnlockModuleList();
1082 }
1083
1084 /*++
1085 Function:
1086   LOADFreeLibrary
1087
1088 Parameters:
1089   MODSTRUCT * module - module to free
1090   BOOL fCallDllMain - if TRUE, call the DllMain function
1091
1092 Returns:
1093   TRUE if successful
1094
1095 --*/
1096 static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain)
1097 {
1098     BOOL retval = FALSE;
1099
1100     LockModuleList();
1101
1102     if (terminator)
1103     {
1104         /* PAL shutdown is in progress - ignore FreeLibrary calls */
1105         retval = TRUE;
1106         goto done;
1107     }
1108
1109     if (!LOADValidateModule(module))
1110     {
1111         TRACE("Can't free invalid module %p\n", module);
1112         SetLastError(ERROR_INVALID_HANDLE);
1113         goto done;
1114     }
1115
1116     if (module->refcount == -1)
1117     {
1118         /* special module - never released */
1119         retval = TRUE;
1120         goto done;
1121     }
1122
1123     module->refcount--;
1124     TRACE("Reference count for module %p (named %S) decreases to %d\n",
1125             module, MODNAME(module), module->refcount);
1126
1127     if (module->refcount != 0)
1128     {
1129         retval = TRUE;
1130         goto done;
1131     }
1132
1133     /* Releasing the last reference : call dlclose(), remove module from the
1134        process-wide module list */
1135
1136     TRACE("Reference count for module %p (named %S) now 0; destroying module structure\n",
1137         module, MODNAME(module));
1138
1139     /* unlink the module structure from the list */
1140     module->prev->next = module->next;
1141     module->next->prev = module->prev;
1142
1143     /* remove the circular reference so that LOADValidateModule will fail */
1144     module->self = nullptr;
1145
1146     /* Call DllMain if the module contains one */
1147     if (fCallDllMain && module->pDllMain)
1148     {
1149         LOADCallDllMainSafe(module, DLL_PROCESS_DETACH, nullptr);
1150     }
1151
1152     if (module->hinstance)
1153     {
1154         PUNREGISTER_MODULE unregisterModule = (PUNREGISTER_MODULE)dlsym(module->dl_handle, "PAL_UnregisterModule");
1155         if (unregisterModule != nullptr)
1156         {
1157              unregisterModule(module->hinstance);
1158         }
1159         module->hinstance = nullptr;
1160     }
1161
1162     if (module->dl_handle && 0 != dlclose(module->dl_handle))
1163     {
1164         /* report dlclose() failure, but proceed anyway. */
1165         WARN("dlclose() call failed!\n");
1166     }
1167
1168     /* release all memory */
1169     free(module->lib_name);
1170     free(module);
1171
1172     retval = TRUE;
1173
1174 done:
1175     UnlockModuleList();
1176     return retval;
1177 }
1178
1179 /*++
1180 Function :
1181     LOADCallDllMainSafe
1182
1183     Exception-safe call to DllMain.
1184
1185 Parameters :
1186     MODSTRUCT *module : module whose DllMain must be called
1187
1188     DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1189         DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1190
1191     LPVOID lpvReserved : parameter to pass down to DllMain,
1192         If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1193         If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1194             and non-NULL if DllMain has been called during process termination.
1195
1196 Returns:
1197     BOOL : DllMain's return value
1198 */
1199 static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved)
1200 {
1201 #if _ENABLE_DEBUG_MESSAGES_
1202     /* reset ENTRY nesting level back to zero while inside the callback... */
1203     int old_level = DBG_change_entrylevel(0);
1204 #endif /* _ENABLE_DEBUG_MESSAGES_ */
1205
1206     struct Param
1207     {
1208         MODSTRUCT *module;
1209         DWORD dwReason;
1210         LPVOID lpReserved;
1211         BOOL ret;
1212     } param;
1213     param.module = module;
1214     param.dwReason = dwReason;
1215     param.lpReserved = lpReserved;
1216     param.ret = FALSE;
1217
1218     PAL_TRY(Param *, pParam, &param)
1219     {
1220         TRACE("Calling DllMain (%p) for module %S\n",
1221               pParam->module->pDllMain,
1222               pParam->module->lib_name ? pParam->module->lib_name : W16_NULLSTRING);
1223
1224         {
1225             // This module may be foreign to our PAL, so leave our PAL.
1226             // If it depends on us, it will re-enter.
1227             PAL_LeaveHolder holder;
1228             pParam->ret = pParam->module->pDllMain(pParam->module->hinstance, pParam->dwReason, pParam->lpReserved);
1229         }
1230     }
1231     PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1232     {
1233         WARN("Call to DllMain (%p) got an unhandled exception; ignoring.\n", module->pDllMain);
1234     }
1235     PAL_ENDTRY
1236
1237 #if _ENABLE_DEBUG_MESSAGES_
1238     /* ...and set nesting level back to what it was */
1239     DBG_change_entrylevel(old_level);
1240 #endif /* _ENABLE_DEBUG_MESSAGES_ */
1241
1242     return param.ret;
1243 }
1244
1245 /*++
1246 Function:
1247     DisableThreadLibraryCalls
1248
1249 See MSDN doc.
1250 --*/
1251 BOOL
1252 PALAPI
1253 DisableThreadLibraryCalls(
1254     IN HMODULE hLibModule)
1255 {
1256     BOOL ret = FALSE;
1257     MODSTRUCT *module;
1258     PERF_ENTRY(DisableThreadLibraryCalls);
1259     ENTRY("DisableThreadLibraryCalls(hLibModule=%p)\n", hLibModule);
1260
1261     LockModuleList();
1262
1263     if (terminator)
1264     {
1265         /* PAL shutdown in progress - ignore DisableThreadLibraryCalls */
1266         ret = TRUE;
1267         goto done;
1268     }
1269
1270     module = (MODSTRUCT *) hLibModule;
1271
1272     if (!LOADValidateModule(module))
1273     {
1274         // DisableThreadLibraryCalls() does nothing when given
1275         // an invalid module handle. This matches the Windows
1276         // behavior, though it is counter to MSDN.
1277         WARN("Invalid module handle %p\n", hLibModule);
1278         ret = TRUE;
1279         goto done;
1280     }
1281
1282     module->threadLibCalls = FALSE;
1283     ret = TRUE;
1284
1285 done:
1286     UnlockModuleList();
1287     LOGEXIT("DisableThreadLibraryCalls returns BOOL %d\n", ret);
1288     PERF_EXIT(DisableThreadLibraryCalls);
1289     return ret;
1290 }
1291
1292 // Checks the library path for null or empty string. On error, calls SetLastError() and returns false.
1293 template<class TChar>
1294 static bool LOADVerifyLibraryPath(const TChar *libraryPath)
1295 {
1296     if (libraryPath == nullptr)
1297     {
1298         ERROR("libraryPath is null\n");
1299         SetLastError(ERROR_MOD_NOT_FOUND);
1300         return false;
1301     }
1302     if (libraryPath[0] == '\0')
1303     {
1304         ERROR("libraryPath is empty\n");
1305         SetLastError(ERROR_INVALID_PARAMETER);
1306         return false;
1307     }
1308     return true;
1309 }
1310
1311 // Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false.
1312 static bool LOADConvertLibraryPathWideStringToMultibyteString(
1313     LPCWSTR wideLibraryPath,
1314     LPSTR multibyteLibraryPath,
1315     INT *multibyteLibraryPathLengthRef)
1316 {
1317     _ASSERTE(multibyteLibraryPathLengthRef != nullptr);
1318     _ASSERTE(wideLibraryPath != nullptr);
1319
1320     size_t length = (PAL_wcslen(wideLibraryPath)+1) * MaxWCharToAcpLength;
1321     *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath,
1322                                                         length, nullptr, nullptr);
1323
1324     if (*multibyteLibraryPathLengthRef == 0)
1325     {
1326         DWORD dwLastError = GetLastError();
1327
1328         ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1329
1330         SetLastError(ERROR_INVALID_PARAMETER);
1331         return false;
1332     }
1333     return true;
1334 }
1335
1336 /*++
1337 Function :
1338     LOADValidateModule
1339
1340     Check whether the given MODSTRUCT pointer is valid
1341
1342 Parameters :
1343     MODSTRUCT *module : module to check
1344
1345 Return value :
1346     TRUE if module is valid, FALSE otherwise
1347
1348 NOTE :
1349     The module lock MUST be owned.
1350
1351 --*/
1352 static BOOL LOADValidateModule(MODSTRUCT *module)
1353 {
1354     MODSTRUCT *modlist_enum = &exe_module;
1355
1356     /* enumerate through the list of modules to make sure the given handle is
1357        really a module (HMODULEs are actually MODSTRUCT pointers) */
1358     do
1359     {
1360         if (module == modlist_enum)
1361         {
1362             /* found it; check its integrity to be on the safe side */
1363             if (module->self != module)
1364             {
1365                 ERROR("Found corrupt module %p!\n",module);
1366                 return FALSE;
1367             }
1368             TRACE("Module %p is valid (name : %S)\n", module, MODNAME(module));
1369             return TRUE;
1370         }
1371         modlist_enum = modlist_enum->next;
1372     }
1373     while (modlist_enum != &exe_module);
1374
1375     TRACE("Module %p is NOT valid.\n", module);
1376     return FALSE;
1377 }
1378
1379 /*++
1380 Function :
1381     LOADGetModuleFileName [internal]
1382
1383     Retrieve the module's full path if it is known, the short name given to
1384     LoadLibrary otherwise.
1385
1386 Parameters :
1387     MODSTRUCT *module : module to check
1388
1389 Return value :
1390     pointer to internal buffer with name of module (Unicode)
1391
1392 Notes :
1393     this function assumes that the module critical section is held, and that
1394     the module has already been validated.
1395 --*/
1396 static LPWSTR LOADGetModuleFileName(MODSTRUCT *module)
1397 {
1398     LPWSTR module_name;
1399     /* special case : if module is NULL, we want the name of the executable */
1400     if (!module)
1401     {
1402         module_name = exe_module.lib_name;
1403         TRACE("Returning name of main executable\n");
1404         return module_name;
1405     }
1406
1407     /* return "real" name of module if it is known. we have this if LoadLibrary
1408        was given an absolute or relative path; we can also determine it at the
1409        first GetProcAddress call. */
1410     TRACE("Returning full path name of module\n");
1411     return module->lib_name;
1412 }
1413
1414 /*
1415 Function:
1416     LOADLoadLibraryDirect [internal]
1417
1418     Loads a library using a system call, without registering the library with the module list.
1419
1420 Parameters:
1421     LPCSTR libraryNameOrPath:           The library to load.
1422
1423 Return value:
1424     System handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1425 */
1426 static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath)
1427 {
1428     _ASSERTE(libraryNameOrPath != nullptr);
1429     _ASSERTE(libraryNameOrPath[0] != '\0');
1430
1431     if (strchr(libraryNameOrPath, '/') != nullptr)
1432     {
1433             if (access(libraryNameOrPath, F_OK) == -1)
1434             {
1435                     SetLastError(ERROR_MOD_NOT_FOUND);
1436                     return (NATIVE_LIBRARY_HANDLE)nullptr;
1437             }
1438     }
1439
1440     NATIVE_LIBRARY_HANDLE dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY);
1441     if (dl_handle == nullptr)
1442     {
1443         SetLastError(ERROR_MOD_NOT_FOUND);
1444     }
1445     else
1446     {
1447         TRACE("dlopen() found module %s\n", libraryNameOrPath);
1448     }
1449
1450     return dl_handle;
1451 }
1452
1453 /*++
1454 Function :
1455     LOADAllocModule
1456
1457     Allocate and initialize a new MODSTRUCT structure
1458
1459 Parameters :
1460     NATIVE_LIBRARY_HANDLE dl_handle :   handle returned by dl_open, goes in MODSTRUCT::dl_handle
1461
1462     char *name :        name of new module. after conversion to widechar,
1463                         goes in MODSTRUCT::lib_name
1464
1465 Return value:
1466     a pointer to a new, initialized MODSTRUCT strucutre, or NULL on failure.
1467
1468 Notes :
1469     'name' is used to initialize MODSTRUCT::lib_name. The other member is set to NULL
1470     In case of failure (in malloc or MBToWC), this function sets LastError.
1471 --*/
1472 static MODSTRUCT *LOADAllocModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR name)
1473 {
1474     MODSTRUCT *module;
1475     LPWSTR wide_name;
1476
1477     /* no match found : try to create a new module structure */
1478     module = (MODSTRUCT *)InternalMalloc(sizeof(MODSTRUCT));
1479     if (nullptr == module)
1480     {
1481         ERROR("malloc() failed! errno is %d (%s)\n", errno, strerror(errno));
1482         return nullptr;
1483     }
1484
1485     wide_name = UTIL_MBToWC_Alloc(name, -1);
1486     if (nullptr == wide_name)
1487     {
1488         ERROR("couldn't convert name to a wide-character string\n");
1489         free(module);
1490         return nullptr;
1491     }
1492
1493     module->dl_handle = dl_handle;
1494 #if NEED_DLCOMPAT
1495     if (isdylib(module))
1496     {
1497         module->refcount = -1;
1498     }
1499     else
1500     {
1501         module->refcount = 1;
1502     }
1503 #else   // NEED_DLCOMPAT
1504     module->refcount = 1;
1505 #endif  // NEED_DLCOMPAT
1506     module->self = module;
1507     module->hinstance = nullptr;
1508     module->threadLibCalls = TRUE;
1509     module->pDllMain = nullptr;
1510     module->next = nullptr;
1511     module->prev = nullptr;
1512
1513     module->lib_name = wide_name;
1514
1515     return module;
1516 }
1517
1518 /*
1519 Function:
1520     LOADAddModule [internal]
1521
1522     Registers a system handle to a loaded library with the module list.
1523
1524 Parameters:
1525     NATIVE_LIBRARY_HANDLE dl_handle:    System handle to the loaded library.
1526     LPCSTR libraryNameOrPath:           The library that was loaded.
1527
1528 Return value:
1529     PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1530 */
1531 static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath)
1532 {
1533     _ASSERTE(dl_handle != nullptr);
1534     _ASSERTE(libraryNameOrPath != nullptr);
1535     _ASSERTE(libraryNameOrPath[0] != '\0');
1536
1537 #if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1538     /* search module list for a match. */
1539     MODSTRUCT *module = &exe_module;
1540     do
1541     {
1542         if (dl_handle == module->dl_handle)
1543         {
1544             /* found the handle. increment the refcount and return the
1545                existing module structure */
1546             TRACE("Found matching module %p for module name %s\n", module, libraryNameOrPath);
1547
1548             if (module->refcount != -1)
1549             {
1550                 module->refcount++;
1551             }
1552             dlclose(dl_handle);
1553             return module;
1554         }
1555         module = module->next;
1556
1557     } while (module != &exe_module);
1558 #endif
1559
1560     TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath);
1561
1562     module = LOADAllocModule(dl_handle, libraryNameOrPath);
1563     if (nullptr == module)
1564     {
1565         ERROR("couldn't create new module\n");
1566         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1567         dlclose(dl_handle);
1568         return nullptr;
1569     }
1570
1571     /* We now get the address of DllMain if the module contains one. */
1572     module->pDllMain = (PDLLMAIN)dlsym(module->dl_handle, "DllMain");
1573
1574     /* Add the new module on to the end of the list */
1575     module->prev = exe_module.prev;
1576     module->next = &exe_module;
1577     exe_module.prev->next = module;
1578     exe_module.prev = module;
1579
1580 #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1581     module->inode = stat_buf.st_ino;
1582     module->device = stat_buf.st_dev;
1583 #endif
1584
1585     return module;
1586 }
1587
1588 /*
1589 Function:
1590     LOADRegisterLibraryDirect [internal]
1591
1592     Registers a system handle to a loaded library with the module list.
1593
1594 Parameters:
1595     NATIVE_LIBRARY_HANDLE dl_handle:    System handle to the loaded library.
1596     LPCSTR libraryNameOrPath:           The library that was loaded.
1597     BOOL fDynamic:                      TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary.
1598
1599 Return value:
1600     PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1601 */
1602 static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic)
1603 {
1604     MODSTRUCT *module = LOADAddModule(dl_handle, libraryNameOrPath);
1605     if (module == nullptr)
1606     {
1607         return nullptr;
1608     }
1609
1610     /* If the module contains a DllMain, call it. */
1611     if (module->pDllMain)
1612     {
1613         TRACE("Calling DllMain (%p) for module %S\n",
1614             module->pDllMain,
1615             module->lib_name ? module->lib_name : W16_NULLSTRING);
1616
1617         if (nullptr == module->hinstance)
1618         {
1619             PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
1620             if (registerModule != nullptr)
1621             {
1622                 module->hinstance = registerModule(libraryNameOrPath);
1623             }
1624             else
1625             {
1626                 // If the target module doesn't have the PAL_RegisterModule export, then use this PAL's
1627                 // module handle assuming that the target module is referencing this PAL's exported
1628                 // functions on said handle.
1629                 module->hinstance = (HINSTANCE)module;
1630             }
1631         }
1632
1633         BOOL dllMainRetVal = LOADCallDllMainSafe(module, DLL_PROCESS_ATTACH, fDynamic ? nullptr : (LPVOID)-1);
1634
1635         // If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module
1636         if (!dllMainRetVal)
1637         {
1638             ERROR("DllMain returned FALSE; unloading module.\n");
1639             module->pDllMain = nullptr;
1640             FreeLibrary((HMODULE)module);
1641             SetLastError(ERROR_DLL_INIT_FAILED);
1642             module = nullptr;
1643         }
1644     }
1645     else
1646     {
1647         TRACE("Module does not contain a DllMain function.\n");
1648     }
1649
1650     return module;
1651 }
1652
1653 /*++
1654 Function :
1655     LOADLoadLibrary [internal]
1656
1657     implementation of LoadLibrary (for use by the A/W variants)
1658
1659 Parameters :
1660     LPSTR shortAsciiName : name of module as specified to LoadLibrary
1661
1662     BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
1663
1664 Return value :
1665     handle to loaded module
1666
1667 --*/
1668 static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
1669 {
1670     HMODULE module = nullptr;
1671     NATIVE_LIBRARY_HANDLE dl_handle = nullptr;
1672
1673     shortAsciiName = FixLibCName(shortAsciiName);
1674
1675     LockModuleList();
1676
1677     dl_handle = LOADLoadLibraryDirect(shortAsciiName);
1678     if (dl_handle)
1679     {
1680         module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic);
1681     }
1682
1683     UnlockModuleList();
1684
1685     return module;
1686 }
1687
1688 /*++
1689     LOADInitializeCoreCLRModule
1690
1691     Run the initialization methods for CoreCLR module (the module containing this PAL).
1692
1693 Parameters:
1694     None
1695
1696 Return value:
1697     TRUE if successful
1698     FALSE if failure
1699 --*/
1700 BOOL LOADInitializeCoreCLRModule()
1701 {
1702     MODSTRUCT *module = LOADGetPalLibrary();
1703     if (!module)
1704     {
1705         ERROR("Can not load the PAL module\n");
1706         return FALSE;
1707     }
1708     PDLLMAIN pRuntimeDllMain = (PDLLMAIN)dlsym(module->dl_handle, "CoreDllMain");
1709     if (!pRuntimeDllMain)
1710     {
1711         ERROR("Can not find the CoreDllMain entry point\n");
1712         return FALSE;
1713     }
1714     return pRuntimeDllMain(module->hinstance, DLL_PROCESS_ATTACH, nullptr);
1715 }
1716
1717 /*++
1718 Function :
1719     LOADGetPalLibrary
1720
1721     Load and initialize the PAL module.
1722
1723 Parameters :
1724     None
1725
1726 Return value :
1727     pointer to module struct
1728
1729 --*/
1730 MODSTRUCT *LOADGetPalLibrary()
1731 {
1732     if (pal_module == nullptr)
1733     {
1734         // Initialize the pal module (the module containing LOADGetPalLibrary). Assumes that
1735         // the PAL is linked into the coreclr module because we use the module name containing
1736         // this function for the coreclr path.
1737         TRACE("Loading module for PAL library\n");
1738
1739         Dl_info info;
1740         if (dladdr((PVOID)&LOADGetPalLibrary, &info) == 0)
1741         {
1742             ERROR("LOADGetPalLibrary: dladdr() failed.\n");
1743             goto exit;
1744         }
1745         // Stash a copy of the CoreCLR installation path in a global variable.
1746         // Make sure it's terminated with a slash.
1747         if (g_szCoreCLRPath == nullptr)
1748         {
1749             size_t  cbszCoreCLRPath = strlen(info.dli_fname) + 1;
1750             g_szCoreCLRPath = (char*) InternalMalloc(cbszCoreCLRPath);
1751
1752             if (g_szCoreCLRPath == nullptr)
1753             {
1754                 ERROR("LOADGetPalLibrary: InternalMalloc failed!");
1755                 goto exit;
1756             }
1757
1758             if (strcpy_s(g_szCoreCLRPath, cbszCoreCLRPath, info.dli_fname) != SAFECRT_SUCCESS)
1759             {
1760                 ERROR("LOADGetPalLibrary: strcpy_s failed!");
1761                 goto exit;
1762             }
1763         }
1764
1765         pal_module = (MODSTRUCT *)LOADLoadLibrary(info.dli_fname, FALSE);
1766     }
1767
1768 exit:
1769     return pal_module;
1770 }
1771
1772 /*++
1773 Function:
1774   LockModuleList
1775
1776 Abstract
1777   Enter the critical section associated to the module list
1778
1779 Parameter
1780   void
1781
1782 Return
1783   void
1784 --*/
1785 extern "C"
1786 void LockModuleList()
1787 {
1788     CPalThread * pThread =
1789         (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1790
1791     InternalEnterCriticalSection(pThread, &module_critsec);
1792 }
1793
1794 /*++
1795 Function:
1796   UnlockModuleList
1797
1798 Abstract
1799   Leave the critical section associated to the module list
1800
1801 Parameter
1802   void
1803
1804 Return
1805   void
1806 --*/
1807 extern "C"
1808 void UnlockModuleList()
1809 {
1810     CPalThread * pThread =
1811         (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1812
1813     InternalLeaveCriticalSection(pThread, &module_critsec);
1814 }