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