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