diff options
-rw-r--r-- | src/debug/debug-pal/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/debug/debug-pal/unix/dynamiclibaddress.cpp | 91 | ||||
-rw-r--r-- | src/dlls/dbgshim/dbgshim.cpp | 168 | ||||
-rw-r--r-- | src/pal/inc/pal.h | 28 | ||||
-rw-r--r-- | src/pal/src/include/pal/module.h | 58 | ||||
-rw-r--r-- | src/pal/src/loader/module.cpp | 370 | ||||
-rw-r--r-- | src/pal/src/thread/process.cpp | 242 |
7 files changed, 396 insertions, 562 deletions
diff --git a/src/debug/debug-pal/CMakeLists.txt b/src/debug/debug-pal/CMakeLists.txt index 01284029dc..43c1c9fdbe 100644 --- a/src/debug/debug-pal/CMakeLists.txt +++ b/src/debug/debug-pal/CMakeLists.txt @@ -23,7 +23,6 @@ if(CLR_CMAKE_PLATFORM_UNIX) set(TWO_WAY_PIPE_SOURCES unix/twowaypipe.cpp - unix/dynamiclibaddress.cpp ) endif(CLR_CMAKE_PLATFORM_UNIX) diff --git a/src/debug/debug-pal/unix/dynamiclibaddress.cpp b/src/debug/debug-pal/unix/dynamiclibaddress.cpp deleted file mode 100644 index 56ab558865..0000000000 --- a/src/debug/debug-pal/unix/dynamiclibaddress.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// -#include "windefs.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <limits.h> - - -void *GetDynamicLibraryAddressInProcess(DWORD pid, const char *libraryName) -{ - -// We don't have proper API detection in debug-pal -// that's why so far we'll just assume that we run on OS with ProcFS (which is not true on Mac OS) -// TODO: We need to implement this function for Mac OS -#define HAVE_PROCFS_CTL -#ifdef HAVE_PROCFS_CTL - - // Here we read /proc/<pid>/maps file in order to parse it and figure out what it says - // about a library we are looking for. This file looks something like this: - // - // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file - // - // 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so - // 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so - // 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so - // 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 [heap] - // 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so - // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so - // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so - // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so - - void *result = NULL; - - // Making something like: /proc/123/maps - char mapFileName[100]; - int chars = snprintf(mapFileName, sizeof(mapFileName), "/proc/%d/maps", pid); - _ASSERTE(chars > 0 && chars <= sizeof(mapFileName)); - - // Making something like: /libcoreclr.so - char slashLibName[PATH_MAX]; - chars = snprintf(slashLibName, sizeof(slashLibName), "/%s", libraryName); - _ASSERTE(chars > 0 && chars <= sizeof(mapFileName)); - size_t slashLibNameLen = strlen(slashLibName); - - FILE *mapsFile = fopen(mapFileName, "r"); - if (mapsFile == NULL) - { - return NULL; - } - - char *line = NULL; - size_t len = 0; - ssize_t read; - - // Reading maps file line by line - while ((read = getline(&line, &len, mapsFile)) != -1) - { - //Checking if this line ends with /libraryName\n - const char *expectedLibLocation = line + strlen(line) - 1 - slashLibNameLen; - if (expectedLibLocation > line && strncmp(expectedLibLocation, slashLibName, slashLibNameLen) == 0) - { - void *address1, *address2, *offset; - // We found a record for our library - // let's parse address and offset - - if (sscanf(line, "%p-%p %*[-rwxsp] %p", &address1, &address2, &offset) == 3) - { - // We were able to read all the info we need - if (offset == 0) - { - // We found address that corresponds to the very beginning of the lib we're looking for - result = address1; - break; - } - } - } - } - - free(line); // We didn't allocate line, but as per contract of getline we should free it - fclose(mapsFile); - return result; - -#else - _ASSERTE(!"Not implemented on this platform"); - return NULL; -#endif -} diff --git a/src/dlls/dbgshim/dbgshim.cpp b/src/dlls/dbgshim/dbgshim.cpp index aa972d8d2f..33871895ea 100644 --- a/src/dlls/dbgshim/dbgshim.cpp +++ b/src/dlls/dbgshim/dbgshim.cpp @@ -142,47 +142,6 @@ HRESULT GetStartupNotificationEvent(DWORD debuggeePID, return S_OK; } -//----------------------------------------------------------------------------- -// Public API. -// -// CloseCLREnumeration -- used to free resources allocated by EnumerateCLRs -// -// pHandleArray -- handle array originally returned by EnumerateCLRs -// pStringArray -- string array originally returned by EnumerateCLRs -// dwArrayLength -- array length originally returned by EnumerateCLRs -// -//----------------------------------------------------------------------------- -HRESULT CloseCLREnumeration(HANDLE* pHandleArray, LPWSTR* pStringArray, DWORD dwArrayLength) -{ - PUBLIC_CONTRACT; - - if ((pHandleArray + dwArrayLength) != (HANDLE*)pStringArray) - return E_INVALIDARG; - - // It's possible that EnumerateCLRs found nothing to enumerate, in which case - // pointers and count are zeroed. If a debugger calls this function in that - // case, let's not try to delete [] on NULL. - if (pHandleArray == NULL) - return S_OK; - -#ifndef FEATURE_PAL - for (DWORD i = 0; i < dwArrayLength; i++) - { - HANDLE hTemp = pHandleArray[i]; - if ( (NULL != hTemp) - && (INVALID_HANDLE_VALUE != hTemp)) - { - CloseHandle(hTemp); - } - } -#endif // FEATURE_PAL - - delete[] pHandleArray; - return S_OK; -} - -#ifndef FEATURE_PAL - HRESULT GetContinueStartupEvent(DWORD debuggeePID, LPCWSTR szTelestoFullPath, __out HANDLE* phContinueStartupEvent); @@ -223,8 +182,9 @@ void GetTargetCLRMetrics(LPCWSTR szTelestoFullPath, CONSISTENCY_CHECK(szTelestoFullPath != NULL); CONSISTENCY_CHECK(pEngineMetricsOut != NULL); +#ifndef FEATURE_PAL HRESULT hr = S_OK; - + HandleHolder hCoreClrFile = WszCreateFile(szTelestoFullPath, GENERIC_READ, FILE_SHARE_READ, @@ -353,8 +313,14 @@ void GetTargetCLRMetrics(LPCWSTR szTelestoFullPath, } // Holder will call FreeLibrary() +#else + //TODO: So far on POSIX systems we only support one version of debugging interface + // in future we might want to detect it the same way we do it on Windows. + pEngineMetricsOut->dwDbiVersion = CorDebugLatestVersion; +#endif // FEATURE_PAL } + // Returns true iff the module represents CoreClr. bool IsCoreClr(const WCHAR* pModulePath) { @@ -362,9 +328,9 @@ bool IsCoreClr(const WCHAR* pModulePath) //strip off everything up to and including the last slash in the path to get name const WCHAR* pModuleName = pModulePath; - while(wcschr(pModuleName, W('\\')) != NULL) + while(wcschr(pModuleName, DIRECTORY_SEPARATOR_CHAR_W) != NULL) { - pModuleName = wcschr(pModuleName, W('\\')); + pModuleName = wcschr(pModuleName, DIRECTORY_SEPARATOR_CHAR_W); pModuleName++; // pass the slash } @@ -406,8 +372,6 @@ bool IsCoreClrWithGoodHeader(HANDLE hProcess, HMODULE hModule) return false; } -#endif // !FEATURE_PAL - //----------------------------------------------------------------------------- // Public API. // @@ -439,7 +403,6 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, if ((ppHandleArrayOut == NULL) || (ppStringArrayOut == NULL) || (pdwArrayLengthOut == NULL)) return E_INVALIDARG; -#ifndef FEATURE_PAL HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, debuggeePID); if (NULL == hProcess) ThrowHR(E_FAIL); @@ -474,9 +437,6 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, return S_OK; } -#else - DWORD count = 1; -#endif // FEATURE_PAL size_t cbEventArrayData = sizeof(HANDLE) * count; // event array data size_t cbStringArrayData = sizeof(LPWSTR) * count; // string array data @@ -494,7 +454,6 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, WCHAR* pStringData = (WCHAR*) &pOutBuffer[cbEventArrayData + cbStringArrayData]; DWORD idx = 0; -#ifndef FEATURE_PAL // There's no guarantee that another coreclr hasn't loaded already anyhow, // so if we get the corner case that the second time through we enumerate // more coreclrs, just ignore the extras. @@ -514,6 +473,7 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, pStringArray[idx] = &pStringData[idx * MAX_PATH]; GetModuleFileNameEx(hProcess, modules[i], pStringArray[idx], MAX_PATH); +#ifndef FEATURE_PAL // fill in event handle -- if GetContinueStartupEvent fails, it will still return // INVALID_HANDLE_VALUE in hContinueStartupEvent, which is what we want. we don't // want to bail out of the enumeration altogether if we can't get an event from @@ -524,6 +484,9 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, _ASSERTE(SUCCEEDED(hr) == (hContinueStartupEvent != INVALID_HANDLE_VALUE)); pEventArray[idx] = hContinueStartupEvent; +#else + pEventArray[idx] = NULL; +#endif // FEATURE_PAL idx++; } @@ -548,11 +511,6 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, // Strings themselves don't need moved. } -#else - pStringArray[idx] = &pStringData[idx * MAX_PATH]; - wcscpy_s(pStringArray[idx], MAX_PATH, MAKEDLLNAME_W(W("coreclr"))); - idx++; -#endif // FEATURE_PAL *ppHandleArrayOut = pEventArray; *ppStringArrayOut = pStringArray; @@ -561,7 +519,44 @@ HRESULT EnumerateCLRs(DWORD debuggeePID, return S_OK; } +//----------------------------------------------------------------------------- +// Public API. +// +// CloseCLREnumeration -- used to free resources allocated by EnumerateCLRs +// +// pHandleArray -- handle array originally returned by EnumerateCLRs +// pStringArray -- string array originally returned by EnumerateCLRs +// dwArrayLength -- array length originally returned by EnumerateCLRs +// +//----------------------------------------------------------------------------- +HRESULT CloseCLREnumeration(HANDLE* pHandleArray, LPWSTR* pStringArray, DWORD dwArrayLength) +{ + PUBLIC_CONTRACT; + + if ((pHandleArray + dwArrayLength) != (HANDLE*)pStringArray) + return E_INVALIDARG; + + // It's possible that EnumerateCLRs found nothing to enumerate, in which case + // pointers and count are zeroed. If a debugger calls this function in that + // case, let's not try to delete [] on NULL. + if (pHandleArray == NULL) + return S_OK; + #ifndef FEATURE_PAL + for (DWORD i = 0; i < dwArrayLength; i++) + { + HANDLE hTemp = pHandleArray[i]; + if ( (NULL != hTemp) + && (INVALID_HANDLE_VALUE != hTemp)) + { + CloseHandle(hTemp); + } + } +#endif // FEATURE_PAL + + delete[] pHandleArray; + return S_OK; +} //----------------------------------------------------------------------------- // Get the base address of a module from the remote process. @@ -581,7 +576,9 @@ BYTE* GetRemoteModuleBaseAddress(DWORD dwPID, LPCWSTR szFullModulePath) HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (NULL == hProcess) + { ThrowHR(E_FAIL); + } // These shouldn't be freed HMODULE modules[1000]; @@ -609,13 +606,10 @@ BYTE* GetRemoteModuleBaseAddress(DWORD dwPID, LPCWSTR szFullModulePath) } } - // Successfully enumerated modules but couldn't find the requested one. return NULL; } -#endif // FEATURE_PAL - // DBI version: max 8 hex chars // SEMICOLON: 1 // PID: max 8 hex chars @@ -692,20 +686,12 @@ HRESULT CreateVersionStringFromModule(DWORD pidDebuggee, { CorDebugInterfaceVersion dbiVersion = CorDebugInvalidVersion; BYTE* hmodTargetCLR = NULL; -#ifndef FEATURE_PAL CLR_ENGINE_METRICS metricsStruct; GetTargetCLRMetrics(szModuleName, &metricsStruct); // throws dbiVersion = (CorDebugInterfaceVersion) metricsStruct.dwDbiVersion; - - hmodTargetCLR = GetRemoteModuleBaseAddress(pidDebuggee, szModuleName); // throws -#else - //TODO: So far on POSIX systems we only support one version of debugging interface - // in future we might want to detect it the same way we do it on Windows. - dbiVersion = CorDebugLatestVersion; - hmodTargetCLR = (BYTE *)GetDynamicLibraryAddressInProcess(pidDebuggee, MAKEDLLNAME_A(MAIN_CLR_MODULE_NAME_A)); -#endif // FEATURE_PAL + hmodTargetCLR = GetRemoteModuleBaseAddress(pidDebuggee, szModuleName); // throws if (hmodTargetCLR == NULL) { hr = COR_E_FILENOTFOUND; @@ -768,7 +754,6 @@ HRESULT ParseVersionString(LPCWSTR szDebuggeeVersion, CorDebugInterfaceVersion * return S_OK; } -#ifndef FEATURE_PAL //----------------------------------------------------------------------------- // Appends "\mscordbi.dll" to the path. This converts a directory name into the full path to mscordbi.dll. // @@ -777,10 +762,11 @@ HRESULT ParseVersionString(LPCWSTR szDebuggeeVersion, CorDebugInterfaceVersion * //----------------------------------------------------------------------------- void AppendDbiDllName(SString & szFullDbiPath) { - const WCHAR * pDbiDllName = W("\\") MAKEDLLNAME_W(W("mscordbi")); + const WCHAR * pDbiDllName = DIRECTORY_SEPARATOR_STR_W MAKEDLLNAME_W(W("mscordbi")); szFullDbiPath.Append(pDbiDllName); } + //----------------------------------------------------------------------------- // Return a path to the dbi next to the runtime, if present. // @@ -811,7 +797,7 @@ void GetDbiFilenameNextToRuntime(DWORD pidDebuggee, HMODULE hmodTargetCLR, SStri // Step 2: 'Coreclr.dll' --> 'mscordbi.dll' // WCHAR * pCoreClrPath = modulePath; - WCHAR * pLast = wcsrchr(pCoreClrPath, '\\'); + WCHAR * pLast = wcsrchr(pCoreClrPath, DIRECTORY_SEPARATOR_CHAR_W); if (pLast == NULL) { ThrowHR(E_FAIL); @@ -833,6 +819,7 @@ void GetDbiFilenameNextToRuntime(DWORD pidDebuggee, HMODULE hmodTargetCLR, SStri szFullCoreClrPath.Set(pCoreClrPath, (COUNT_T)wcslen(pCoreClrPath)); } + //--------------------------------------------------------------------------------------- // // The current policy is that the DBI DLL must live right next to the coreclr DLL. We check the product @@ -848,6 +835,7 @@ void GetDbiFilenameNextToRuntime(DWORD pidDebuggee, HMODULE hmodTargetCLR, SStri bool CheckDbiAndRuntimeVersion(SString & szFullDbiPath, SString & szFullCoreClrPath) { +#ifndef FEATURE_PAL DWORD dwDbiVersionMS = 0; DWORD dwDbiVersionLS = 0; DWORD dwCoreClrVersionMS = 0; @@ -866,16 +854,11 @@ bool CheckDbiAndRuntimeVersion(SString & szFullDbiPath, SString & szFullCoreClrP { return false; } -} - #else - -// Functions that we'll look for in the loaded Mscordbi module. -typedef HRESULT (STDAPICALLTYPE *FPCreateCordbObject)( - int iDebuggerVersion, - IUnknown ** ppCordb); - + return true; #endif // FEATURE_PAL +} + //----------------------------------------------------------------------------- // Public API. @@ -905,6 +888,8 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( HRESULT hr = S_OK; HMODULE hMod = NULL; IUnknown * pCordb = NULL; + FPCoreCLRCreateCordbObject fpCreate2 = NULL; + LOG((LF_CORDB, LL_EVERYTHING, "Calling CreateDebuggerInterfaceFromVersion, ver=%S\n", szDebuggeeVersion)); if ((szDebuggeeVersion == NULL) || (ppCordb == NULL)) @@ -915,7 +900,6 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( *ppCordb = NULL; - // // Step 1: Parse version information into internal data structures // @@ -928,7 +912,6 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( if (FAILED(hr)) goto Exit; -#ifndef FEATURE_PAL // // Step 2: Find the proper Dbi module (mscordbi.dll) and load it. // @@ -954,7 +937,11 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( // Issue:951525: coreclr mscordbi load fails on downlevel OS since LoadLibraryEx can't find // dependent forwarder DLLs. Force LoadLibrary to look for dependencies in szFullDbiPath plus the default // search paths. +#ifndef FEATURE_PAL hMod = WszLoadLibraryEx(szFullDbiPath, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); +#else + hMod = LoadLibraryExW(szFullDbiPath, NULL, 0); +#endif } EX_CATCH_HRESULT(hrIgnore); // failure leaves hMod null @@ -977,7 +964,7 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( // // Step 3: Now that module is loaded, instantiate an ICorDebug. // - FPCoreCLRCreateCordbObject fpCreate2 = (FPCoreCLRCreateCordbObject)GetProcAddress(hMod, "CoreCLRCreateCordbObject"); + fpCreate2 = (FPCoreCLRCreateCordbObject)GetProcAddress(hMod, "CoreCLRCreateCordbObject"); if (fpCreate2 == NULL) { // New-style creation API didn't exist - this DBI must be the wrong version, for the Mix07 protocol @@ -987,23 +974,6 @@ HRESULT CreateDebuggingInterfaceFromVersionEx( // Invoke to instantiate an ICorDebug. This export was introduced after the Mix'07 release. hr = fpCreate2(iDebuggerVersion, pidDebuggee, hmodTargetCLR, &pCordb); -#else - { - hMod = LoadLibraryExW(MAKEDLLNAME_W(W("mscordbi")), NULL, 0); - if (NULL == hMod) - { - hr = CORDBG_E_DEBUG_COMPONENT_MISSING; - goto Exit; - } - FPCoreCLRCreateCordbObject fpCreate2 = (FPCoreCLRCreateCordbObject)GetProcAddress(hMod, "CoreCLRCreateCordbObject"); - if (hmodTargetCLR == NULL || fpCreate2 == NULL) - { - hr = CORDBG_E_INCOMPATIBLE_PROTOCOL; - goto Exit; - } - hr = fpCreate2(iDebuggerVersion, pidDebuggee, hmodTargetCLR, &pCordb); - } -#endif // FEATURE_PAL _ASSERTE((pCordb == NULL) == FAILED(hr)); Exit: diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 69b5362b45..e6c287f5d8 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -3358,6 +3358,20 @@ GetModuleFileNameW( #define GetModuleFileName GetModuleFileNameA #endif +PALIMPORT +DWORD +PALAPI +GetModuleFileNameExW( + IN HANDLE hProcess, + IN HMODULE hModule, + OUT LPWSTR lpFilename, + IN DWORD nSize + ); + +#ifdef UNICODE +#define GetModuleFileNameEx GetModuleFileNameExW +#endif + // Get base address of the module containing a given symbol PALAPI LPCVOID @@ -4550,16 +4564,26 @@ OpenProcess( ); PALIMPORT +BOOL +PALAPI +EnumProcessModules( + IN HANDLE hProcess, + OUT HMODULE *lphModule, + IN DWORD cb, + OUT LPDWORD lpcbNeeded + ); + +PALIMPORT VOID PALAPI OutputDebugStringA( - IN LPCSTR lpOutputString); + IN LPCSTR lpOutputString); PALIMPORT VOID PALAPI OutputDebugStringW( - IN LPCWSTR lpOutputStrig); + IN LPCWSTR lpOutputStrig); #ifdef UNICODE #define OutputDebugString OutputDebugStringW diff --git a/src/pal/src/include/pal/module.h b/src/pal/src/include/pal/module.h index a58a82a458..fada2ae169 100644 --- a/src/pal/src/include/pal/module.h +++ b/src/pal/src/include/pal/module.h @@ -21,24 +21,6 @@ Abstract: #ifndef _PAL_MODULE_H_ #define _PAL_MODULE_H_ -#if defined(CORECLR) && defined(__APPLE__) - -#include <CoreFoundation/CFBundle.h> - -// Name of the CoreCLR bundle executable -#define CORECLR_BUNDLE_NAME "coreclr" - -// Name of the CoreCLR bundle root directory. -#define CORECLR_BUNDLE_DIR "CoreCLR.bundle" - -// Directory components between the bundle root and the executable. -#define CORECLR_BUNDLE_PATH "Contents/MacOS/" - -// Abstract the API used to load and query for functions in the CoreCLR binary to make it easier to change the -// underlying implementation. -typedef CFBundleRef CORECLRHANDLE; -#endif // CORECLR && __APPLE__ - #ifdef __cplusplus extern "C" { @@ -65,22 +47,18 @@ typedef struct _MODSTRUCT HMODULE self; /* circular reference to this module */ void *dl_handle; /* handle returned by dlopen() */ HINSTANCE hinstance; /* handle returned by PAL_RegisterLibrary */ -#if defined(CORECLR) && defined(__APPLE__) - CORECLRHANDLE sys_module; /* System modules can be loaded via mechanisms other than dlopen() under - * CoreCLR/Mac */ -#endif // CORECLR && __APPLE__ LPWSTR lib_name; /* full path of module */ INT refcount; /* reference count */ /* -1 means infinite reference count - module is never released */ BOOL ThreadLibCalls; /* TRUE for DLL_THREAD_ATTACH/DETACH notifications - enabled, FALSE if they are disabled */ + enabled, FALSE if they are disabled */ #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN ino_t inode; dev_t device; #endif - PDLLMAIN pDllMain; /* entry point of module */ + PDLLMAIN pDllMain; /* entry point of module */ /* reference to next and previous modules in list (in load order) */ struct _MODSTRUCT *next; @@ -204,23 +182,6 @@ Return value: --*/ BOOL PAL_LOADUnloadPEFile(void * ptr); - -#if !defined(CORECLR) || !defined(__APPLE__) -/*++ - LOADGetLibRotorPalSoFileName - - Retrieve the full path of the librotor_pal.so being used. - -Parameters: - OUT pwzBuf - WCHAR buffer of MAX_PATH length to receive file name - -Return value: - 0 if successful - -1 if failure, with last error set. ---*/ -int LOADGetLibRotorPalSoFileName(LPSTR pszBuf); -#endif // !CORECLR || !__APPLE__ - /*++ LOADInitCoreCLRModules @@ -236,21 +197,6 @@ Return value: --*/ BOOL LOADInitCoreCLRModules(const char *szCoreCLRPath); -#if defined(CORECLR) && defined(__APPLE__) -// Abstract the API used to load and query for functions in the CoreCLR binary to make it easier to change the -// underlying implementation. - -// Load the CoreCLR module into memory given the directory in which it resides. Returns NULL on failure. -CORECLRHANDLE LoadCoreCLR(const char *szPath); - -// Lookup the named function in the given CoreCLR image. Returns NULL on failure. -void *LookupFunctionInCoreCLR(CORECLRHANDLE hCoreCLR, const char *szFunction); - -// Locate the CoreCLR module handle associated with the code currently executing. Returns NULL on failure. -CORECLRHANDLE FindCoreCLRHandle(); - -#endif // CORECLR && __APPLE__ - #ifdef __cplusplus } #endif // __cplusplus diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp index aadf12850e..ad61285a9f 100644 --- a/src/pal/src/loader/module.cpp +++ b/src/pal/src/loader/module.cpp @@ -95,10 +95,9 @@ MODSTRUCT pal_module; /* always the second, in the in-load-order list */ static BOOL LOADValidateModule(MODSTRUCT *module); static LPWSTR LOADGetModuleFileName(MODSTRUCT *module); -static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic); +static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic); static void LOAD_SEH_CallDllMain(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved); static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name); -static INT FindLibrary(CHAR* pszRelName, CHAR** ppszFullName); /* API function definitions ***************************************************/ @@ -111,7 +110,7 @@ See MSDN doc. HMODULE PALAPI LoadLibraryA( - IN LPCSTR lpLibFileName) + IN LPCSTR lpLibFileName) { return LoadLibraryExA(lpLibFileName, NULL, 0); } @@ -125,7 +124,7 @@ See MSDN doc. HMODULE PALAPI LoadLibraryW( - IN LPCWSTR lpLibFileName) + IN LPCWSTR lpLibFileName) { return LoadLibraryExW(lpLibFileName, NULL, 0); } @@ -139,9 +138,9 @@ See MSDN doc. HMODULE PALAPI LoadLibraryExA( - IN LPCSTR lpLibFileName, - IN /*Reserved*/ HANDLE hFile, - IN DWORD dwFlags) + IN LPCSTR lpLibFileName, + IN /*Reserved*/ HANDLE hFile, + IN DWORD dwFlags) { if (dwFlags != 0) { @@ -208,9 +207,9 @@ See MSDN doc. HMODULE PALAPI LoadLibraryExW( - IN LPCWSTR lpLibFileName, - IN /*Reserved*/ HANDLE hFile, - IN DWORD dwFlags) + IN LPCWSTR lpLibFileName, + IN /*Reserved*/ HANDLE hFile, + IN DWORD dwFlags) { if (dwFlags != 0) { @@ -281,8 +280,8 @@ See MSDN doc. FARPROC PALAPI GetProcAddress( - IN HMODULE hModule, - IN LPCSTR lpProcName) + IN HMODULE hModule, + IN LPCSTR lpProcName) { MODSTRUCT *module; FARPROC ProcAddress = NULL; @@ -305,7 +304,7 @@ GetProcAddress( goto done; } - if( !LOADValidateModule( module ) ) + if( !LOADValidateModule(module) ) { TRACE("Invalid module handle %p\n", hModule); SetLastError(ERROR_INVALID_HANDLE); @@ -405,7 +404,7 @@ See MSDN doc. BOOL PALAPI FreeLibrary( - IN OUT HMODULE hLibModule) + IN OUT HMODULE hLibModule) { MODSTRUCT *module; BOOL retval = FALSE; @@ -435,7 +434,7 @@ FreeLibrary( if( module->refcount == -1 ) { /* special module - never released */ - retval=TRUE; + retval = TRUE; goto done; } @@ -445,7 +444,7 @@ FreeLibrary( if( module->refcount != 0 ) { - retval=TRUE; + retval = TRUE; goto done; } @@ -460,7 +459,7 @@ FreeLibrary( module->next->prev = module->prev; /* remove the circular reference so that LOADValidateModule will fail */ - module->self=NULL; + module->self = NULL; /* Call DllMain if the module contains one */ if(module->pDllMain) @@ -498,7 +497,7 @@ FreeLibrary( #endif /* !_NO_DEBUG_MESSAGES_ */ } - if(module->dl_handle && 0!=dlclose(module->dl_handle)) + if(module->dl_handle && 0 != dlclose(module->dl_handle)) { /* report dlclose() failure, but proceed anyway. */ WARN("dlclose() call failed! error message is \"%s\"\n", dlerror()); @@ -509,7 +508,7 @@ FreeLibrary( InternalFree(pThread, module->lib_name); InternalFree(pThread, module); - retval=TRUE; + retval = TRUE; done: UnlockModuleList(); @@ -530,8 +529,8 @@ PALIMPORT VOID PALAPI FreeLibraryAndExitThread( - IN HMODULE hLibModule, - IN DWORD dwExitCode) + IN HMODULE hLibModule, + IN DWORD dwExitCode) { PERF_ENTRY(FreeLibraryAndExitThread); ENTRY("FreeLibraryAndExitThread()\n"); @@ -558,12 +557,12 @@ Notes : DWORD PALAPI GetModuleFileNameA( - IN HMODULE hModule, - OUT LPSTR lpFileName, - IN DWORD nSize) + IN HMODULE hModule, + OUT LPSTR lpFileName, + IN DWORD nSize) { INT name_length; - DWORD retval=0; + DWORD retval = 0; LPWSTR wide_name = NULL; PERF_ENTRY(GetModuleFileNameA); @@ -577,7 +576,7 @@ GetModuleFileNameA( SetLastError(ERROR_INVALID_HANDLE); goto done; } - wide_name=LOADGetModuleFileName((MODSTRUCT *)hModule); + wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule); if(!wide_name) { @@ -598,7 +597,7 @@ GetModuleFileNameA( } TRACE("File name of module %p is %s\n", hModule, lpFileName); - retval=name_length; + retval = name_length; done: UnlockModuleList(); LOGEXIT("GetModuleFileNameA returns DWORD %d\n", retval); @@ -623,12 +622,12 @@ Notes : DWORD PALAPI GetModuleFileNameW( - IN HMODULE hModule, - OUT LPWSTR lpFileName, - IN DWORD nSize) + IN HMODULE hModule, + OUT LPWSTR lpFileName, + IN DWORD nSize) { INT name_length; - DWORD retval=0; + DWORD retval = 0; LPWSTR wide_name = NULL; PERF_ENTRY(GetModuleFileNameW); @@ -645,7 +644,7 @@ GetModuleFileNameW( SetLastError(ERROR_INVALID_HANDLE); goto done; } - wide_name=LOADGetModuleFileName((MODSTRUCT *)hModule); + wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule); if(!wide_name) { @@ -657,7 +656,7 @@ GetModuleFileNameW( /* Copy module name into supplied buffer */ name_length = lstrlenW(wide_name); - if(name_length>=(INT)nSize) + if(name_length >= (INT)nSize) { TRACE("Buffer too small to copy module's file name.\n"); SetLastError(ERROR_INSUFFICIENT_BUFFER); @@ -667,7 +666,7 @@ GetModuleFileNameW( wcscpy_s(lpFileName, nSize, wide_name); TRACE("file name of module %p is %S\n", hModule, lpFileName); - retval=name_length; + retval = name_length; done: UnlockModuleList(); LOGEXIT("GetModuleFileNameW returns DWORD %u\n", retval); @@ -675,6 +674,7 @@ done: return retval; } + /*++ Function: PAL_RegisterModule @@ -737,7 +737,7 @@ Function: HMODULE PALAPI PAL_RegisterLibraryW( - IN LPCWSTR lpLibFileName) + IN LPCWSTR lpLibFileName) { HMODULE hModule = NULL; CHAR lpstr[MAX_PATH]; @@ -814,7 +814,7 @@ Function: BOOL PALAPI PAL_UnregisterLibraryW( - IN OUT HMODULE hLibModule) + IN OUT HMODULE hLibModule) { BOOL retval; @@ -831,81 +831,6 @@ PAL_UnregisterLibraryW( /* Internal PAL functions *****************************************************/ /*++ - LOADGetLibRotorPalSoFileName - - Search LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH) for LibRotorPal. This - defines the working directory for PAL. - -Parameters: - OUT LPSTR pszBuf - WCHAR buffer of MAX_PATH length to receive file name - -Return value: - 0 if successful - -1 if failure, with last error set. ---*/ -extern "C" -int LOADGetLibRotorPalSoFileName(LPSTR pszBuf) -{ - INT iRetVal = -1; - CHAR* pszFileName = NULL; - CPalThread *pthrThread = InternalGetCurrentThread(); - - if (!pszBuf) - { - ASSERT("LOADGetLibRotorPalSoFileName requires non-NULL pszBuf\n"); - SetLastError(ERROR_INTERNAL_ERROR); - goto Done; - } - iRetVal = FindLibrary((CHAR*)MAKEDLLNAME_A("coreclrpal"), &pszFileName); - if (pszFileName) - { - UINT cchFileName = strlen(pszFileName); - if (cchFileName + 1 > MAX_PATH) - { - ASSERT("Filename returned by FindLibrary was longer than" - "MAX_PATH!\n"); - SetLastError(ERROR_FILENAME_EXCED_RANGE); - goto Done; - } - // If the path is relative, get current working directory and prepend - // it (Note that this function is called only on PAL startup, so - // current working directory should still be correct) - if (pszFileName[0] != '/') - { - CHAR szCurDir[MAX_PATH]; - CHAR* pszRetVal = NULL; - if ((pszRetVal = InternalGetcwd(pthrThread, szCurDir, MAX_PATH)) == NULL) - { - SetLastError(DIRGetLastErrorFromErrno()); - goto Done; - } - // If the strings would overflow (note that if the sum of the - // lengths == MAX_PATH, the string would overflow b/c of the null - // terminator -- the 1 is added to account for the /) - if ((strlen(szCurDir) + strlen(pszFileName) + 1) >= MAX_PATH) - { - SetLastError(ERROR_FILENAME_EXCED_RANGE); - goto Done; - } - strcat_s(pszBuf, MAX_PATH, szCurDir); - strcat_s(pszBuf, MAX_PATH, "/"); - strcat_s(pszBuf, MAX_PATH, pszFileName); - } - else - { - strcpy_s(pszBuf, MAX_PATH, pszFileName); - } - iRetVal = 0; - } -Done: - if (pszFileName) - { - InternalFree(pthrThread, pszFileName); - } - return iRetVal; -} - -/*++ Function : LOADInitializeModules @@ -1207,7 +1132,7 @@ DisableThreadLibraryCalls( LockModuleList(); module = (MODSTRUCT *) hLibModule; - if(!module || !LOADValidateModule(module)) + if(!LOADValidateModule(module)) { // DisableThreadLibraryCalls() does nothing when given // an invalid module handle. This matches the Windows @@ -1250,24 +1175,23 @@ static BOOL LOADValidateModule(MODSTRUCT *module) LockModuleList(); - modlist_enum=&exe_module; + modlist_enum = &exe_module; /* enumerate through the list of modules to make sure the given handle is really a module (HMODULEs are actually MODSTRUCT pointers) */ do { - if(module==modlist_enum) + if(module == modlist_enum) { /* found it; check its integrity to be on the safe side */ - if(module->self!=module) + if(module->self != module) { ERROR("Found corrupt module %p!\n",module); UnlockModuleList(); return FALSE; } UnlockModuleList(); - TRACE("Module %p is valid (name : %S)\n", module, - MODNAME(module)); + TRACE("Module %p is valid (name : %S)\n", module, MODNAME(module)); return TRUE; } modlist_enum = modlist_enum->next; @@ -1387,7 +1311,7 @@ Function : implementation of LoadLibrary (for use by the A/W variants) Parameters : - LPSTR ShortAsciiName : name of module as specified to LoadLibrary + LPSTR shortAsciiName : name of module as specified to LoadLibrary BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary @@ -1395,7 +1319,7 @@ Return value : handle to loaded module --*/ -static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) +static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) { CHAR fullLibraryName[MAX_PATH]; MODSTRUCT *module = NULL; @@ -1407,14 +1331,14 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) // The problem is that calling dlopen("libc.so") will fail for libc even thought it works // for other libraries. The reason is that libc.so is just linker script (i.e. a test file). // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO. - if (strcmp(ShortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0) + if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0) { #if defined(__APPLE__) - ShortAsciiName = "libc.dylib"; + shortAsciiName = "libc.dylib"; #elif defined(__FreeBSD__) - ShortAsciiName = FREEBSD_LIBC; + shortAsciiName = FREEBSD_LIBC; #else - ShortAsciiName = LIBC_SO; + shortAsciiName = LIBC_SO; #endif } @@ -1426,10 +1350,10 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) { // See GetProcAddress for an explanation why we leave the PAL. PAL_LeaveHolder holder; - dl_handle = dlopen(ShortAsciiName, RTLD_LAZY | RTLD_NOLOAD); + dl_handle = dlopen(shortAsciiName, RTLD_LAZY | RTLD_NOLOAD); if (!dl_handle) { - dl_handle = dlopen(ShortAsciiName, RTLD_LAZY); + dl_handle = dlopen(shortAsciiName, RTLD_LAZY); } // P/Invoke calls are often defined without an extension in the name of the @@ -1437,7 +1361,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) // a proper extension and load the library again. if (!dl_handle) { - if (snprintf(fullLibraryName, MAX_PATH, "%s%s", ShortAsciiName, PAL_SHLIB_SUFFIX) < MAX_PATH) + if (snprintf(fullLibraryName, MAX_PATH, "%s%s", shortAsciiName, PAL_SHLIB_SUFFIX) < MAX_PATH) { dl_handle = dlopen(fullLibraryName, RTLD_LAZY | RTLD_NOLOAD); if (!dl_handle) @@ -1446,7 +1370,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) } if (dl_handle) { - ShortAsciiName = fullLibraryName; + shortAsciiName = fullLibraryName; } } } @@ -1458,8 +1382,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) SetLastError(ERROR_MOD_NOT_FOUND); goto done; } - TRACE("dlopen() found module %s\n", ShortAsciiName); - + TRACE("dlopen() found module %s\n", shortAsciiName); #if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN /* search module list for a match. */ @@ -1471,7 +1394,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) /* found the handle. increment the refcount and return the existing module structure */ TRACE("Found matching module %p for module name %s\n", - module, ShortAsciiName); + module, shortAsciiName); if (module->refcount != -1) module->refcount++; dlclose(dl_handle); @@ -1481,8 +1404,8 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) } while (module != &exe_module); #endif - TRACE("Module doesn't exist : creating %s.\n", ShortAsciiName); - module = LOADAllocModule(dl_handle, ShortAsciiName); + TRACE("Module doesn't exist : creating %s.\n", shortAsciiName); + module = LOADAllocModule(dl_handle, shortAsciiName); if(NULL == module) { @@ -1527,7 +1450,7 @@ static HMODULE LOADLoadLibrary(LPCSTR ShortAsciiName, BOOL fDynamic) PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule"); if (registerModule) { - module->hinstance = registerModule(ShortAsciiName); + module->hinstance = registerModule(shortAsciiName); } else { @@ -1764,185 +1687,6 @@ BOOL PAL_LOADUnloadPEFile(void * ptr) } /*++ -Function: - FindLibrary - -Abstract - Search LD_LIBRARY_PATH/DYLD_LIBRARY_PATH for a file named pszRelName - -Parameter - pszRelName: The relative name of the file sought - ppszFullName: A pointer that will be filled in with the full filename if - we find it - -Return - 0 if completed successfully, even if library not found - -1 on error ---*/ -INT FindLibrary(CHAR* pszRelName, CHAR** ppszFullName) -{ - CPalThread *pThread = NULL; - CHAR* pszLibPath = NULL; - CHAR* pszNext = NULL; - CHAR** rgpLibDirSeparators = NULL; - UINT cSeparators = 0; - UINT iSeparator = 0; - UINT iStringLen = 0; - INT iRetVal = 0; - CHAR* pszSearchPath = NULL; - BOOL fSearchPathNeedsFreeing = FALSE; - - if (!ppszFullName) - { - SetLastError(ERROR_INVALID_PARAMETER); - iRetVal = -1; - goto Done; - } - *ppszFullName = NULL; - - // First, get the LD_LIBRARY_PATH to figure out where to look - // Note that pszLibPath points to system memory -- don't free. - pszLibPath = MiscGetenv(LIBSEARCHPATH); - if (!pszLibPath) - { - TRACE("FindLibrary: " LIBSEARCHPATH " not set\n"); - pszLibPath = (char*)"."; - } - else - { - TRACE("FindLibrary: " LIBSEARCHPATH " is %s\n", pszLibPath); - } - - pThread = InternalGetCurrentThread(); - iStringLen = strlen(pszLibPath); - - // We want to make sure that we always search the current directory, - // regardless of whether LD_LIBRARY_PATH includes it (this mimics - // Windows behavior) - if ( (!(strstr(pszLibPath, ":.:"))) && // if you don't find '.' in the middle - (!(iStringLen == 1 && pszLibPath[0] == '.')) && // if it's not just equal to '.' - (!(iStringLen >= 2 && pszLibPath[0] == '.' - && pszLibPath[1] == ':')) && // if it doesn't start with ".:" - (!(iStringLen >= 2 && pszLibPath[iStringLen-2] == ':' - && pszLibPath[iStringLen-1] == '.')) ) // if it doesn't end with ":." - { - // 3 is hardcoded here for :. and null - int iLen = sizeof(pszSearchPath[0]) * (iStringLen + 3); - pszSearchPath = (char*) InternalMalloc (pThread, iLen); - if (!pszSearchPath) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - iRetVal = -1; - goto Done; - } - iStringLen += 3; // This 3 is hard coded for :. and null - fSearchPathNeedsFreeing = TRUE; - if (strcpy_s(pszSearchPath, iLen, pszLibPath) != SAFECRT_SUCCESS) - { - ERROR("strcpy_s failed!\n"); - SetLastError(ERROR_INSUFFICIENT_BUFFER); - goto Done; - } - - if (strcat_s(pszSearchPath, iLen, ":.") != SAFECRT_SUCCESS) - { - ERROR("strcat_s failed!\n"); - SetLastError(ERROR_INSUFFICIENT_BUFFER); - goto Done; - } - } - // If LD_LIBRARY_PATH already includes a reference to the current - // directory, we'll search it in the right order. - else - { - pszSearchPath = pszLibPath; - } - - _ASSERTE(strchr(pszSearchPath, '.')); - - // Allocate an array for pointers to separators -- there can't be more than - // the length of LD_LIBRARY_PATH - 1 separators (since we always have atleast a '.' in it ) - // + 2 implicit seperators... - rgpLibDirSeparators = (char **) - InternalMalloc(pThread, sizeof(rgpLibDirSeparators[0]) * (iStringLen+1)); - if (!rgpLibDirSeparators) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - iRetVal = -1; - goto Done; - } - - // Now, find the separators in LD_LIBRARY_PATH. Set a pointer to each : - pszNext = pszSearchPath; - // There's an implicit separator at the start... - rgpLibDirSeparators[0] = pszNext - 1; - cSeparators = 1; - while (*pszNext != '\0') - { - if (*pszNext == ':') - { - _ASSERTE(cSeparators < iStringLen); - rgpLibDirSeparators[cSeparators] = pszNext; - cSeparators++; - } - pszNext++; - } - - _ASSERTE(cSeparators <= iStringLen); - // And there's an implicit separator at the end. - rgpLibDirSeparators[cSeparators] = pszNext; - cSeparators++; - - // Now, check each path for the File - // Note that cSeparators is always >= 2, so the < -1 check is safe - for (iSeparator = 0; iSeparator < (cSeparators-1); iSeparator++) - { - CHAR szFileName[MAX_PATH + 1]; - CHAR szDirName[MAX_PATH + 1]; - struct stat stat_buf; - UINT cchDirName = 0; - - // length of DirName is number of chars between the first char after - // the colon and the next colon - cchDirName = rgpLibDirSeparators[iSeparator + 1] - - (rgpLibDirSeparators[iSeparator] + 1); - memcpy(szDirName, rgpLibDirSeparators[iSeparator] + 1, cchDirName); - szDirName[cchDirName] = '\0'; - snprintf(szFileName, MAX_PATH, "%s/%s", szDirName, pszRelName); - if (0 == stat(szFileName, &stat_buf)) - { - // First, make sure we've got the canonical path - CHAR szRealPath[PATH_MAX + 1]; - - if(!realpath(szFileName, szRealPath)) - { - ASSERT("realpath() failed! problem path is %s\n", szFileName); - SetLastError(ERROR_INTERNAL_ERROR); - goto Done; - } - // We've found it. Rejoice! - TRACE("FindLibrary: found file: %s\n", szRealPath); - *ppszFullName = InternalStrdup(pThread, szRealPath); - if (!*ppszFullName) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - iRetVal = -1; - } - goto Done; - } - } - -Done: - if (rgpLibDirSeparators) - InternalFree(pThread, rgpLibDirSeparators); - if (fSearchPathNeedsFreeing) - InternalFree(pThread, pszSearchPath); - // Don't treat it as an error if the library's not found -- just set - // *ppszFullName to NULL. - return iRetVal; -} - -/*++ LOADInitCoreCLRModules Run the initialization methods for CoreCLR modules that used to be standalone dynamic libraries (PALRT and @@ -2015,5 +1759,5 @@ PAL_GetSymbolModuleBase(void *symbol) LOGEXIT("PAL_GetPalModuleBase returns %p\n", retval); PERF_EXIT(PAL_GetPalModuleBase); return retval; - } + diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp index 7097e093b5..3fcd43d0da 100644 --- a/src/pal/src/thread/process.cpp +++ b/src/pal/src/thread/process.cpp @@ -23,6 +23,7 @@ Abstract: #include "pal/thread.hpp" #include "pal/file.hpp" #include "pal/handlemgr.hpp" +#include "pal/module.h" #include "procprivate.hpp" #include "pal/palinternal.h" #include "pal/process.h" @@ -172,7 +173,18 @@ static int checkFileType(char *lpFileName); static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUnconditionally); +// +// Struct for temporary process module list +// +struct ProcessModules +{ + struct ProcessModules *Next; + PVOID BaseAddress; + CHAR Name[0]; +}; +ProcessModules *CreateProcessModules(IN HANDLE hProcess, OUT LPDWORD lpCount); +void DestroyProcessModules(IN ProcessModules *listHead); /*++ Function: @@ -1758,6 +1770,236 @@ OpenProcessExit: /*++ Function: + EnumProcessModules + +Abstract + Returns a process's module list + +Return + TRUE if it succeeded, FALSE otherwise + +Notes + This API is tricky because the module handles are never closed/freed so there can't be any + allocations for the module handle or name strings, etc. The "handles" are actually the base + addresses of the modules. The module handles should only be used by GetModuleFileNameExW + below. +--*/ +BOOL +PALAPI +EnumProcessModules( + IN HANDLE hProcess, + OUT HMODULE *lphModule, + IN DWORD cb, + OUT LPDWORD lpcbNeeded) +{ + PERF_ENTRY(EnumProcessModules); + ENTRY("EnumProcessModules(hProcess=0x%08x, cb=%d)\n", hProcess, cb); + + BOOL result = TRUE; + DWORD count = 0; + + ProcessModules *listHead = CreateProcessModules(hProcess, &count); + if (listHead != NULL) + { + for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next) + { + if (cb <= 0) + { + break; + } + cb -= sizeof(HMODULE); + *lphModule = (HMODULE)entry->BaseAddress; + lphModule++; + } + } + else + { + result = FALSE; + } + + DestroyProcessModules(listHead); + + if (lpcbNeeded) + { + // This return value isn't exactly up to spec because it should return the actual + // number of modules in the process even if "cb" isn't big enough but for our use + // it works just fine. + (*lpcbNeeded) = count * sizeof(HMODULE); + } + + LOGEXIT("EnumProcessModules returns %d\n", result); + PERF_EXIT(EnumProcessModules); + return result; +} + +/*++ +Function: + GetModuleFileNameExW + + Used only with module handles returned from EnumProcessModule (for dbgshim). + +--*/ +DWORD +PALAPI +GetModuleFileNameExW( + IN HANDLE hProcess, + IN HMODULE hModule, + OUT LPWSTR lpFilename, + IN DWORD nSize +) +{ + DWORD result = 0; + DWORD count = 0; + + ProcessModules *listHead = CreateProcessModules(hProcess, &count); + if (listHead != NULL) + { + for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next) + { + if ((HMODULE)entry->BaseAddress == hModule) + { + // Convert CHAR string into WCHAR string + result = MultiByteToWideChar(CP_ACP, 0, entry->Name, -1, lpFilename, nSize); + break; + } + } + } + + DestroyProcessModules(listHead); + + return result; +} + +/*++ +Function: + CreateProcessModules + +Abstract + Returns a process's module list + +Return + ProcessModules * list + +--*/ +ProcessModules * +CreateProcessModules( + IN HANDLE hProcess, + OUT LPDWORD lpCount) +{ + DWORD dwProcessId = PROCGetProcessIDFromHandle(hProcess); + if (dwProcessId == 0) + { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + +#ifdef HAVE_PROCFS_CTL + // Here we read /proc/<pid>/maps file in order to parse it and figure out what it says + // about a library we are looking for. This file looks something like this: + // + // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file + // + // 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so + // 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so + // 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so + // 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 [heap] + // 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so + // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so + // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so + // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so + + // Making something like: /proc/123/maps + char mapFileName[100]; + int chars = snprintf(mapFileName, sizeof(mapFileName), "/proc/%d/maps", dwProcessId); + _ASSERTE(chars > 0 && chars <= sizeof(mapFileName)); + + FILE *mapsFile = fopen(mapFileName, "r"); + if (mapsFile == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return NULL; + } + + LockModuleList(); + + CPalThread* pThread = InternalGetCurrentThread(); + ProcessModules *listHead = NULL; + char *line = NULL; + size_t lineLen = 0; + int count = 0; + ssize_t read; + + // Reading maps file line by line + while ((read = getline(&line, &lineLen, mapsFile)) != -1) + { + void *startAddress, *endAddress, *offset; + int devHi, devLo, inode; + char moduleName[PATH_MAX]; + + if (sscanf(line, "%p-%p %*[-rwxsp] %p %x:%x %d %s\n", &startAddress, &endAddress, &offset, &devHi, &devLo, &inode, moduleName) == 7) + { + if (inode != 0) + { + bool dup = false; + for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next) + { + if (strcmp(moduleName, entry->Name) == 0) + { + dup = true; + break; + } + } + + if (!dup) + { + int cbModuleName = strlen(moduleName) + 1; + ProcessModules *entry = (ProcessModules *)InternalMalloc(pThread, sizeof(ProcessModules) + cbModuleName); + if (entry == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + DestroyProcessModules(listHead); + listHead = NULL; + count = 0; + break; + } + strcpy_s(entry->Name, cbModuleName, moduleName); + entry->BaseAddress = startAddress; + entry->Next = listHead; + listHead = entry; + count++; + } + } + } + } + + *lpCount = count; + + free(line); // We didn't allocate line, but as per contract of getline we should free it + fclose(mapsFile); + UnlockModuleList(); + + return listHead; +#else + _ASSERTE(!"Not implemented on this platform"); + return NULL; +#endif +} + +void +DestroyProcessModules(IN ProcessModules *listHead) +{ + CPalThread* pThread = InternalGetCurrentThread(); + + for (ProcessModules *entry = listHead; entry != NULL; ) + { + ProcessModules *next = entry->Next; + InternalFree(pThread, entry); + entry = next; + } +} + +/*++ +Function: InitializeFlushProcessWriteBuffers Abstract |