1 /* 2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 #include "Platform.h" 35 36 #ifdef WINDOWS 37 38 #include "WindowsPlatform.h" 39 #include "Package.h" 40 #include "Helpers.h" 41 #include "PlatformString.h" 42 #include "Macros.h" 43 44 #include <map> 45 #include <vector> 46 #include <regex> 47 48 49 //-------------------------------------------------------------------------------------------------- 50 51 class Registry { 52 private: 53 HKEY FKey; 54 HKEY FOpenKey; 55 bool FOpen; 56 57 public: 58 Registry(HKEY Key) { 59 FOpen = false; 60 FKey = Key; 61 } 62 63 ~Registry() { 64 Close(); 65 } 66 67 void Close() { 68 if (FOpen == true) { 69 RegCloseKey(FOpenKey); 70 } 71 } 72 73 bool Open(TString SubKey) { 74 bool result = false; 75 Close(); 76 77 if (RegOpenKeyEx(FKey, SubKey.data(), 0, KEY_READ, &FOpenKey) == ERROR_SUCCESS) { 78 result = true; 79 } 80 81 return result; 82 } 83 84 std::list<TString> GetKeys() { 85 std::list<TString> result; 86 DWORD count; 87 88 if (RegQueryInfoKey(FOpenKey, NULL, NULL, NULL, NULL, NULL, NULL, 89 &count, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { 90 91 DWORD length = 255; 92 DynamicBuffer<TCHAR> buffer(length); 93 94 for (unsigned int index = 0; index < count; index++) { 95 buffer.Zero(); 96 DWORD status = RegEnumValue(FOpenKey, index, buffer.GetData(), 97 &length, NULL, NULL, NULL, NULL); 98 99 while (status == ERROR_MORE_DATA) { 100 length = length * 2; 101 buffer.Resize(length); 102 status = RegEnumValue(FOpenKey, index, buffer.GetData(), 103 &length, NULL, NULL, NULL, NULL); 104 } 105 106 if (status == ERROR_SUCCESS) { 107 TString value = buffer.GetData(); 108 result.push_back(value); 109 } 110 } 111 } 112 113 return result; 114 } 115 116 TString ReadString(TString Name) { 117 TString result; 118 DWORD length; 119 DWORD dwRet; 120 DynamicBuffer<wchar_t> buffer(0); 121 length = 0; 122 123 dwRet = RegQueryValueEx(FOpenKey, Name.data(), NULL, NULL, NULL, &length); 124 if (dwRet == ERROR_MORE_DATA || dwRet == 0) { 125 buffer.Resize(length + 1); 126 dwRet = RegQueryValueEx(FOpenKey, Name.data(), NULL, NULL, (LPBYTE)buffer.GetData(), &length); 127 result = buffer.GetData(); 128 } 129 130 return result; 131 } 132 }; 133 134 //-------------------------------------------------------------------------------------------------- 135 136 WindowsPlatform::WindowsPlatform(void) : Platform(), GenericPlatform() { 137 FMainThread = ::GetCurrentThreadId(); 138 } 139 140 WindowsPlatform::~WindowsPlatform(void) { 141 } 142 143 TCHAR* WindowsPlatform::ConvertStringToFileSystemString(TCHAR* Source, bool &release) { 144 // Not Implemented. 145 return NULL; 146 } 147 148 TCHAR* WindowsPlatform::ConvertFileSystemStringToString(TCHAR* Source, bool &release) { 149 // Not Implemented. 150 return NULL; 151 } 152 153 void WindowsPlatform::SetCurrentDirectory(TString Value) { 154 _wchdir(Value.data()); 155 } 156 157 TString WindowsPlatform::GetPackageRootDirectory() { 158 TString filename = GetModuleFileName(); 159 return FilePath::ExtractFilePath(filename); 160 } 161 162 TString WindowsPlatform::GetAppDataDirectory() { 163 TString result; 164 TCHAR path[MAX_PATH]; 165 166 if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path) == S_OK) { 167 result = path; 168 } 169 170 return result; 171 } 172 173 #define JAVA_RUNTIME_SUBKEY _T("SOFTWARE\\JavaSoft\\Java Runtime Environment") 174 #define BUFFER_SIZE 256 175 176 // try to find current Java Home from registry 177 // HKLM\Software\JavaSoft\Java Runtime Environment\CurrentVersion 178 // HKLM\Software\JavaSoft\Java Runtime Environment\[CurrentVersion]\JavaHome 179 // return TRUE if found, and path is set in lpszJavaHome 180 // return FALSE otherwise 181 TString WindowsPlatform::GetSystemJRE() { 182 TString result; 183 Registry registry(HKEY_LOCAL_MACHINE); 184 185 if (registry.Open(JAVA_RUNTIME_SUBKEY) == true) { 186 TString version = registry.ReadString(_T("CurrentVersion")); 187 188 if (version.empty() == false) { 189 if (registry.Open(JAVA_RUNTIME_SUBKEY + TString(_T("\\")) + TString(version)) == true) { 190 TString javaHome = registry.ReadString(_T("JavaHome")); 191 192 if (FilePath::DirectoryExists(javaHome) == true) { 193 result = javaHome; 194 } 195 } 196 } 197 } 198 199 return result; 200 } 201 202 void WindowsPlatform::ShowMessage(TString title, TString description) { 203 MessageBox(NULL, description.data(), !title.empty() ? title.data() : description.data(), MB_ICONERROR | MB_OK); 204 } 205 206 void WindowsPlatform::ShowMessage(TString description) { 207 TString appname = GetModuleFileName(); 208 appname = FilePath::ExtractFileName(appname); 209 MessageBox(NULL, appname.data(), description.data(), MB_ICONERROR | MB_OK); 210 } 211 212 TString WindowsPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) { 213 214 TString result = FilePath::IncludeTrailingSlash(RuntimePath) + 215 _T("jre\\bin\\client\\jvm.dll"); 216 217 if (FilePath::FileExists(result) == false) { 218 result = FilePath::IncludeTrailingSlash(RuntimePath) + 219 _T("jre\\bin\\server\\jvm.dll"); 220 } 221 222 if (FilePath::FileExists(result) == false) { 223 result = FilePath::IncludeTrailingSlash(RuntimePath) + 224 _T("bin\\client\\jvm.dll"); 225 } 226 227 if (FilePath::FileExists(result) == false) { 228 result = FilePath::IncludeTrailingSlash(RuntimePath) + 229 _T("bin\\server\\jvm.dll"); 230 } 231 232 return result; 233 } 234 235 TString WindowsPlatform::GetSystemJVMLibraryFileName() { 236 TString result; 237 TString jvmPath = GetSystemJRE(); 238 239 if (jvmPath.empty() == false) { 240 result = GetBundledJVMLibraryFileName(jvmPath); 241 } 242 243 return result; 244 } 245 246 PropertyContainer* WindowsPlatform::GetConfigFile(TString FileName) { 247 return new PropertyFile(FileName); 248 } 249 250 TString WindowsPlatform::GetModuleFileName() { 251 TString result; 252 DynamicBuffer<wchar_t> buffer(MAX_PATH); 253 ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize()); 254 255 while (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { 256 buffer.Resize(buffer.GetSize() * 2); 257 ::GetModuleFileName(NULL, buffer.GetData(), buffer.GetSize()); 258 } 259 260 result = buffer.GetData(); 261 return result; 262 } 263 264 Module WindowsPlatform::LoadLibrary(TString FileName) { 265 return ::LoadLibrary(FileName.data()); 266 } 267 268 void WindowsPlatform::FreeLibrary(Module AModule) { 269 ::FreeLibrary((HMODULE)AModule); 270 } 271 272 Procedure WindowsPlatform::GetProcAddress(Module AModule, std::string MethodName) { 273 return ::GetProcAddress((HMODULE)AModule, MethodName.c_str()); 274 } 275 276 bool WindowsPlatform::IsMainThread() { 277 bool result = (FMainThread == ::GetCurrentThreadId()); 278 return result; 279 } 280 281 TPlatformNumber WindowsPlatform::GetMemorySize() { 282 SYSTEM_INFO si; 283 GetSystemInfo(&si); 284 size_t result = (size_t)si.lpMaximumApplicationAddress; 285 result = result / 1048576; // Convert from bytes to megabytes. 286 return result; 287 } 288 289 std::vector<TString> WindowsPlatform::GetLibraryImports(const TString FileName) { 290 std::vector<TString> result; 291 WindowsLibrary library(FileName); 292 result = library.GetImports(); 293 return result; 294 } 295 296 std::vector<TString> FilterList(std::vector<TString> &Items, std::wregex Pattern) { 297 std::vector<TString> result; 298 299 for (std::vector<TString>::iterator it = Items.begin(); it != Items.end(); ++it) { 300 TString item = *it; 301 std::wsmatch match; 302 303 if (std::regex_search(item, match, Pattern)) { 304 result.push_back(item); 305 } 306 } 307 return result; 308 } 309 310 std::vector<TString> WindowsPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) { 311 std::vector<TString> result; 312 313 Package& package = Package::GetInstance(); 314 Macros& macros = Macros::GetInstance(); 315 TString runtimeDir = macros.ExpandMacros(package.GetJVMRuntimeDirectory()); 316 std::vector<TString> filelist = FilterList(Imports, std::wregex(_T("MSVCR.*.DLL"), std::regex_constants::icase)); 317 318 for (std::vector<TString>::iterator it = filelist.begin(); it != filelist.end(); ++it) { 319 TString filename = *it; 320 TString msvcr100FileName = FilePath::IncludeTrailingSlash(runtimeDir) + _T("jre\\bin\\") + filename; 321 322 if (FilePath::FileExists(msvcr100FileName) == true) { 323 result.push_back(msvcr100FileName); 324 break; 325 } 326 else { 327 msvcr100FileName = FilePath::IncludeTrailingSlash(runtimeDir) + _T("bin\\") + filename; 328 329 if (FilePath::FileExists(msvcr100FileName) == true) { 330 result.push_back(msvcr100FileName); 331 break; 332 } 333 } 334 } 335 336 return result; 337 } 338 339 #ifdef DEBUG 340 bool WindowsPlatform::IsNativeDebuggerPresent() { 341 bool result = false; 342 343 if (IsDebuggerPresent() == TRUE) { 344 result = true; 345 } 346 347 return result; 348 } 349 350 int WindowsPlatform::GetProcessID() { 351 int pid = GetProcessId(GetCurrentProcess()); 352 return pid; 353 } 354 #endif //DEBUG 355 356 //-------------------------------------------------------------------------------------------------- 357 358 WindowsJavaUserPreferences::WindowsJavaUserPreferences(void) : JavaUserPreferences() { 359 } 360 361 WindowsJavaUserPreferences::~WindowsJavaUserPreferences(void) { 362 } 363 364 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java. 365 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args. 366 // See WindowsPreferences.java toWindowsName() 367 TString ConvertStringToJavaEcodedString(TString Value) { 368 TString result; 369 TCHAR* p = (TCHAR*)Value.c_str(); 370 TCHAR c = *p; 371 372 while (c != 0) { 373 switch (c) { 374 case '\\': 375 result += _T("//"); 376 break; 377 378 case '/': 379 result += '\\'; 380 break; 381 default: 382 if ((c >= 'A') && (c <= 'Z')) { 383 result += '/'; 384 result += c; 385 } 386 else 387 result += c; 388 break; 389 } 390 391 p++; 392 c = *p; 393 } 394 395 return result; 396 } 397 398 // Java Preferences API encodes it's strings, so we need to match what Java does to work with Java. 399 // CAVEAT: Java also does unicode encoding which this doesn't do yet. Should be sufficient for jvm args. 400 // See WindowsPreferences.java toJavaName() 401 TString ConvertJavaEcodedStringToString(TString Value) { 402 TString result; 403 404 for (size_t index = 0; index < Value.length(); index++) { 405 TCHAR c = Value[index]; 406 407 switch (c) { 408 case '/': 409 if ((index + 1) < Value.length()) { 410 index++; 411 TCHAR nextc = Value[index]; 412 413 if (nextc >= 'A' && nextc <= 'Z') { 414 result += nextc; 415 } 416 else if (nextc == '/') { 417 result += '\\'; 418 } 419 } 420 break; 421 case '\\': 422 result += '/'; 423 break; 424 default: 425 result += c; 426 break; 427 } 428 } 429 430 return result; 431 } 432 433 bool WindowsJavaUserPreferences::Load(TString Appid) { 434 bool result = false; 435 TString lappid = Helpers::ConvertIdToFilePath(Appid); 436 lappid = ConvertStringToJavaEcodedString(Appid); 437 TString registryKey = TString(_T("SOFTWARE\\JavaSoft\\Prefs\\")) + lappid + TString(_T("\\/J/V/M/User/Options")); 438 Registry registry(HKEY_CURRENT_USER); 439 440 if (registry.Open(registryKey) == true) { 441 std::list<TString> keys = registry.GetKeys(); 442 TOrderedMap mapOfKeysAndValues; 443 int index = 1; 444 445 for (std::list<TString>::const_iterator iterator = keys.begin(); iterator != keys.end(); iterator++) { 446 TString key = *iterator; 447 TString value = registry.ReadString(key); 448 key = ConvertJavaEcodedStringToString(key); 449 value = ConvertJavaEcodedStringToString(value); 450 451 if (key.empty() == false) { 452 TValueIndex item; 453 item.value = value; 454 item.index = index; 455 456 mapOfKeysAndValues.insert(TOrderedMap::value_type(key, item)); 457 result = true; 458 index++; 459 } 460 } 461 462 FMap = mapOfKeysAndValues; 463 } 464 465 return result; 466 } 467 468 //-------------------------------------------------------------------------------------------------- 469 470 FileHandle::FileHandle(std::wstring FileName) { 471 FHandle = ::CreateFile(FileName.data(), GENERIC_READ, FILE_SHARE_READ, NULL, 472 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 473 } 474 475 FileHandle::~FileHandle() { 476 if (IsValid() == true) { 477 ::CloseHandle(FHandle); 478 } 479 } 480 481 bool FileHandle::IsValid() { 482 return FHandle != INVALID_HANDLE_VALUE; 483 } 484 485 HANDLE FileHandle::GetHandle() { 486 return FHandle; 487 } 488 489 FileMappingHandle::FileMappingHandle(HANDLE FileHandle) { 490 FHandle = ::CreateFileMapping(FileHandle, NULL, PAGE_READONLY, 0, 0, NULL); 491 } 492 493 bool FileMappingHandle::IsValid() { 494 return FHandle != NULL; 495 } 496 497 FileMappingHandle::~FileMappingHandle() { 498 if (IsValid() == true) { 499 ::CloseHandle(FHandle); 500 } 501 } 502 503 HANDLE FileMappingHandle::GetHandle() { 504 return FHandle; 505 } 506 507 FileData::FileData(HANDLE Handle) { 508 FBaseAddress = ::MapViewOfFile(Handle, FILE_MAP_READ, 0, 0, 0); 509 } 510 511 FileData::~FileData() { 512 if (IsValid() == true) { 513 ::UnmapViewOfFile(FBaseAddress); 514 } 515 } 516 517 bool FileData::IsValid() { 518 return FBaseAddress != NULL; 519 } 520 521 LPVOID FileData::GetBaseAddress() { 522 return FBaseAddress; 523 } 524 525 526 WindowsLibrary::WindowsLibrary(std::wstring FileName) { 527 FFileName = FileName; 528 } 529 530 std::vector<TString> WindowsLibrary::GetImports() { 531 std::vector<TString> result; 532 FileHandle library(FFileName); 533 534 if (library.IsValid() == true) { 535 FileMappingHandle mapping(library.GetHandle()); 536 537 if (mapping.IsValid() == true) { 538 FileData fileData(mapping.GetHandle()); 539 540 if (fileData.IsValid() == true) { 541 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileData.GetBaseAddress(); 542 PIMAGE_FILE_HEADER pImgFileHdr = (PIMAGE_FILE_HEADER)fileData.GetBaseAddress(); 543 544 if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) { 545 result = DumpPEFile(dosHeader); 546 } 547 } 548 } 549 } 550 551 return result; 552 } 553 554 // Given an RVA, look up the section header that encloses it and return a 555 // pointer to its IMAGE_SECTION_HEADER 556 PIMAGE_SECTION_HEADER WindowsLibrary::GetEnclosingSectionHeader(DWORD rva, 557 PIMAGE_NT_HEADERS pNTHeader) { 558 PIMAGE_SECTION_HEADER result = 0; 559 PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader); 560 561 for (unsigned index = 0; index < pNTHeader->FileHeader.NumberOfSections; index++, section++) { 562 // Is the RVA is within this section? 563 if ((rva >= section->VirtualAddress) && 564 (rva < (section->VirtualAddress + section->Misc.VirtualSize))) { 565 result = section; 566 } 567 } 568 569 return result; 570 } 571 572 LPVOID WindowsLibrary::GetPtrFromRVA(DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase) { 573 LPVOID result = 0; 574 PIMAGE_SECTION_HEADER pSectionHdr = GetEnclosingSectionHeader(rva, pNTHeader); 575 576 if (pSectionHdr != NULL) { 577 INT delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData); 578 result = (PVOID)(imageBase + rva - delta); 579 } 580 581 return result; 582 } 583 584 std::vector<TString> WindowsLibrary::GetImportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader) { 585 std::vector<TString> result; 586 587 // Look up where the imports section is located. Normally in the .idata section, 588 // but not necessarily so. Therefore, grab the RVA from the data dir. 589 DWORD importsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 590 591 if (importsStartRVA != NULL) { 592 // Get the IMAGE_SECTION_HEADER that contains the imports. This is 593 // usually the .idata section, but doesn't have to be. 594 PIMAGE_SECTION_HEADER pSection = GetEnclosingSectionHeader(importsStartRVA, pNTHeader); 595 596 if (pSection != NULL) { 597 PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)GetPtrFromRVA(importsStartRVA, pNTHeader,base); 598 599 if (importDesc != NULL) { 600 while (true) 601 { 602 // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR 603 if ((importDesc->TimeDateStamp == 0) && (importDesc->Name == 0)) 604 break; 605 606 std::string filename = (char*)GetPtrFromRVA(importDesc->Name, pNTHeader, base); 607 result.push_back(PlatformString(filename)); 608 importDesc++; // advance to next IMAGE_IMPORT_DESCRIPTOR 609 } 610 } 611 } 612 } 613 614 return result; 615 } 616 617 std::vector<TString> WindowsLibrary::DumpPEFile(PIMAGE_DOS_HEADER dosHeader) { 618 std::vector<TString> result; 619 PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (DWORD)(dosHeader->e_lfanew)); 620 621 // Verify that the e_lfanew field gave us a reasonable 622 // pointer and the PE signature. 623 if (pNTHeader->Signature == IMAGE_NT_SIGNATURE) { 624 DWORD base = (DWORD)dosHeader; 625 result = GetImportsSection(base, pNTHeader); 626 } 627 628 return result; 629 } 630 631 //-------------------------------------------------------------------------------------------------- 632 633 #endif //WINDOWS