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
9Module Name:
10
11 module.c
12
13Abstract:
14
15 Implementation of module related functions in the Win32 API
16
17
18
19--*/
20
21#include "pal/dbgmsg.h"
22SET_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
63using 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 */
87CRITICAL_SECTION module_critsec;
88
89/* always the first, in the in-load-order list */
90MODSTRUCT exe_module;
91MODSTRUCT *pal_module = nullptr;
92
93char * g_szCoreCLRPath = nullptr;
94
95int MaxWCharToAcpLength = 3;
96
97/* static function declarations ***********************************************/
98
99template<class TChar> static bool LOADVerifyLibraryPath(const TChar *libraryPath);
100static bool LOADConvertLibraryPathWideStringToMultibyteString(
101 LPCWSTR wideLibraryPath,
102 LPSTR multibyteLibraryPath,
103 INT *multibyteLibraryPathLengthRef);
104static BOOL LOADValidateModule(MODSTRUCT *module);
105static LPWSTR LOADGetModuleFileName(MODSTRUCT *module);
106static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath);
107static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath);
108static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain);
109static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic);
110static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic);
111static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved);
112
113/* API function definitions ***************************************************/
114
115/*++
116Function:
117 LoadLibraryA
118
119See MSDN doc.
120--*/
121HMODULE
122PALAPI
123LoadLibraryA(
124 IN LPCSTR lpLibFileName)
125{
126 return LoadLibraryExA(lpLibFileName, nullptr, 0);
127}
128
129/*++
130Function:
131 LoadLibraryW
132
133See MSDN doc.
134--*/
135HMODULE
136PALAPI
137LoadLibraryW(
138 IN LPCWSTR lpLibFileName)
139{
140 return LoadLibraryExW(lpLibFileName, nullptr, 0);
141}
142
143/*++
144Function:
145LoadLibraryExA
146
147See MSDN doc.
148--*/
149HMODULE
150PALAPI
151LoadLibraryExA(
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/*++
202Function:
203LoadLibraryExW
204
205See MSDN doc.
206--*/
207HMODULE
208PALAPI
209LoadLibraryExW(
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
253done:
254 LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
255 PERF_EXIT(LoadLibraryExW);
256 return hModule;
257}
258
259/*++
260Function:
261 GetProcAddress
262
263See MSDN doc.
264--*/
265FARPROC
266PALAPI
267GetProcAddress(
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 }
374done:
375 UnlockModuleList();
376 LOGEXIT("GetProcAddress returns FARPROC %p\n", ProcAddress);
377 PERF_EXIT(GetProcAddress);
378 return ProcAddress;
379}
380
381/*++
382Function:
383 FreeLibrary
384
385See MSDN doc.
386--*/
387BOOL
388PALAPI
389FreeLibrary(
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/*++
405Function:
406 FreeLibraryAndExitThread
407
408See MSDN doc.
409
410--*/
411PALIMPORT
412VOID
413PALAPI
414FreeLibraryAndExitThread(
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/*++
427Function:
428 GetModuleFileNameA
429
430See MSDN doc.
431
432Notes :
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--*/
439DWORD
440PALAPI
441GetModuleFileNameA(
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;
483done:
484 UnlockModuleList();
485 LOGEXIT("GetModuleFileNameA returns DWORD %d\n", retval);
486 PERF_EXIT(GetModuleFileNameA);
487 return retval;
488}
489
490/*++
491Function:
492 GetModuleFileNameW
493
494See MSDN doc.
495
496Notes :
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--*/
503DWORD
504PALAPI
505GetModuleFileNameW(
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;
552done:
553 UnlockModuleList();
554 LOGEXIT("GetModuleFileNameW returns DWORD %u\n", retval);
555 PERF_EXIT(GetModuleFileNameW);
556 return retval;
557}
558
559LPCSTR 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/*
587Function:
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*/
594NATIVE_LIBRARY_HANDLE
595PALAPI
596PAL_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
632done:
633 LOGEXIT("LoadLibraryDirect returns NATIVE_LIBRARY_HANDLE %p\n", dl_handle);
634 PERF_EXIT(LoadLibraryDirect);
635 return dl_handle;
636}
637
638/*
639Function:
640 PAL_RegisterLibraryDirect
641
642 Registers a system handle to a loaded library with the module list.
643
644 Returns a PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
645*/
646HMODULE
647PALAPI
648PAL_RegisterLibraryDirect(
649 IN NATIVE_LIBRARY_HANDLE dl_handle,
650 IN LPCWSTR lpLibFileName)
651{
652 PathCharString pathstr;
653 CHAR * lpstr = nullptr;
654 INT name_length;
655 HMODULE hModule = nullptr;
656
657 PERF_ENTRY(RegisterLibraryDirect);
658 ENTRY("RegisterLibraryDirect (lpLibFileName=%p (%S)) \n",
659 lpLibFileName ? lpLibFileName : W16_NULLSTRING,
660 lpLibFileName ? lpLibFileName : W16_NULLSTRING);
661
662 if (!LOADVerifyLibraryPath(lpLibFileName))
663 {
664 goto done;
665 }
666
667 lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
668 if (nullptr == lpstr)
669 {
670 goto done;
671 }
672 if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
673 {
674 goto done;
675 }
676
677 /* do the Dos/Unix conversion on our own copy of the name */
678 FILEDosToUnixPathA(lpstr);
679 pathstr.CloseBuffer(name_length);
680
681 /* let LOADRegisterLibraryDirect call SetLastError in case of failure */
682 LockModuleList();
683 hModule = LOADRegisterLibraryDirect(dl_handle, lpstr, true /* fDynamic */);
684 UnlockModuleList();
685
686done:
687 LOGEXIT("RegisterLibraryDirect returns HMODULE %p\n", hModule);
688 PERF_EXIT(RegisterLibraryDirect);
689 return hModule;
690}
691
692/*
693Function:
694 PAL_FreeLibraryDirect
695
696 Free a loaded library
697
698 Returns true on success, false on failure.
699*/
700BOOL
701PALAPI
702PAL_FreeLibraryDirect(
703 IN NATIVE_LIBRARY_HANDLE dl_handle)
704{
705 BOOL retValue = 0;
706 PERF_ENTRY(PAL_FreeLibraryDirect);
707 ENTRY("PAL_FreeLibraryDirect (dl_handle=%p) \n", dl_handle);
708
709 retValue = dlclose(dl_handle) == 0;
710
711 LOGEXIT("PAL_FreeLibraryDirect returns BOOL %p\n", retValue);
712 PERF_EXIT(PAL_FreeLibraryDirect);
713 return retValue;
714}
715
716/*
717Function:
718 PAL_GetProcAddressDirect
719
720 Get the address corresponding to a symbol in a loaded native library.
721
722 Returns the address of the sumbol loaded in memory.
723*/
724FARPROC
725PALAPI
726PAL_GetProcAddressDirect(
727 IN NATIVE_LIBRARY_HANDLE dl_handle,
728 IN LPCSTR lpProcName)
729{
730 INT name_length;
731 FARPROC address = nullptr;
732
733 PERF_ENTRY(PAL_GetProcAddressDirect);
734 ENTRY("PAL_GetProcAddressDirect (lpLibFileName=%p (%S)) \n",
735 lpProcName ? lpProcName : "NULL",
736 lpProcName ? lpProcName : "NULL");
737
738 address = (FARPROC) dlsym(dl_handle, lpProcName);
739
740 LOGEXIT("PAL_GetProcAddressDirect returns FARPROC %p\n", address);
741 PERF_EXIT(PAL_GetProcAddressDirect);
742 return address;
743}
744
745/*++
746Function:
747 PAL_RegisterModule
748
749 Register the module with the target module and return a module handle in
750 the target module's context. Doesn't call the DllMain because it is used
751 as part of calling DllMain in the calling module.
752
753--*/
754HINSTANCE
755PALAPI
756PAL_RegisterModule(
757 IN LPCSTR lpLibFileName)
758{
759 HINSTANCE hinstance = nullptr;
760
761 int err = PAL_InitializeDLL();
762 if (err == 0)
763 {
764 PERF_ENTRY(PAL_RegisterModule);
765 ENTRY("PAL_RegisterModule(%s)\n", lpLibFileName ? lpLibFileName : "");
766
767 LockModuleList();
768
769 NATIVE_LIBRARY_HANDLE dl_handle = LOADLoadLibraryDirect(lpLibFileName);
770 if (dl_handle)
771 {
772 // This only creates/adds the module handle and doesn't call DllMain
773 hinstance = LOADAddModule(dl_handle, lpLibFileName);
774 }
775
776 UnlockModuleList();
777
778 LOGEXIT("PAL_RegisterModule returns HINSTANCE %p\n", hinstance);
779 PERF_EXIT(PAL_RegisterModule);
780 }
781
782 return hinstance;
783}
784
785/*++
786Function:
787 PAL_UnregisterModule
788
789 Used to cleanup the module HINSTANCE from PAL_RegisterModule.
790--*/
791VOID
792PALAPI
793PAL_UnregisterModule(
794 IN HINSTANCE hInstance)
795{
796 PERF_ENTRY(PAL_UnregisterModule);
797 ENTRY("PAL_UnregisterModule(hInstance=%p)\n", hInstance);
798
799 LOADFreeLibrary((MODSTRUCT *)hInstance, FALSE /* fCallDllMain */);
800
801 LOGEXIT("PAL_UnregisterModule returns\n");
802 PERF_EXIT(PAL_UnregisterModule);
803}
804
805/*++
806 PAL_LOADLoadPEFile
807
808 Map a PE format file into memory like Windows LoadLibrary() would do.
809 Doesn't apply base relocations if the function is relocated.
810
811Parameters:
812 IN hFile - file to map
813
814Return value:
815 non-NULL - the base address of the mapped image
816 NULL - error, with last error set.
817--*/
818void *
819PALAPI
820PAL_LOADLoadPEFile(HANDLE hFile)
821{
822 ENTRY("PAL_LOADLoadPEFile (hFile=%p)\n", hFile);
823
824 void * loadedBase = MAPMapPEFile(hFile);
825
826#ifdef _DEBUG
827 if (loadedBase != nullptr)
828 {
829 char* envVar = EnvironGetenv("PAL_ForcePEMapFailure");
830 if (envVar)
831 {
832 if (strlen(envVar) > 0)
833 {
834 TRACE("Forcing failure of PE file map, and retry\n");
835 PAL_LOADUnloadPEFile(loadedBase); // unload it
836 loadedBase = MAPMapPEFile(hFile); // load it again
837 }
838
839 free(envVar);
840 }
841 }
842#endif // _DEBUG
843
844 LOGEXIT("PAL_LOADLoadPEFile returns %p\n", loadedBase);
845 return loadedBase;
846}
847
848/*++
849 PAL_LOADUnloadPEFile
850
851 Unload a PE file that was loaded by PAL_LOADLoadPEFile().
852
853Parameters:
854 IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
855
856Return value:
857 TRUE - success
858 FALSE - failure (incorrect ptr, etc.)
859--*/
860BOOL
861PALAPI
862PAL_LOADUnloadPEFile(void * ptr)
863{
864 BOOL retval = FALSE;
865
866 ENTRY("PAL_LOADUnloadPEFile (ptr=%p)\n", ptr);
867
868 if (nullptr == ptr)
869 {
870 ERROR( "Invalid pointer value\n" );
871 }
872 else
873 {
874 retval = MAPUnmapPEFile(ptr);
875 }
876
877 LOGEXIT("PAL_LOADUnloadPEFile returns %d\n", retval);
878 return retval;
879}
880
881/*++
882 PAL_GetSymbolModuleBase
883
884 Get base address of the module containing a given symbol
885
886Parameters:
887 void *symbol - address of symbol
888
889Return value:
890 module base address
891--*/
892LPCVOID
893PALAPI
894PAL_GetSymbolModuleBase(void *symbol)
895{
896 LPCVOID retval = nullptr;
897
898 PERF_ENTRY(PAL_GetPalModuleBase);
899 ENTRY("PAL_GetPalModuleBase\n");
900
901 if (symbol == nullptr)
902 {
903 TRACE("Can't get base address. Argument symbol == nullptr\n");
904 SetLastError(ERROR_INVALID_DATA);
905 }
906 else
907 {
908 Dl_info info;
909 if (dladdr(symbol, &info) != 0)
910 {
911 retval = info.dli_fbase;
912 }
913 else
914 {
915 TRACE("Can't get base address of the current module\n");
916 SetLastError(ERROR_INVALID_DATA);
917 }
918 }
919
920 LOGEXIT("PAL_GetPalModuleBase returns %p\n", retval);
921 PERF_EXIT(PAL_GetPalModuleBase);
922 return retval;
923}
924
925/*++
926 PAL_GetLoadLibraryError
927
928 Wrapper for dlerror() to be used by PAL functions
929
930Return value:
931
932A LPCSTR containing the output of dlerror()
933
934--*/
935PALIMPORT
936LPCSTR
937PALAPI
938PAL_GetLoadLibraryError()
939{
940
941 PERF_ENTRY(PAL_GetLoadLibraryError);
942 ENTRY("PAL_GetLoadLibraryError");
943
944 LPCSTR last_error = dlerror();
945
946 LOGEXIT("PAL_GetLoadLibraryError returns %p\n", last_error);
947 PERF_EXIT(PAL_GetLoadLibraryError);
948 return last_error;
949}
950
951
952/* Internal PAL functions *****************************************************/
953
954/*++
955Function :
956 LOADInitializeModules
957
958 Initialize the process-wide list of modules
959
960Parameters :
961 None
962
963Return value :
964 TRUE if initialization succeedded
965 FALSE otherwise
966
967--*/
968extern "C"
969BOOL LOADInitializeModules()
970{
971 _ASSERTE(exe_module.prev == nullptr);
972
973 InternalInitializeCriticalSection(&module_critsec);
974
975 // Initialize module for main executable
976 TRACE("Initializing module for main executable\n");
977
978 exe_module.self = (HMODULE)&exe_module;
979 exe_module.dl_handle = dlopen(nullptr, RTLD_LAZY);
980 if (exe_module.dl_handle == nullptr)
981 {
982 ERROR("Executable module will be broken : dlopen(nullptr) failed\n");
983 return FALSE;
984 }
985 exe_module.lib_name = nullptr;
986 exe_module.refcount = -1;
987 exe_module.next = &exe_module;
988 exe_module.prev = &exe_module;
989 exe_module.pDllMain = nullptr;
990 exe_module.hinstance = nullptr;
991 exe_module.threadLibCalls = TRUE;
992 return TRUE;
993}
994
995/*++
996Function :
997 LOADSetExeName
998
999 Set the exe name path
1000
1001Parameters :
1002 LPWSTR man exe path and name
1003
1004Return value :
1005 TRUE if initialization succeedded
1006 FALSE otherwise
1007
1008--*/
1009extern "C"
1010BOOL LOADSetExeName(LPWSTR name)
1011{
1012#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1013 LPSTR pszExeName = nullptr;
1014#endif
1015 BOOL result = FALSE;
1016
1017 LockModuleList();
1018
1019 // Save the exe path in the exe module struct
1020 free(exe_module.lib_name);
1021 exe_module.lib_name = name;
1022
1023 // For platforms where we can't trust the handle to be constant, we need to
1024 // store the inode/device pairs for the modules we just initialized.
1025#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1026 {
1027 struct stat stat_buf;
1028 pszExeName = UTIL_WCToMB_Alloc(name, -1);
1029 if (nullptr == pszExeName)
1030 {
1031 ERROR("WCToMB failure, unable to get full name of exe\n");
1032 goto exit;
1033 }
1034 if (-1 == stat(pszExeName, &stat_buf))
1035 {
1036 SetLastError(ERROR_MOD_NOT_FOUND);
1037 goto exit;
1038 }
1039 TRACE("Executable has inode %d and device %d\n", stat_buf.st_ino, stat_buf.st_dev);
1040
1041 exe_module.inode = stat_buf.st_ino;
1042 exe_module.device = stat_buf.st_dev;
1043 }
1044#endif
1045 result = TRUE;
1046
1047#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1048exit:
1049 if (pszExeName)
1050 {
1051 free(pszExeName);
1052 }
1053#endif
1054 UnlockModuleList();
1055 return result;
1056}
1057
1058/*++
1059Function :
1060 LOADCallDllMain
1061
1062 Call DllMain for all modules (that have one) with the given "fwReason"
1063
1064Parameters :
1065 DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1066 DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1067
1068 LPVOID lpReserved : parameter to pass down to DllMain
1069 If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1070 If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1071 and non-NULL if DllMain has been called during process termination.
1072
1073(no return value)
1074
1075Notes :
1076 This is used to send DLL_THREAD_*TACH messages to modules
1077--*/
1078extern "C"
1079void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
1080{
1081 MODSTRUCT *module = nullptr;
1082 BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */
1083 CPalThread *pThread;
1084
1085 pThread = InternalGetCurrentThread();
1086 if (UserCreatedThread != pThread->GetThreadType())
1087 {
1088 return;
1089 }
1090
1091 /* Validate dwReason */
1092 switch(dwReason)
1093 {
1094 case DLL_PROCESS_ATTACH:
1095 ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n");
1096 break;
1097 case DLL_PROCESS_DETACH:
1098 ASSERT("got called with DLL_PROCESS_DETACH parameter! Why?\n");
1099 InLoadOrder = FALSE;
1100 break;
1101 case DLL_THREAD_ATTACH:
1102 TRACE("Calling DllMain(DLL_THREAD_ATTACH) on all known modules.\n");
1103 break;
1104 case DLL_THREAD_DETACH:
1105 TRACE("Calling DllMain(DLL_THREAD_DETACH) on all known modules.\n");
1106 InLoadOrder = FALSE;
1107 break;
1108 default:
1109 ASSERT("LOADCallDllMain called with unknown parameter %d!\n", dwReason);
1110 return;
1111 }
1112
1113 LockModuleList();
1114
1115 module = &exe_module;
1116
1117 do
1118 {
1119 if (!InLoadOrder)
1120 module = module->prev;
1121
1122 if (module->threadLibCalls)
1123 {
1124 if (module->pDllMain)
1125 {
1126 LOADCallDllMainSafe(module, dwReason, lpReserved);
1127 }
1128 }
1129
1130 if (InLoadOrder)
1131 module = module->next;
1132
1133 } while (module != &exe_module);
1134
1135 UnlockModuleList();
1136}
1137
1138/*++
1139Function:
1140 LOADFreeLibrary
1141
1142Parameters:
1143 MODSTRUCT * module - module to free
1144 BOOL fCallDllMain - if TRUE, call the DllMain function
1145
1146Returns:
1147 TRUE if successful
1148
1149--*/
1150static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain)
1151{
1152 BOOL retval = FALSE;
1153
1154 LockModuleList();
1155
1156 if (terminator)
1157 {
1158 /* PAL shutdown is in progress - ignore FreeLibrary calls */
1159 retval = TRUE;
1160 goto done;
1161 }
1162
1163 if (!LOADValidateModule(module))
1164 {
1165 TRACE("Can't free invalid module %p\n", module);
1166 SetLastError(ERROR_INVALID_HANDLE);
1167 goto done;
1168 }
1169
1170 if (module->refcount == -1)
1171 {
1172 /* special module - never released */
1173 retval = TRUE;
1174 goto done;
1175 }
1176
1177 module->refcount--;
1178 TRACE("Reference count for module %p (named %S) decreases to %d\n",
1179 module, MODNAME(module), module->refcount);
1180
1181 if (module->refcount != 0)
1182 {
1183 retval = TRUE;
1184 goto done;
1185 }
1186
1187 /* Releasing the last reference : call dlclose(), remove module from the
1188 process-wide module list */
1189
1190 TRACE("Reference count for module %p (named %S) now 0; destroying module structure\n",
1191 module, MODNAME(module));
1192
1193 /* unlink the module structure from the list */
1194 module->prev->next = module->next;
1195 module->next->prev = module->prev;
1196
1197 /* remove the circular reference so that LOADValidateModule will fail */
1198 module->self = nullptr;
1199
1200 /* Call DllMain if the module contains one */
1201 if (fCallDllMain && module->pDllMain)
1202 {
1203 LOADCallDllMainSafe(module, DLL_PROCESS_DETACH, nullptr);
1204 }
1205
1206 if (module->hinstance)
1207 {
1208 PUNREGISTER_MODULE unregisterModule = (PUNREGISTER_MODULE)dlsym(module->dl_handle, "PAL_UnregisterModule");
1209 if (unregisterModule != nullptr)
1210 {
1211 unregisterModule(module->hinstance);
1212 }
1213 module->hinstance = nullptr;
1214 }
1215
1216 if (module->dl_handle && 0 != dlclose(module->dl_handle))
1217 {
1218 /* report dlclose() failure, but proceed anyway. */
1219 WARN("dlclose() call failed!\n");
1220 }
1221
1222 /* release all memory */
1223 free(module->lib_name);
1224 free(module);
1225
1226 retval = TRUE;
1227
1228done:
1229 UnlockModuleList();
1230 return retval;
1231}
1232
1233/*++
1234Function :
1235 LOADCallDllMainSafe
1236
1237 Exception-safe call to DllMain.
1238
1239Parameters :
1240 MODSTRUCT *module : module whose DllMain must be called
1241
1242 DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
1243 DLL_THREAD_ATTACH, DLL_THREAD_DETACH
1244
1245 LPVOID lpvReserved : parameter to pass down to DllMain,
1246 If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
1247 If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
1248 and non-NULL if DllMain has been called during process termination.
1249
1250Returns:
1251 BOOL : DllMain's return value
1252*/
1253static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved)
1254{
1255#if _ENABLE_DEBUG_MESSAGES_
1256 /* reset ENTRY nesting level back to zero while inside the callback... */
1257 int old_level = DBG_change_entrylevel(0);
1258#endif /* _ENABLE_DEBUG_MESSAGES_ */
1259
1260 struct Param
1261 {
1262 MODSTRUCT *module;
1263 DWORD dwReason;
1264 LPVOID lpReserved;
1265 BOOL ret;
1266 } param;
1267 param.module = module;
1268 param.dwReason = dwReason;
1269 param.lpReserved = lpReserved;
1270 param.ret = FALSE;
1271
1272 PAL_TRY(Param *, pParam, &param)
1273 {
1274 TRACE("Calling DllMain (%p) for module %S\n",
1275 pParam->module->pDllMain,
1276 pParam->module->lib_name ? pParam->module->lib_name : W16_NULLSTRING);
1277
1278 {
1279 // This module may be foreign to our PAL, so leave our PAL.
1280 // If it depends on us, it will re-enter.
1281 PAL_LeaveHolder holder;
1282 pParam->ret = pParam->module->pDllMain(pParam->module->hinstance, pParam->dwReason, pParam->lpReserved);
1283 }
1284 }
1285 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1286 {
1287 WARN("Call to DllMain (%p) got an unhandled exception; ignoring.\n", module->pDllMain);
1288 }
1289 PAL_ENDTRY
1290
1291#if _ENABLE_DEBUG_MESSAGES_
1292 /* ...and set nesting level back to what it was */
1293 DBG_change_entrylevel(old_level);
1294#endif /* _ENABLE_DEBUG_MESSAGES_ */
1295
1296 return param.ret;
1297}
1298
1299/*++
1300Function:
1301 DisableThreadLibraryCalls
1302
1303See MSDN doc.
1304--*/
1305BOOL
1306PALAPI
1307DisableThreadLibraryCalls(
1308 IN HMODULE hLibModule)
1309{
1310 BOOL ret = FALSE;
1311 MODSTRUCT *module;
1312 PERF_ENTRY(DisableThreadLibraryCalls);
1313 ENTRY("DisableThreadLibraryCalls(hLibModule=%p)\n", hLibModule);
1314
1315 LockModuleList();
1316
1317 if (terminator)
1318 {
1319 /* PAL shutdown in progress - ignore DisableThreadLibraryCalls */
1320 ret = TRUE;
1321 goto done;
1322 }
1323
1324 module = (MODSTRUCT *) hLibModule;
1325
1326 if (!LOADValidateModule(module))
1327 {
1328 // DisableThreadLibraryCalls() does nothing when given
1329 // an invalid module handle. This matches the Windows
1330 // behavior, though it is counter to MSDN.
1331 WARN("Invalid module handle %p\n", hLibModule);
1332 ret = TRUE;
1333 goto done;
1334 }
1335
1336 module->threadLibCalls = FALSE;
1337 ret = TRUE;
1338
1339done:
1340 UnlockModuleList();
1341 LOGEXIT("DisableThreadLibraryCalls returns BOOL %d\n", ret);
1342 PERF_EXIT(DisableThreadLibraryCalls);
1343 return ret;
1344}
1345
1346// Checks the library path for null or empty string. On error, calls SetLastError() and returns false.
1347template<class TChar>
1348static bool LOADVerifyLibraryPath(const TChar *libraryPath)
1349{
1350 if (libraryPath == nullptr)
1351 {
1352 ERROR("libraryPath is null\n");
1353 SetLastError(ERROR_MOD_NOT_FOUND);
1354 return false;
1355 }
1356 if (libraryPath[0] == '\0')
1357 {
1358 ERROR("libraryPath is empty\n");
1359 SetLastError(ERROR_INVALID_PARAMETER);
1360 return false;
1361 }
1362 return true;
1363}
1364
1365// Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false.
1366static bool LOADConvertLibraryPathWideStringToMultibyteString(
1367 LPCWSTR wideLibraryPath,
1368 LPSTR multibyteLibraryPath,
1369 INT *multibyteLibraryPathLengthRef)
1370{
1371 _ASSERTE(multibyteLibraryPathLengthRef != nullptr);
1372 _ASSERTE(wideLibraryPath != nullptr);
1373
1374 size_t length = (PAL_wcslen(wideLibraryPath)+1) * MaxWCharToAcpLength;
1375 *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath,
1376 length, nullptr, nullptr);
1377
1378 if (*multibyteLibraryPathLengthRef == 0)
1379 {
1380 DWORD dwLastError = GetLastError();
1381
1382 ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
1383
1384 SetLastError(ERROR_INVALID_PARAMETER);
1385 return false;
1386 }
1387 return true;
1388}
1389
1390/*++
1391Function :
1392 LOADValidateModule
1393
1394 Check whether the given MODSTRUCT pointer is valid
1395
1396Parameters :
1397 MODSTRUCT *module : module to check
1398
1399Return value :
1400 TRUE if module is valid, FALSE otherwise
1401
1402NOTE :
1403 The module lock MUST be owned.
1404
1405--*/
1406static BOOL LOADValidateModule(MODSTRUCT *module)
1407{
1408 MODSTRUCT *modlist_enum = &exe_module;
1409
1410 /* enumerate through the list of modules to make sure the given handle is
1411 really a module (HMODULEs are actually MODSTRUCT pointers) */
1412 do
1413 {
1414 if (module == modlist_enum)
1415 {
1416 /* found it; check its integrity to be on the safe side */
1417 if (module->self != module)
1418 {
1419 ERROR("Found corrupt module %p!\n",module);
1420 return FALSE;
1421 }
1422 TRACE("Module %p is valid (name : %S)\n", module, MODNAME(module));
1423 return TRUE;
1424 }
1425 modlist_enum = modlist_enum->next;
1426 }
1427 while (modlist_enum != &exe_module);
1428
1429 TRACE("Module %p is NOT valid.\n", module);
1430 return FALSE;
1431}
1432
1433/*++
1434Function :
1435 LOADGetModuleFileName [internal]
1436
1437 Retrieve the module's full path if it is known, the short name given to
1438 LoadLibrary otherwise.
1439
1440Parameters :
1441 MODSTRUCT *module : module to check
1442
1443Return value :
1444 pointer to internal buffer with name of module (Unicode)
1445
1446Notes :
1447 this function assumes that the module critical section is held, and that
1448 the module has already been validated.
1449--*/
1450static LPWSTR LOADGetModuleFileName(MODSTRUCT *module)
1451{
1452 LPWSTR module_name;
1453 /* special case : if module is NULL, we want the name of the executable */
1454 if (!module)
1455 {
1456 module_name = exe_module.lib_name;
1457 TRACE("Returning name of main executable\n");
1458 return module_name;
1459 }
1460
1461 /* return "real" name of module if it is known. we have this if LoadLibrary
1462 was given an absolute or relative path; we can also determine it at the
1463 first GetProcAddress call. */
1464 TRACE("Returning full path name of module\n");
1465 return module->lib_name;
1466}
1467
1468/*
1469Function:
1470 LOADLoadLibraryDirect [internal]
1471
1472 Loads a library using a system call, without registering the library with the module list.
1473
1474Parameters:
1475 LPCSTR libraryNameOrPath: The library to load.
1476
1477Return value:
1478 System handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1479*/
1480static NATIVE_LIBRARY_HANDLE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath)
1481{
1482 _ASSERTE(libraryNameOrPath != nullptr);
1483 _ASSERTE(libraryNameOrPath[0] != '\0');
1484
1485 NATIVE_LIBRARY_HANDLE dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY);
1486 if (dl_handle == nullptr)
1487 {
1488 SetLastError(ERROR_MOD_NOT_FOUND);
1489 }
1490 else
1491 {
1492 TRACE("dlopen() found module %s\n", libraryNameOrPath);
1493 }
1494
1495 return dl_handle;
1496}
1497
1498/*++
1499Function :
1500 LOADAllocModule
1501
1502 Allocate and initialize a new MODSTRUCT structure
1503
1504Parameters :
1505 NATIVE_LIBRARY_HANDLE dl_handle : handle returned by dl_open, goes in MODSTRUCT::dl_handle
1506
1507 char *name : name of new module. after conversion to widechar,
1508 goes in MODSTRUCT::lib_name
1509
1510Return value:
1511 a pointer to a new, initialized MODSTRUCT strucutre, or NULL on failure.
1512
1513Notes :
1514 'name' is used to initialize MODSTRUCT::lib_name. The other member is set to NULL
1515 In case of failure (in malloc or MBToWC), this function sets LastError.
1516--*/
1517static MODSTRUCT *LOADAllocModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR name)
1518{
1519 MODSTRUCT *module;
1520 LPWSTR wide_name;
1521
1522 /* no match found : try to create a new module structure */
1523 module = (MODSTRUCT *)InternalMalloc(sizeof(MODSTRUCT));
1524 if (nullptr == module)
1525 {
1526 ERROR("malloc() failed! errno is %d (%s)\n", errno, strerror(errno));
1527 return nullptr;
1528 }
1529
1530 wide_name = UTIL_MBToWC_Alloc(name, -1);
1531 if (nullptr == wide_name)
1532 {
1533 ERROR("couldn't convert name to a wide-character string\n");
1534 free(module);
1535 return nullptr;
1536 }
1537
1538 module->dl_handle = dl_handle;
1539#if NEED_DLCOMPAT
1540 if (isdylib(module))
1541 {
1542 module->refcount = -1;
1543 }
1544 else
1545 {
1546 module->refcount = 1;
1547 }
1548#else // NEED_DLCOMPAT
1549 module->refcount = 1;
1550#endif // NEED_DLCOMPAT
1551 module->self = module;
1552 module->hinstance = nullptr;
1553 module->threadLibCalls = TRUE;
1554 module->pDllMain = nullptr;
1555 module->next = nullptr;
1556 module->prev = nullptr;
1557
1558 module->lib_name = wide_name;
1559
1560 return module;
1561}
1562
1563/*
1564Function:
1565 LOADAddModule [internal]
1566
1567 Registers a system handle to a loaded library with the module list.
1568
1569Parameters:
1570 NATIVE_LIBRARY_HANDLE dl_handle: System handle to the loaded library.
1571 LPCSTR libraryNameOrPath: The library that was loaded.
1572
1573Return value:
1574 PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1575*/
1576static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath)
1577{
1578 _ASSERTE(dl_handle != nullptr);
1579 _ASSERTE(libraryNameOrPath != nullptr);
1580 _ASSERTE(libraryNameOrPath[0] != '\0');
1581
1582#if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1583 /* search module list for a match. */
1584 MODSTRUCT *module = &exe_module;
1585 do
1586 {
1587 if (dl_handle == module->dl_handle)
1588 {
1589 /* found the handle. increment the refcount and return the
1590 existing module structure */
1591 TRACE("Found matching module %p for module name %s\n", module, libraryNameOrPath);
1592
1593 if (module->refcount != -1)
1594 {
1595 module->refcount++;
1596 }
1597 dlclose(dl_handle);
1598 return module;
1599 }
1600 module = module->next;
1601
1602 } while (module != &exe_module);
1603#endif
1604
1605 TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath);
1606
1607 module = LOADAllocModule(dl_handle, libraryNameOrPath);
1608 if (nullptr == module)
1609 {
1610 ERROR("couldn't create new module\n");
1611 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1612 dlclose(dl_handle);
1613 return nullptr;
1614 }
1615
1616 /* We now get the address of DllMain if the module contains one. */
1617 module->pDllMain = (PDLLMAIN)dlsym(module->dl_handle, "DllMain");
1618
1619 /* Add the new module on to the end of the list */
1620 module->prev = exe_module.prev;
1621 module->next = &exe_module;
1622 exe_module.prev->next = module;
1623 exe_module.prev = module;
1624
1625#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
1626 module->inode = stat_buf.st_ino;
1627 module->device = stat_buf.st_dev;
1628#endif
1629
1630 return module;
1631}
1632
1633/*
1634Function:
1635 LOADRegisterLibraryDirect [internal]
1636
1637 Registers a system handle to a loaded library with the module list.
1638
1639Parameters:
1640 NATIVE_LIBRARY_HANDLE dl_handle: System handle to the loaded library.
1641 LPCSTR libraryNameOrPath: The library that was loaded.
1642 BOOL fDynamic: TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary.
1643
1644Return value:
1645 PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
1646*/
1647static HMODULE LOADRegisterLibraryDirect(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic)
1648{
1649 MODSTRUCT *module = LOADAddModule(dl_handle, libraryNameOrPath);
1650 if (module == nullptr)
1651 {
1652 return nullptr;
1653 }
1654
1655 /* If the module contains a DllMain, call it. */
1656 if (module->pDllMain)
1657 {
1658 TRACE("Calling DllMain (%p) for module %S\n",
1659 module->pDllMain,
1660 module->lib_name ? module->lib_name : W16_NULLSTRING);
1661
1662 if (nullptr == module->hinstance)
1663 {
1664 PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
1665 if (registerModule != nullptr)
1666 {
1667 module->hinstance = registerModule(libraryNameOrPath);
1668 }
1669 else
1670 {
1671 // If the target module doesn't have the PAL_RegisterModule export, then use this PAL's
1672 // module handle assuming that the target module is referencing this PAL's exported
1673 // functions on said handle.
1674 module->hinstance = (HINSTANCE)module;
1675 }
1676 }
1677
1678 BOOL dllMainRetVal = LOADCallDllMainSafe(module, DLL_PROCESS_ATTACH, fDynamic ? nullptr : (LPVOID)-1);
1679
1680 // If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module
1681 if (!dllMainRetVal)
1682 {
1683 ERROR("DllMain returned FALSE; unloading module.\n");
1684 module->pDllMain = nullptr;
1685 FreeLibrary((HMODULE)module);
1686 SetLastError(ERROR_DLL_INIT_FAILED);
1687 module = nullptr;
1688 }
1689 }
1690 else
1691 {
1692 TRACE("Module does not contain a DllMain function.\n");
1693 }
1694
1695 return module;
1696}
1697
1698/*++
1699Function :
1700 LOADLoadLibrary [internal]
1701
1702 implementation of LoadLibrary (for use by the A/W variants)
1703
1704Parameters :
1705 LPSTR shortAsciiName : name of module as specified to LoadLibrary
1706
1707 BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
1708
1709Return value :
1710 handle to loaded module
1711
1712--*/
1713static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
1714{
1715 HMODULE module = nullptr;
1716 NATIVE_LIBRARY_HANDLE dl_handle = nullptr;
1717
1718 shortAsciiName = FixLibCName(shortAsciiName);
1719
1720 LockModuleList();
1721
1722 dl_handle = LOADLoadLibraryDirect(shortAsciiName);
1723 if (dl_handle)
1724 {
1725 module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic);
1726 }
1727
1728 UnlockModuleList();
1729
1730 return module;
1731}
1732
1733/*++
1734 LOADInitializeCoreCLRModule
1735
1736 Run the initialization methods for CoreCLR module (the module containing this PAL).
1737
1738Parameters:
1739 None
1740
1741Return value:
1742 TRUE if successful
1743 FALSE if failure
1744--*/
1745BOOL LOADInitializeCoreCLRModule()
1746{
1747 MODSTRUCT *module = LOADGetPalLibrary();
1748 if (!module)
1749 {
1750 ERROR("Can not load the PAL module\n");
1751 return FALSE;
1752 }
1753 PDLLMAIN pRuntimeDllMain = (PDLLMAIN)dlsym(module->dl_handle, "CoreDllMain");
1754 if (!pRuntimeDllMain)
1755 {
1756 ERROR("Can not find the CoreDllMain entry point\n");
1757 return FALSE;
1758 }
1759 return pRuntimeDllMain(module->hinstance, DLL_PROCESS_ATTACH, nullptr);
1760}
1761
1762/*++
1763Function :
1764 LOADGetPalLibrary
1765
1766 Load and initialize the PAL module.
1767
1768Parameters :
1769 None
1770
1771Return value :
1772 pointer to module struct
1773
1774--*/
1775MODSTRUCT *LOADGetPalLibrary()
1776{
1777 if (pal_module == nullptr)
1778 {
1779 // Initialize the pal module (the module containing LOADGetPalLibrary). Assumes that
1780 // the PAL is linked into the coreclr module because we use the module name containing
1781 // this function for the coreclr path.
1782 TRACE("Loading module for PAL library\n");
1783
1784 Dl_info info;
1785 if (dladdr((PVOID)&LOADGetPalLibrary, &info) == 0)
1786 {
1787 ERROR("LOADGetPalLibrary: dladdr() failed.\n");
1788 goto exit;
1789 }
1790 // Stash a copy of the CoreCLR installation path in a global variable.
1791 // Make sure it's terminated with a slash.
1792 if (g_szCoreCLRPath == nullptr)
1793 {
1794 size_t cbszCoreCLRPath = strlen(info.dli_fname) + 1;
1795 g_szCoreCLRPath = (char*) InternalMalloc(cbszCoreCLRPath);
1796
1797 if (g_szCoreCLRPath == nullptr)
1798 {
1799 ERROR("LOADGetPalLibrary: InternalMalloc failed!");
1800 goto exit;
1801 }
1802
1803 if (strcpy_s(g_szCoreCLRPath, cbszCoreCLRPath, info.dli_fname) != SAFECRT_SUCCESS)
1804 {
1805 ERROR("LOADGetPalLibrary: strcpy_s failed!");
1806 goto exit;
1807 }
1808 }
1809
1810 pal_module = (MODSTRUCT *)LOADLoadLibrary(info.dli_fname, FALSE);
1811 }
1812
1813exit:
1814 return pal_module;
1815}
1816
1817/*++
1818Function:
1819 LockModuleList
1820
1821Abstract
1822 Enter the critical section associated to the module list
1823
1824Parameter
1825 void
1826
1827Return
1828 void
1829--*/
1830extern "C"
1831void LockModuleList()
1832{
1833 CPalThread * pThread =
1834 (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1835
1836 InternalEnterCriticalSection(pThread, &module_critsec);
1837}
1838
1839/*++
1840Function:
1841 UnlockModuleList
1842
1843Abstract
1844 Leave the critical section associated to the module list
1845
1846Parameter
1847 void
1848
1849Return
1850 void
1851--*/
1852extern "C"
1853void UnlockModuleList()
1854{
1855 CPalThread * pThread =
1856 (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
1857
1858 InternalLeaveCriticalSection(pThread, &module_critsec);
1859}
1860