< prev index next >

src/java.base/macosx/native/libjli/java_md_macosx.c

Print this page
rev 12879 : 8136556: Add the ability to perform static builds of MacOSX x64 binaries
Reviewed-by: ihse, bdelsart, gadams, lfoltan, rriggs, hseigel, twisti


 228 #endif
 229     }
 230 
 231     char jvmPath[PATH_MAX];
 232     jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
 233     if (!gotJVMPath) {
 234         JLI_ReportErrorMessage("Failed to GetJVMPath()");
 235         return NULL;
 236     }
 237 
 238     InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
 239     jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
 240     if (!vmLoaded) {
 241         JLI_ReportErrorMessage("Failed to LoadJavaVM()");
 242         return NULL;
 243     }
 244 
 245     return sExportedJNIFunctions = fxns;
 246 }
 247 


 248 JNIEXPORT jint JNICALL
 249 JNI_GetDefaultJavaVMInitArgs(void *args) {
 250     InvocationFunctions *ifn = GetExportedJNIFunctions();
 251     if (ifn == NULL) return JNI_ERR;
 252     return ifn->GetDefaultJavaVMInitArgs(args);
 253 }
 254 
 255 JNIEXPORT jint JNICALL
 256 JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
 257     InvocationFunctions *ifn = GetExportedJNIFunctions();
 258     if (ifn == NULL) return JNI_ERR;
 259     return ifn->CreateJavaVM(pvm, penv, args);
 260 }
 261 
 262 JNIEXPORT jint JNICALL
 263 JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
 264     InvocationFunctions *ifn = GetExportedJNIFunctions();
 265     if (ifn == NULL) return JNI_ERR;
 266     return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
 267 }

 268 
 269 /*
 270  * Allow JLI-aware launchers to specify a client/server preference
 271  */
 272 JNIEXPORT void JNICALL
 273 JLI_SetPreferredJVM(const char *prefJVM) {
 274     if (sPreferredJVMType != NULL) {
 275         free(sPreferredJVMType);
 276         sPreferredJVMType = NULL;
 277     }
 278 
 279     if (prefJVM == NULL) return;
 280     sPreferredJVMType = strdup(prefJVM);
 281 }
 282 
 283 static BOOL awtLoaded = NO;
 284 static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
 285 static pthread_cond_t  awtLoaded_cv = PTHREAD_COND_INITIALIZER;
 286 
 287 JNIEXPORT void JNICALL
 288 JLI_NotifyAWTLoaded()
 289 {
 290     pthread_mutex_lock(&awtLoaded_mutex);
 291     awtLoaded = YES;
 292     pthread_cond_signal(&awtLoaded_cv);
 293     pthread_mutex_unlock(&awtLoaded_mutex);
 294 }
 295 
 296 static int (*main_fptr)(int argc, char **argv) = NULL;
 297 
 298 /*
 299  * Unwrap the arguments and re-run main()
 300  */
 301 static void *apple_main (void *arg)
 302 {
 303     objc_registerThreadWithCollector();
 304 
 305     if (main_fptr == NULL) {




 306         main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");

 307         if (main_fptr == NULL) {
 308             JLI_ReportErrorMessageSys("error locating main entrypoint\n");
 309             exit(1);
 310         }
 311     }
 312 
 313     struct NSAppArgs *args = (struct NSAppArgs *) arg;
 314     exit(main_fptr(args->argc, args->argv));
 315 }
 316 
 317 static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
 318 
 319 static void ParkEventLoop() {
 320     // RunLoop needs at least one source, and 1e20 is pretty far into the future
 321     CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
 322     CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
 323     CFRelease(t);
 324 
 325     // Park this thread in the main run loop.
 326     int32_t result;


 571  */
 572 static jboolean
 573 GetJVMPath(const char *jrepath, const char *jvmtype,
 574            char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
 575 {
 576     struct stat s;
 577 
 578     if (JLI_StrChr(jvmtype, '/')) {
 579         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
 580     } else {
 581         /*
 582          * macosx client library is built thin, i386 only.
 583          * 64 bit client requests must load server library
 584          */
 585         const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;
 586         JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);
 587     }
 588 
 589     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
 590 



 591     if (stat(jvmpath, &s) == 0) {
 592         JLI_TraceLauncher("yes.\n");
 593         return JNI_TRUE;
 594     } else {
 595         JLI_TraceLauncher("no.\n");
 596         return JNI_FALSE;
 597     }

 598 }
 599 
 600 /*
 601  * Find path to JRE based on .exe's location or registry settings.
 602  */
 603 static jboolean
 604 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
 605 {
 606     char libjava[MAXPATHLEN];
 607 
 608     if (GetApplicationHome(path, pathsize)) {
 609         /* Is JRE co-located with the application? */







 610         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
 611         if (access(libjava, F_OK) == 0) {
 612             return JNI_TRUE;
 613         }

 614         /* ensure storage for path + /jre + NULL */
 615         if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
 616             JLI_TraceLauncher("Insufficient space to store JRE path\n");
 617             return JNI_FALSE;
 618         }
 619         /* Does the app ship a private JRE in <apphome>/jre directory? */
 620         JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
 621         if (access(libjava, F_OK) == 0) {
 622             JLI_StrCat(path, "/jre");
 623             JLI_TraceLauncher("JRE path is %s\n", path);
 624             return JNI_TRUE;
 625         }
 626     }
 627 
 628     /* try to find ourselves instead */
 629     Dl_info selfInfo;
 630     dladdr(&GetJREPath, &selfInfo);
 631 


















 632     char *realPathToSelf = realpath(selfInfo.dli_fname, path);
 633     if (realPathToSelf != path) {
 634         return JNI_FALSE;
 635     }
 636 
 637     size_t pathLen = strlen(realPathToSelf);
 638     if (pathLen == 0) {
 639         return JNI_FALSE;
 640     }
 641 
 642     const char lastPathComponent[] = "/lib/jli/libjli.dylib";
 643     size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
 644     if (pathLen < sizeOfLastPathComponent) {
 645         return JNI_FALSE;
 646     }
 647 
 648     size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
 649     if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
 650         realPathToSelf[indexOfLastPathComponent + 1] = '\0';
 651         return JNI_TRUE;
 652     }
 653 
 654     if (!speculative)
 655       JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
 656     return JNI_FALSE;
 657 }
 658 
 659 jboolean
 660 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
 661 {
 662     Dl_info dlinfo;
 663     void *libjvm;
 664 
 665     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
 666 

 667     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);



 668     if (libjvm == NULL) {
 669         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
 670         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 671         return JNI_FALSE;
 672     }
 673 
 674     ifn->CreateJavaVM = (CreateJavaVM_t)
 675         dlsym(libjvm, "JNI_CreateJavaVM");
 676     if (ifn->CreateJavaVM == NULL) {
 677         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 678         return JNI_FALSE;
 679     }
 680 
 681     ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
 682         dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
 683     if (ifn->GetDefaultJavaVMInitArgs == NULL) {
 684         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 685         return JNI_FALSE;
 686     }
 687 


 697 
 698 /*
 699  * Compute the name of the executable
 700  *
 701  * In order to re-exec securely we need the absolute path of the
 702  * executable. On Solaris getexecname(3c) may not return an absolute
 703  * path so we use dladdr to get the filename of the executable and
 704  * then use realpath to derive an absolute path. From Solaris 9
 705  * onwards the filename returned in DL_info structure from dladdr is
 706  * an absolute pathname so technically realpath isn't required.
 707  * On Linux we read the executable name from /proc/self/exe.
 708  * As a fallback, and for platforms other than Solaris and Linux,
 709  * we use FindExecName to compute the executable name.
 710  */
 711 const char*
 712 SetExecname(char **argv)
 713 {
 714     char* exec_path = NULL;
 715     {
 716         Dl_info dlinfo;
 717         int (*fptr)();
 718 





 719         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");

 720         if (fptr == NULL) {
 721             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
 722             return JNI_FALSE;
 723         }
 724 
 725         if (dladdr((void*)fptr, &dlinfo)) {
 726             char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
 727             if (resolved != NULL) {
 728                 exec_path = realpath(dlinfo.dli_fname, resolved);
 729                 if (exec_path == NULL) {
 730                     JLI_MemFree(resolved);
 731                 }
 732             }
 733         }
 734     }
 735     if (exec_path == NULL) {
 736         exec_path = FindExecName(argv[0]);
 737     }
 738     execname = exec_path;
 739     return exec_path;




 228 #endif
 229     }
 230 
 231     char jvmPath[PATH_MAX];
 232     jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
 233     if (!gotJVMPath) {
 234         JLI_ReportErrorMessage("Failed to GetJVMPath()");
 235         return NULL;
 236     }
 237 
 238     InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
 239     jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
 240     if (!vmLoaded) {
 241         JLI_ReportErrorMessage("Failed to LoadJavaVM()");
 242         return NULL;
 243     }
 244 
 245     return sExportedJNIFunctions = fxns;
 246 }
 247 
 248 #ifndef STATIC_BUILD
 249 
 250 JNIEXPORT jint JNICALL
 251 JNI_GetDefaultJavaVMInitArgs(void *args) {
 252     InvocationFunctions *ifn = GetExportedJNIFunctions();
 253     if (ifn == NULL) return JNI_ERR;
 254     return ifn->GetDefaultJavaVMInitArgs(args);
 255 }
 256 
 257 JNIEXPORT jint JNICALL
 258 JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
 259     InvocationFunctions *ifn = GetExportedJNIFunctions();
 260     if (ifn == NULL) return JNI_ERR;
 261     return ifn->CreateJavaVM(pvm, penv, args);
 262 }
 263 
 264 JNIEXPORT jint JNICALL
 265 JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
 266     InvocationFunctions *ifn = GetExportedJNIFunctions();
 267     if (ifn == NULL) return JNI_ERR;
 268     return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
 269 }
 270 #endif
 271 
 272 /*
 273  * Allow JLI-aware launchers to specify a client/server preference
 274  */
 275 JNIEXPORT void JNICALL
 276 JLI_SetPreferredJVM(const char *prefJVM) {
 277     if (sPreferredJVMType != NULL) {
 278         free(sPreferredJVMType);
 279         sPreferredJVMType = NULL;
 280     }
 281 
 282     if (prefJVM == NULL) return;
 283     sPreferredJVMType = strdup(prefJVM);
 284 }
 285 
 286 static BOOL awtLoaded = NO;
 287 static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
 288 static pthread_cond_t  awtLoaded_cv = PTHREAD_COND_INITIALIZER;
 289 
 290 JNIEXPORT void JNICALL
 291 JLI_NotifyAWTLoaded()
 292 {
 293     pthread_mutex_lock(&awtLoaded_mutex);
 294     awtLoaded = YES;
 295     pthread_cond_signal(&awtLoaded_cv);
 296     pthread_mutex_unlock(&awtLoaded_mutex);
 297 }
 298 
 299 static int (*main_fptr)(int argc, char **argv) = NULL;
 300 
 301 /*
 302  * Unwrap the arguments and re-run main()
 303  */
 304 static void *apple_main (void *arg)
 305 {
 306     objc_registerThreadWithCollector();
 307 
 308     if (main_fptr == NULL) {
 309 #ifdef STATIC_BUILD
 310         extern int main(int argc, char **argv);
 311         main_fptr = &main;
 312 #else
 313         main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
 314 #endif
 315         if (main_fptr == NULL) {
 316             JLI_ReportErrorMessageSys("error locating main entrypoint\n");
 317             exit(1);
 318         }
 319     }
 320 
 321     struct NSAppArgs *args = (struct NSAppArgs *) arg;
 322     exit(main_fptr(args->argc, args->argv));
 323 }
 324 
 325 static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
 326 
 327 static void ParkEventLoop() {
 328     // RunLoop needs at least one source, and 1e20 is pretty far into the future
 329     CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
 330     CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
 331     CFRelease(t);
 332 
 333     // Park this thread in the main run loop.
 334     int32_t result;


 579  */
 580 static jboolean
 581 GetJVMPath(const char *jrepath, const char *jvmtype,
 582            char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
 583 {
 584     struct stat s;
 585 
 586     if (JLI_StrChr(jvmtype, '/')) {
 587         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
 588     } else {
 589         /*
 590          * macosx client library is built thin, i386 only.
 591          * 64 bit client requests must load server library
 592          */
 593         const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;
 594         JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);
 595     }
 596 
 597     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
 598 
 599 #ifdef STATIC_BUILD
 600     return JNI_TRUE;
 601 #else
 602     if (stat(jvmpath, &s) == 0) {
 603         JLI_TraceLauncher("yes.\n");
 604         return JNI_TRUE;
 605     } else {
 606         JLI_TraceLauncher("no.\n");
 607         return JNI_FALSE;
 608     }
 609 #endif
 610 }
 611 
 612 /*
 613  * Find path to JRE based on .exe's location or registry settings.
 614  */
 615 static jboolean
 616 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
 617 {
 618     char libjava[MAXPATHLEN];
 619 
 620     if (GetApplicationHome(path, pathsize)) {
 621         /* Is JRE co-located with the application? */
 622 #ifdef STATIC_BUILD
 623         char jvm_cfg[MAXPATHLEN];
 624         JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
 625         if (access(jvm_cfg, F_OK) == 0) {
 626             return JNI_TRUE;
 627         }
 628 #else
 629         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
 630         if (access(libjava, F_OK) == 0) {
 631             return JNI_TRUE;
 632         }
 633 #endif
 634         /* ensure storage for path + /jre + NULL */
 635         if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
 636             JLI_TraceLauncher("Insufficient space to store JRE path\n");
 637             return JNI_FALSE;
 638         }
 639         /* Does the app ship a private JRE in <apphome>/jre directory? */
 640         JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
 641         if (access(libjava, F_OK) == 0) {
 642             JLI_StrCat(path, "/jre");
 643             JLI_TraceLauncher("JRE path is %s\n", path);
 644             return JNI_TRUE;
 645         }
 646     }
 647 
 648     /* try to find ourselves instead */
 649     Dl_info selfInfo;
 650     dladdr(&GetJREPath, &selfInfo);
 651 
 652 #ifdef STATIC_BUILD
 653     char jvm_cfg[MAXPATHLEN];
 654     char *p = NULL;
 655     strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
 656     p = strrchr(jvm_cfg, '/'); *p = '\0';
 657     p = strrchr(jvm_cfg, '/');
 658     if (strcmp(p, "/.") == 0) {
 659       *p = '\0';
 660       p = strrchr(jvm_cfg, '/'); *p = '\0';
 661     }
 662     else *p = '\0';
 663     strncpy(path, jvm_cfg, pathsize);
 664     strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
 665     if (access(jvm_cfg, F_OK) == 0) {
 666       return JNI_TRUE;
 667     }
 668 #endif
 669 
 670     char *realPathToSelf = realpath(selfInfo.dli_fname, path);
 671     if (realPathToSelf != path) {
 672         return JNI_FALSE;
 673     }
 674 
 675     size_t pathLen = strlen(realPathToSelf);
 676     if (pathLen == 0) {
 677         return JNI_FALSE;
 678     }
 679 
 680     const char lastPathComponent[] = "/lib/jli/libjli.dylib";
 681     size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
 682     if (pathLen < sizeOfLastPathComponent) {
 683         return JNI_FALSE;
 684     }
 685 
 686     size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
 687     if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
 688         realPathToSelf[indexOfLastPathComponent + 1] = '\0';
 689         return JNI_TRUE;
 690     }
 691 
 692     if (!speculative)
 693       JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
 694     return JNI_FALSE;
 695 }
 696 
 697 jboolean
 698 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
 699 {
 700     Dl_info dlinfo;
 701     void *libjvm;
 702 
 703     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
 704 
 705 #ifndef STATIC_BUILD
 706     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
 707 #else
 708     libjvm = dlopen(NULL, RTLD_FIRST);
 709 #endif
 710     if (libjvm == NULL) {
 711         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
 712         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 713         return JNI_FALSE;
 714     }
 715 
 716     ifn->CreateJavaVM = (CreateJavaVM_t)
 717         dlsym(libjvm, "JNI_CreateJavaVM");
 718     if (ifn->CreateJavaVM == NULL) {
 719         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 720         return JNI_FALSE;
 721     }
 722 
 723     ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
 724         dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
 725     if (ifn->GetDefaultJavaVMInitArgs == NULL) {
 726         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 727         return JNI_FALSE;
 728     }
 729 


 739 
 740 /*
 741  * Compute the name of the executable
 742  *
 743  * In order to re-exec securely we need the absolute path of the
 744  * executable. On Solaris getexecname(3c) may not return an absolute
 745  * path so we use dladdr to get the filename of the executable and
 746  * then use realpath to derive an absolute path. From Solaris 9
 747  * onwards the filename returned in DL_info structure from dladdr is
 748  * an absolute pathname so technically realpath isn't required.
 749  * On Linux we read the executable name from /proc/self/exe.
 750  * As a fallback, and for platforms other than Solaris and Linux,
 751  * we use FindExecName to compute the executable name.
 752  */
 753 const char*
 754 SetExecname(char **argv)
 755 {
 756     char* exec_path = NULL;
 757     {
 758         Dl_info dlinfo;

 759 
 760 #ifdef STATIC_BUILD
 761         void *fptr;
 762         fptr = (void *)&SetExecname;
 763 #else
 764         int (*fptr)();
 765         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
 766 #endif
 767         if (fptr == NULL) {
 768             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
 769             return JNI_FALSE;
 770         }
 771 
 772         if (dladdr((void*)fptr, &dlinfo)) {
 773             char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
 774             if (resolved != NULL) {
 775                 exec_path = realpath(dlinfo.dli_fname, resolved);
 776                 if (exec_path == NULL) {
 777                     JLI_MemFree(resolved);
 778                 }
 779             }
 780         }
 781     }
 782     if (exec_path == NULL) {
 783         exec_path = FindExecName(argv[0]);
 784     }
 785     execname = exec_path;
 786     return exec_path;


< prev index next >