diff options
Diffstat (limited to 'src/pal/src/loader/modulename.cpp')
-rw-r--r-- | src/pal/src/loader/modulename.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/pal/src/loader/modulename.cpp b/src/pal/src/loader/modulename.cpp new file mode 100644 index 0000000000..026f89b3ea --- /dev/null +++ b/src/pal/src/loader/modulename.cpp @@ -0,0 +1,207 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*++ + + + +Module Name: + + modulename.cpp + +Abstract: + + Implementation of internal functions to get module names + + + +--*/ + +#include "pal/thread.hpp" +#include "pal/malloc.hpp" +#include "pal/palinternal.h" +#include "pal/dbgmsg.h" +#include "pal/modulename.h" + +#if NEED_DLCOMPAT +#include "dlcompat.h" +#else // NEED_DLCOMPAT +#include <dlfcn.h> +#endif // NEED_DLCOMPAT + +#if defined(_AIX) +#include <sys/ldr.h> +#endif + +using namespace CorUnix; + +SET_DEFAULT_DEBUG_CHANNEL(LOADER); + +#if defined(_AIX) +/*++ + GetLibRotorNameViaLoadQuery + + Retrieve the full path of the librotor_pal.so using loadquery() + +Parameters: + pszBuf - CHAR array of MAX_PATH_FNAME length + +Return value: + 0 on success + -1 on failure, with last error set +--*/ +int GetLibRotorNameViaLoadQuery(LPSTR pszBuf) +{ + CHAR* pLoadQueryBuf = NULL; + UINT cbBuf = 1024; + struct ld_info * pInfo = NULL; + INT iLQRetVal = -1; + INT iRetVal = -1; + CPalThread *pThread = NULL; + + if (!pszBuf) + { + ASSERT("GetLibRotorNameViaLoadQuery requires non-NULL pszBuf\n"); + SetLastError(ERROR_INTERNAL_ERROR); + goto Done; + } + + pThread = InternalGetCurrentThread(); + // Loop trying to call loadquery with enough memory until either + // 1) we succeed, 2) we run out of memory or 3) loadquery throws + // an error other than ENOMEM + while (iLQRetVal != 0) + { + pLoadQueryBuf = (CHAR*) InternalMalloc (pThread, cbBuf * sizeof(char)); + if (!pLoadQueryBuf) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto Done; + } + iLQRetVal = loadquery(L_GETINFO, pLoadQueryBuf, cbBuf); + if (iLQRetVal < 0) + { + free(pThread, pLoadQueryBuf); + pLoadQueryBuf = NULL; + DWORD dwLastError = GetLastError(); + if (dwLastError == ERROR_NOT_ENOUGH_MEMORY) + { + // The buffer's too small. Try twice as large as a guess... + cbBuf *= 2; + } + else + { + SetLastError(ERROR_INTERNAL_ERROR); + goto Done; + } + } + } + + // We successfully called loadquery, so now see if we can find + // librotor_pal.a in the module list + if (pLoadQueryBuf) + { + pInfo = (struct ld_info *)pLoadQueryBuf; + while (TRUE) + { + if (strstr(pInfo->ldinfo_filename, "librotor_pal.a")) + { + UINT cchFileName = strlen(pInfo->ldinfo_filename); + if (cchFileName + 1 > MAX_PATH_FNAME) + { + ASSERT("Filename returned by loadquery was longer than MAX_PATH_FNAME!\n"); + SetLastError(ERROR_INTERNAL_ERROR); + goto Done; + } + else + { + // The buffer should be large enough to accomodate the filename. + // So, we send in the size of the filename+1 + strcpy_s(pszBuf, MAX_PATH_FNAME, pInfo->ldinfo_filename); + iRetVal = 0; + goto Done; + } + } + else + { + // The (wacky) design of ld_info is that the value of next is an offset in + // bytes rather than a pointer. So we need this weird cast to char * to get + // the pointer math correct. + if (pInfo->ldinfo_next == 0) + break; + else + pInfo = (struct ld_info *) ((char *)pInfo + pInfo->ldinfo_next); + } + } + } +Done: + if (pLoadQueryBuf) + free(pThread, pLoadQueryBuf); + return iRetVal; +} +#endif // defined(_AIX) + +/*++ + PAL_dladdr + + Internal wrapper for dladder used only to get module name + +Parameters: + None + +Return value: + Pointer to string with the fullpath to the librotor_pal.so being + used. + + NULL if error occurred. + +Notes: + The string returned by this function is owned by the OS. + If you need to keep it, strdup() it, because it is unknown how long + this ptr will point at the string you want (over the lifetime of + the system running) It is only safe to use it immediately after calling + this function. +--*/ +const char *PAL_dladdr(LPVOID ProcAddress) +{ +#if defined(_AIX) || defined(__hppa__) + /* dladdr is not supported on AIX or 32-bit HPUX-PARISC */ + return (NULL); +#elif defined(_HPUX_) && defined(_IA64_) + /* dladdr is not supported on HP-UX/IA64. That said, PAL_dladdr just returns to module name + and we can get that via dlgetname. So use that for HPUX. */ + { + char* pszName = NULL; + load_module_desc desc; + __uint64_t uimodret = NULL; + uimodret = dlmodinfo((__uint64_t)ProcAddress, &desc, sizeof(desc), NULL, 0, 0); + if (!uimodret) + { + WARN("dlmodinfo call failed! dlerror says '%s'\n", dlerror()); + return NULL; + } + pszName = dlgetname(&desc, sizeof(desc), NULL, 0, 0); + if (!pszName) + { + WARN("dlgetname desc didn't describe a loaded module?! dlerror says '%s'\n", dlerror()); + return NULL; + } + return pszName; + } +#else + Dl_info dl_info; + if (!dladdr(ProcAddress, &dl_info)) + { + WARN("dladdr() call failed! dlerror says '%s'\n", dlerror()); + /* If we get an error, return NULL */ + return (NULL); + } + else + { + /* Return the module name */ + return dl_info.dli_fname; + } +#endif +} + |