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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 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 /*****************************************************************************/ 133 void SAL_CALL osl_unloadModule(oslModule Module) 134 { 135 FreeLibrary((HINSTANCE)Module); 136 } 137 138 /*****************************************************************************/ 139 /* osl_getSymbol */ 140 /*****************************************************************************/ 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 /*****************************************************************************/ 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 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 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 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 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 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 /*****************************************************************************/ 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