summaryrefslogtreecommitdiff
path: root/src/pal/src/loader/modulename.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/loader/modulename.cpp')
-rw-r--r--src/pal/src/loader/modulename.cpp207
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
+}
+