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.
15 Implementation of internal functions to get module names
21 #include "pal/thread.hpp"
22 #include "pal/malloc.hpp"
23 #include "pal/palinternal.h"
24 #include "pal/dbgmsg.h"
25 #include "pal/modulename.h"
29 #else // NEED_DLCOMPAT
31 #endif // NEED_DLCOMPAT
37 using namespace CorUnix;
39 SET_DEFAULT_DEBUG_CHANNEL(LOADER);
43 GetLibRotorNameViaLoadQuery
45 Retrieve the full path of the librotor_pal.so using loadquery()
48 pszBuf - CHAR array of MAX_PATH_FNAME length
52 -1 on failure, with last error set
54 int GetLibRotorNameViaLoadQuery(LPSTR pszBuf)
56 CHAR* pLoadQueryBuf = NULL;
58 struct ld_info * pInfo = NULL;
61 CPalThread *pThread = NULL;
65 ASSERT("GetLibRotorNameViaLoadQuery requires non-NULL pszBuf\n");
66 SetLastError(ERROR_INTERNAL_ERROR);
70 pThread = InternalGetCurrentThread();
71 // Loop trying to call loadquery with enough memory until either
72 // 1) we succeed, 2) we run out of memory or 3) loadquery throws
73 // an error other than ENOMEM
74 while (iLQRetVal != 0)
76 pLoadQueryBuf = (CHAR*) InternalMalloc (pThread, cbBuf * sizeof(char));
79 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
82 iLQRetVal = loadquery(L_GETINFO, pLoadQueryBuf, cbBuf);
85 free(pThread, pLoadQueryBuf);
87 DWORD dwLastError = GetLastError();
88 if (dwLastError == ERROR_NOT_ENOUGH_MEMORY)
90 // The buffer's too small. Try twice as large as a guess...
95 SetLastError(ERROR_INTERNAL_ERROR);
101 // We successfully called loadquery, so now see if we can find
102 // librotor_pal.a in the module list
105 pInfo = (struct ld_info *)pLoadQueryBuf;
108 if (strstr(pInfo->ldinfo_filename, "librotor_pal.a"))
110 UINT cchFileName = strlen(pInfo->ldinfo_filename);
111 if (cchFileName + 1 > MAX_PATH_FNAME)
113 ASSERT("Filename returned by loadquery was longer than MAX_PATH_FNAME!\n");
114 SetLastError(ERROR_INTERNAL_ERROR);
119 // The buffer should be large enough to accomodate the filename.
120 // So, we send in the size of the filename+1
121 strcpy_s(pszBuf, MAX_PATH_FNAME, pInfo->ldinfo_filename);
128 // The (wacky) design of ld_info is that the value of next is an offset in
129 // bytes rather than a pointer. So we need this weird cast to char * to get
130 // the pointer math correct.
131 if (pInfo->ldinfo_next == 0)
134 pInfo = (struct ld_info *) ((char *)pInfo + pInfo->ldinfo_next);
140 free(pThread, pLoadQueryBuf);
143 #endif // defined(_AIX)
148 Internal wrapper for dladder used only to get module name
154 Pointer to string with the fullpath to the librotor_pal.so being
157 NULL if error occurred.
160 The string returned by this function is owned by the OS.
161 If you need to keep it, strdup() it, because it is unknown how long
162 this ptr will point at the string you want (over the lifetime of
163 the system running) It is only safe to use it immediately after calling
166 const char *PAL_dladdr(LPVOID ProcAddress)
168 #if defined(_AIX) || defined(__hppa__)
169 /* dladdr is not supported on AIX or 32-bit HPUX-PARISC */
171 #elif defined(_HPUX_) && defined(_IA64_)
172 /* dladdr is not supported on HP-UX/IA64. That said, PAL_dladdr just returns to module name
173 and we can get that via dlgetname. So use that for HPUX. */
175 char* pszName = NULL;
176 load_module_desc desc;
177 __uint64_t uimodret = NULL;
178 uimodret = dlmodinfo((__uint64_t)ProcAddress, &desc, sizeof(desc), NULL, 0, 0);
181 WARN("dlmodinfo call failed! dlerror says '%s'\n", dlerror());
184 pszName = dlgetname(&desc, sizeof(desc), NULL, 0, 0);
187 WARN("dlgetname desc didn't describe a loaded module?! dlerror says '%s'\n", dlerror());
194 if (!dladdr(ProcAddress, &dl_info))
196 WARN("dladdr() call failed! dlerror says '%s'\n", dlerror());
197 /* If we get an error, return NULL */
202 /* Return the module name */
203 return dl_info.dli_fname;