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 /*****************************************************************************/ 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, rtl::Allocator<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 /*****************************************************************************/ 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 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 /*****************************************************************************/ 135 void SAL_CALL osl_unloadModule(oslModule Module) 136 { 137 FreeLibrary((HINSTANCE)Module); 138 } 139 140 /*****************************************************************************/ 141 /* osl_getSymbol */ 142 /*****************************************************************************/ 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 /*****************************************************************************/ 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 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 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 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 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 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 /*****************************************************************************/ 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