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 compatible 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 available on NT 4. But MSDN from Platform SDK says Win 2K is required. MSDN from VS 6.0a says
314 it's OK 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 recursively scans subdirectories of
323 the root when calling SymInitialize(), so we prefer DBGHELP.DLL
324 which exports the same symbols and is shipped with AOO */
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 Library 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