xref: /AOO41X/main/sal/osl/w32/module.cxx (revision 79e556ee827beb4823bf162e2fd4108e56b8fd4e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "system.h"
25 #include <tlhelp32.h>
26 
27 #include "file_url.h"
28 #include "path_helper.hxx"
29 
30 #include <osl/module.h>
31 #include <osl/diagnose.h>
32 #include <osl/thread.h>
33 #include <osl/file.h>
34 #include <rtl/logfile.h>
35 #include <vector>
36 
37 /*
38     under WIN32, we use the void* oslModule
39     as a WIN32 HANDLE (which is also a 32-bit value)
40 */
41 
42 /*****************************************************************************/
43 /* osl_loadModule */
44 /*****************************************************************************/
osl_loadModule(rtl_uString * strModuleName,sal_Int32 nRtldMode)45 oslModule SAL_CALL osl_loadModule(rtl_uString *strModuleName, sal_Int32 nRtldMode )
46 {
47     HINSTANCE hInstance;
48     UINT errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
49     rtl_uString* Module = NULL;
50     oslModule ret = 0;
51     oslFileError    nError;
52 
53     RTL_LOGFILE_TRACE1( "{ osl_loadModule start: %S", (LPTSTR)&strModuleName->buffer );
54 
55     OSL_ASSERT(strModuleName);
56 
57     nRtldMode = nRtldMode; /* avoid warnings */
58 
59     nError = osl_getSystemPathFromFileURL(strModuleName, &Module);
60 
61     if ( osl_File_E_None != nError )
62         rtl_uString_assign(&Module, strModuleName);
63 
64     hInstance = LoadLibraryW(reinterpret_cast<LPCWSTR>(Module->buffer));
65 
66     if (hInstance == NULL)
67         hInstance = LoadLibraryExW(reinterpret_cast<LPCWSTR>(Module->buffer), NULL,
68                                   LOAD_WITH_ALTERED_SEARCH_PATH);
69 
70     //In case of long path names (\\?\c:\...) try to shorten the filename.
71     //LoadLibrary cannot handle file names which exceed 260 letters.
72     //In case the path is to long, the function will fail. However, the error
73     //code can be different. For example, it returned  ERROR_FILENAME_EXCED_RANGE
74     //on Windows XP and ERROR_INSUFFICIENT_BUFFER on Windows 7 (64bit)
75     if (hInstance == NULL && Module->length > 260)
76     {
77         std::vector<WCHAR> vec(Module->length + 1);
78         DWORD len = GetShortPathNameW(reinterpret_cast<LPCWSTR>(Module->buffer),
79                                       &vec[0], Module->length + 1);
80         if (len )
81         {
82             hInstance = LoadLibraryW(&vec[0]);
83 
84             if (hInstance == NULL)
85                 hInstance = LoadLibraryExW(&vec[0], NULL,
86                                   LOAD_WITH_ALTERED_SEARCH_PATH);
87         }
88     }
89 
90 
91     if (hInstance <= (HINSTANCE)HINSTANCE_ERROR)
92         hInstance = 0;
93 
94     ret = (oslModule) hInstance;
95     rtl_uString_release(Module);
96     SetErrorMode(errorMode);
97 
98     RTL_LOGFILE_TRACE1( "} osl_loadModule end: %S", (LPTSTR)&strModuleName->buffer );
99 
100     return ret;
101 }
102 
103 /*****************************************************************************/
104 /* osl_loadAsciiModule */
105 /*****************************************************************************/
osl_loadAsciiModule(const sal_Char * pModuleName,sal_Int32 nRtldMode)106 oslModule SAL_CALL osl_loadAsciiModule( const sal_Char* pModuleName, sal_Int32 nRtldMode )
107 {
108     rtl_uString* pUniName = NULL;
109     rtl_uString_newFromAscii( &pUniName, pModuleName );
110     oslModule aModule = osl_loadModule( pUniName, nRtldMode );
111     rtl_uString_release( pUniName );
112     return aModule;
113 }
114 
115 /*****************************************************************************/
116 /* osl_getModuleHandle */
117 /*****************************************************************************/
118 
119 sal_Bool SAL_CALL
osl_getModuleHandle(rtl_uString * pModuleName,oslModule * pResult)120 osl_getModuleHandle(rtl_uString *pModuleName, oslModule *pResult)
121 {
122     HINSTANCE hInstance = GetModuleHandleW(reinterpret_cast<LPCWSTR>(pModuleName->buffer));
123     if( hInstance )
124     {
125         *pResult = (oslModule) hInstance;
126         return sal_True;
127     }
128 
129     return sal_False;
130 }
131 
132 /*****************************************************************************/
133 /* osl_unloadModule */
134 /*****************************************************************************/
osl_unloadModule(oslModule Module)135 void SAL_CALL osl_unloadModule(oslModule Module)
136 {
137     FreeLibrary((HINSTANCE)Module);
138 }
139 
140 /*****************************************************************************/
141 /* osl_getSymbol */
142 /*****************************************************************************/
osl_getSymbol(oslModule Module,rtl_uString * strSymbolName)143 void* SAL_CALL osl_getSymbol(oslModule Module, rtl_uString *strSymbolName)
144 {
145     /* casting from a function pointer to a data pointer is invalid
146        be in this case unavoidable because the API has to stay
147        compitable we need to keep this function which returns a
148        void* by definition */
149 #ifdef _MSC_VER
150 #pragma warning(push)
151 #pragma warning(disable:4054)
152 #endif
153     return (void*)(osl_getFunctionSymbol(Module, strSymbolName));
154 #ifdef _MSC_VER
155 #pragma warning(pop)
156 #endif
157 }
158 
159 /*****************************************************************************/
160 /* osl_getFunctionSymbol */
161 /*****************************************************************************/
osl_getFunctionSymbol(oslModule Module,rtl_uString * strSymbolName)162 oslGenericFunction SAL_CALL osl_getFunctionSymbol( oslModule Module, rtl_uString *strSymbolName )
163 {
164     rtl_String *symbolName = NULL;
165     oslGenericFunction address;
166 
167     OSL_ASSERT(Module);
168     OSL_ASSERT(strSymbolName);
169 
170     rtl_uString2String(
171         &symbolName,
172         strSymbolName->buffer,
173         strSymbolName->length,
174         RTL_TEXTENCODING_UTF8,
175         OUSTRING_TO_OSTRING_CVTFLAGS
176     );
177 
178     address=osl_getAsciiFunctionSymbol(Module, rtl_string_getStr(symbolName));
179     rtl_string_release(symbolName);
180 
181     return address;
182 }
183 
184 /*****************************************************************************/
185 /* osl_getAsciiFunctionSymbol */
186 /*****************************************************************************/
187 oslGenericFunction SAL_CALL
osl_getAsciiFunctionSymbol(oslModule Module,const sal_Char * pSymbol)188 osl_getAsciiFunctionSymbol( oslModule Module, const sal_Char *pSymbol )
189 {
190     oslGenericFunction fncAddr = NULL;
191 
192     if( pSymbol )
193         fncAddr=(oslGenericFunction)GetProcAddress((HINSTANCE) Module, pSymbol);
194 
195     return fncAddr;
196 }
197 
198 
199 
200 /*****************************************************************************/
201 /* osl_addressGetModuleURL */
202 /*****************************************************************************/
203 
204 /*****************************************************************************/
205 /* Implementation for Windows 95, 98 and Me */
206 /*****************************************************************************/
207 
208 /* Undefine because there is no explicit "A" definition */
209 
210 #ifdef MODULEENTRY32
211 #undef MODULEENTRY32
212 #endif
213 
214 #ifdef LPMODULEENTRY32
215 #undef LPMODULEENTRY32
216 #endif
217 
218 typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_PROC)( DWORD dwFlags, DWORD th32ProcessID );
219 typedef BOOL (WINAPI *Module32First_PROC)( HANDLE   hSnapshot, LPMODULEENTRY32 lpme32 );
220 typedef BOOL (WINAPI *Module32Next_PROC)( HANDLE    hSnapshot, LPMODULEENTRY32 lpme32 );
221 
_osl_addressGetModuleURL_Windows(void * pv,rtl_uString ** pustrURL)222 static sal_Bool SAL_CALL _osl_addressGetModuleURL_Windows( void *pv, rtl_uString **pustrURL )
223 {
224     sal_Bool    bSuccess        = sal_False;    /* Assume failure */
225     HMODULE     hModKernel32    = GetModuleHandleA( "KERNEL32.DLL" );
226 
227     if ( hModKernel32 )
228     {
229         CreateToolhelp32Snapshot_PROC   lpfnCreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_PROC)GetProcAddress( hModKernel32, "CreateToolhelp32Snapshot" );
230         Module32First_PROC              lpfnModule32First = (Module32First_PROC)GetProcAddress( hModKernel32, "Module32First" );
231         Module32Next_PROC               lpfnModule32Next = (Module32Next_PROC)GetProcAddress( hModKernel32, "Module32Next" );
232 
233         if ( lpfnCreateToolhelp32Snapshot && lpfnModule32First && lpfnModule32Next )
234         {
235             HANDLE  hModuleSnap = NULL;
236             DWORD   dwProcessId = GetCurrentProcessId();
237 
238             // Take a snapshot of all modules in the specified process.
239 
240             hModuleSnap = lpfnCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId );
241 
242             if ( INVALID_HANDLE_VALUE != hModuleSnap )
243             {
244                 MODULEENTRY32   me32    = {0};
245 
246                 // Fill the size of the structure before using it.
247 
248                 me32.dwSize = sizeof(MODULEENTRY32);
249 
250                 // Walk the module list of the process, and find the module of
251                 // interest. Then copy the information to the buffer pointed
252                 // to by lpMe32 so that it can be returned to the caller.
253 
254                 if ( lpfnModule32First(hModuleSnap, &me32) )
255                 {
256                     do
257                     {
258                         if ( (BYTE *)pv >= (BYTE *)me32.hModule && (BYTE *)pv < (BYTE *)me32.hModule + me32.modBaseSize )
259                         {
260                             rtl_uString *ustrSysPath = NULL;
261 
262                             rtl_string2UString( &ustrSysPath, me32.szExePath, strlen(me32.szExePath), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
263                             OSL_ASSERT(ustrSysPath != NULL);
264                             osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
265                             rtl_uString_release( ustrSysPath );
266 
267                             bSuccess = sal_True;
268                         }
269 
270                     } while ( !bSuccess && lpfnModule32Next( hModuleSnap, &me32 ) );
271                 }
272 
273 
274                 // Do not forget to clean up the snapshot object.
275 
276                 CloseHandle (hModuleSnap);
277             }
278 
279         }
280     }
281 
282     return  bSuccess;
283 }
284 
285 /***************************************************************************************/
286 /* Implementation for Windows NT, 2K and XP (2K and XP could use the above method too) */
287 /***************************************************************************************/
288 
289 #ifdef _MSC_VER
290 #pragma warning(push,1) /* disable warnings within system headers */
291 #endif
292 #include <imagehlp.h>
293 #ifdef _MSC_VER
294 #pragma warning(pop)
295 #endif
296 
297 typedef BOOL (WINAPI *SymInitialize_PROC)(
298     HANDLE   hProcess,
299     LPSTR    UserSearchPath,
300     BOOL     fInvadeProcess
301     );
302 
303 typedef BOOL (WINAPI *SymCleanup_PROC)(
304     HANDLE hProcess
305     );
306 
307 typedef BOOL (WINAPI *SymGetModuleInfo_PROC)(
308     HANDLE              hProcess,
309     DWORD               dwAddr,
310     PIMAGEHLP_MODULE  ModuleInfo
311     );
312 
313 /* Seems that IMAGEHLP.DLL is always availiable on NT 4. But MSDN from Platform SDK says Win 2K is required. MSDN from VS 6.0a says
314     it's O.K on NT 4 ???!!!
315     BTW: We are using ANSI function because not all version of IMAGEHLP.DLL contain Unicode support
316 */
317 
_osl_addressGetModuleURL_NT4(void * pv,rtl_uString ** pustrURL)318 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT4( void *pv, rtl_uString **pustrURL )
319 {
320     sal_Bool    bSuccess    = sal_False;    /* Assume failure */
321 
322     /*  IMAGEHELP.DLL has a bug that it recursivly scans subdirectories of
323         the root when calling SymInitialize(), so we preferr DBGHELP.DLL
324         which exports the same symbols and is shipped with OOo */
325 
326     HMODULE     hModImageHelp = LoadLibrary( "DBGHELP.DLL" );
327 
328     if ( !hModImageHelp )
329         hModImageHelp = LoadLibrary( "IMAGEHLP.DLL" );
330 
331     if ( hModImageHelp )
332     {
333         SymGetModuleInfo_PROC   lpfnSymGetModuleInfo;
334         SymInitialize_PROC      lpfnSymInitialize;
335         SymCleanup_PROC         lpfnSymCleanup;
336 
337 
338         lpfnSymInitialize = (SymInitialize_PROC)GetProcAddress( hModImageHelp, "SymInitialize" );
339         lpfnSymCleanup = (SymCleanup_PROC)GetProcAddress( hModImageHelp, "SymCleanup" );
340         lpfnSymGetModuleInfo = (SymGetModuleInfo_PROC)GetProcAddress( hModImageHelp, "SymGetModuleInfo" );
341 
342 
343         if ( lpfnSymInitialize && lpfnSymCleanup && lpfnSymGetModuleInfo )
344         {
345             IMAGEHLP_MODULE ModuleInfo;
346             ::osl::LongPathBuffer< sal_Char > aModuleFileName( MAX_LONG_PATH );
347             LPSTR   lpSearchPath = NULL;
348 
349             if ( GetModuleFileNameA( NULL, aModuleFileName, aModuleFileName.getBufSizeInSymbols() ) )
350             {
351                 char *pLastBkSlash = strrchr( aModuleFileName, '\\' );
352 
353                 if (
354                     pLastBkSlash &&
355                     pLastBkSlash > (sal_Char*)aModuleFileName
356                     && *(pLastBkSlash - 1) != ':'
357                     && *(pLastBkSlash - 1) != '\\'
358                     )
359                 {
360                     *pLastBkSlash = 0;
361                     lpSearchPath = aModuleFileName;
362                 }
363             }
364 
365             lpfnSymInitialize( GetCurrentProcess(), lpSearchPath, TRUE );
366 
367             ZeroMemory( &ModuleInfo, sizeof(ModuleInfo) );
368             ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
369 
370             bSuccess = (sal_Bool)(!!lpfnSymGetModuleInfo( GetCurrentProcess(), (DWORD)pv, &ModuleInfo ));
371 
372             if ( bSuccess )
373             {
374                 /*  #99182 On localized (non-english) NT4 and XP (!!!) for some libraries the LoadedImageName member of ModuleInfo isn't filled. Because
375                     other members ModuleName and ImageName do not contain the full path we can cast the Member
376                     BaseOfImage to a HMODULE (on NT it's the same) and use GetModuleFileName to retrieve the full
377                     path of the loaded image */
378 
379                 if ( ModuleInfo.LoadedImageName[0] || GetModuleFileNameA( (HMODULE)ModuleInfo.BaseOfImage, ModuleInfo.LoadedImageName, sizeof(ModuleInfo.LoadedImageName) ) )
380                 {
381                     rtl_uString *ustrSysPath = NULL;
382 
383                     rtl_string2UString( &ustrSysPath, ModuleInfo.LoadedImageName, strlen(ModuleInfo.LoadedImageName), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
384                     OSL_ASSERT(ustrSysPath != NULL);
385                     osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
386                     rtl_uString_release( ustrSysPath );
387                 }
388                 else
389                     bSuccess = sal_False;
390             }
391 
392             lpfnSymCleanup( GetCurrentProcess() );
393         }
394 
395         FreeLibrary( hModImageHelp );
396     }
397 
398     return bSuccess;
399 }
400 
401 
402 typedef struct _MODULEINFO {
403     LPVOID lpBaseOfDll;
404     DWORD SizeOfImage;
405     LPVOID EntryPoint;
406 } MODULEINFO, *LPMODULEINFO;
407 
408 typedef BOOL (WINAPI *EnumProcessModules_PROC)(
409   HANDLE hProcess,      // handle to the process
410   HMODULE * lphModule,  // array to receive the module handles
411   DWORD cb,             // size of the array
412   LPDWORD lpcbNeeded    // receives the number of bytes returned
413 );
414 
415 typedef BOOL (WINAPI *GetModuleInformation_PROC)(
416   HANDLE hProcess,         // handle to the process
417   HMODULE hModule,         // handle to the module
418   LPMODULEINFO lpmodinfo,  // structure that receives information
419   DWORD cb                 // size of the structure
420 );
421 
422 #define bufsizeof(buffer) (sizeof(buffer) / sizeof((buffer)[0]))
423 
424 /* This version can fail because PSAPI.DLL is not always part of NT 4 despite MSDN Libary 6.0a say so */
425 
_osl_addressGetModuleURL_NT(void * pv,rtl_uString ** pustrURL)426 static sal_Bool SAL_CALL _osl_addressGetModuleURL_NT( void *pv, rtl_uString **pustrURL )
427 {
428     sal_Bool    bSuccess    = sal_False;    /* Assume failure */
429     static HMODULE      hModPsapi = NULL;
430 
431     if ( !hModPsapi )
432         hModPsapi = LoadLibrary( "PSAPI.DLL" );
433 
434     if ( hModPsapi )
435     {
436         EnumProcessModules_PROC     lpfnEnumProcessModules      = (EnumProcessModules_PROC)GetProcAddress( hModPsapi, "EnumProcessModules" );
437         GetModuleInformation_PROC   lpfnGetModuleInformation    = (GetModuleInformation_PROC)GetProcAddress( hModPsapi, "GetModuleInformation" );
438 
439         if ( lpfnEnumProcessModules && lpfnGetModuleInformation )
440         {
441             DWORD       cbNeeded = 0;
442             HMODULE     *lpModules = NULL;
443             DWORD       nModules = 0;
444             UINT        iModule = 0;
445             MODULEINFO  modinfo;
446 
447             lpfnEnumProcessModules( GetCurrentProcess(), NULL, 0, &cbNeeded );
448 
449             lpModules = (HMODULE *)_alloca( cbNeeded );
450             lpfnEnumProcessModules( GetCurrentProcess(), lpModules, cbNeeded, &cbNeeded );
451 
452             nModules = cbNeeded / sizeof(HMODULE);
453 
454             for ( iModule = 0; !bSuccess && iModule < nModules; iModule++ )
455             {
456                 lpfnGetModuleInformation( GetCurrentProcess(), lpModules[iModule], &modinfo, sizeof(modinfo) );
457 
458                 if ( (BYTE *)pv >= (BYTE *)modinfo.lpBaseOfDll && (BYTE *)pv < (BYTE *)modinfo.lpBaseOfDll + modinfo.SizeOfImage )
459                 {
460                     ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
461                     rtl_uString *ustrSysPath = NULL;
462 
463                     GetModuleFileNameW( lpModules[iModule], ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), aBuffer.getBufSizeInSymbols() );
464 
465                     rtl_uString_newFromStr( &ustrSysPath, aBuffer );
466                     osl_getFileURLFromSystemPath( ustrSysPath, pustrURL );
467                     rtl_uString_release( ustrSysPath );
468 
469                     bSuccess = sal_True;
470                 }
471             }
472         }
473 
474     }
475 
476     return bSuccess;
477 }
478 
479 /*****************************************************************************/
480 /* Dispatcher for osl_osl_addressGetModuleURL */
481 /*****************************************************************************/
482 
osl_getModuleURLFromAddress(void * pv,rtl_uString ** pustrURL)483 sal_Bool SAL_CALL osl_getModuleURLFromAddress( void *pv, rtl_uString **pustrURL )
484 {
485     /* Use ..._NT first because ..._NT4 is much slower */
486     if ( IS_NT )
487         return _osl_addressGetModuleURL_NT( pv, pustrURL ) || _osl_addressGetModuleURL_NT4( pv, pustrURL );
488     else
489         return _osl_addressGetModuleURL_Windows( pv, pustrURL );
490 }
491 
492 /*****************************************************************************/
493 /* osl_getModuleURLFromFunctionAddress */
494 /*****************************************************************************/
osl_getModuleURLFromFunctionAddress(oslGenericFunction addr,rtl_uString ** ppLibraryUrl)495 sal_Bool SAL_CALL osl_getModuleURLFromFunctionAddress( oslGenericFunction addr, rtl_uString ** ppLibraryUrl )
496 {
497     /* casting a function pointer to a data pointer (void*) is
498        not allowed according to the C/C++ standards. In this case
499        it is unavoidable because we have to stay compatible we
500        cannot remove any function. */
501 #ifdef _MSC_VER
502 #pragma warning(push)
503 #pragma warning(disable:4054)
504 #endif
505     return osl_getModuleURLFromAddress((void*)addr, ppLibraryUrl);
506 #ifdef _MSC_VER
507 #pragma warning(pop)
508 #endif
509 }
510 
511 
512