21 * questions.
22 *
23 */
24
25 #include <objc/objc-runtime.h>
26 #import <Foundation/Foundation.h>
27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
28
29 #include <JavaVM/jni.h>
30
31 #import <mach/mach.h>
32 #import <mach/mach_types.h>
33 #import <sys/sysctl.h>
34 #import <stdio.h>
35 #import <stdarg.h>
36 #import <stdlib.h>
37 #import <strings.h>
38 #import <dlfcn.h>
39 #import <limits.h>
40 #import <errno.h>
41
42 jboolean debug = JNI_FALSE;
43
44 static jfieldID symbolicatorID = 0; // set in _init0
45 static jfieldID taskID = 0; // set in _init0
46
47 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
48 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
49 }
50
51 static id getSymbolicator(JNIEnv *env, jobject this_obj) {
52 jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
53 return (id)(intptr_t)ptr;
54 }
55
56 static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
57 (*env)->SetLongField(env, this_obj, taskID, (jlong)task);
58 }
59
60 static task_t getTask(JNIEnv *env, jobject this_obj) {
413
414 kern_return_t result;
415 thread_t foreign_tid, usable_tid;
416 mach_msg_type_name_t type;
417
418 foreign_tid = tid;
419
420 task_t gTask = getTask(env, this_obj);
421 result = mach_port_extract_right(gTask, foreign_tid,
422 MACH_MSG_TYPE_COPY_SEND,
423 &usable_tid, &type);
424 if (result != KERN_SUCCESS)
425 return -1;
426
427 if (debug)
428 printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
429
430 return (jint) usable_tid;
431 }
432
433 /*
434 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
435 * Method: attach0
436 * Signature: (I)V
437 */
438 JNIEXPORT void JNICALL
439 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
440 JNIEnv *env, jobject this_obj, jint jpid)
441 {
442 JNF_COCOA_ENTER(env);
443 if (getenv("JAVA_SAPROC_DEBUG") != NULL)
444 debug = JNI_TRUE;
445 else
446 debug = JNI_FALSE;
447 if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
448
449 kern_return_t result;
450 task_t gTask = 0;
451 result = task_for_pid(mach_task_self(), jpid, &gTask);
452 if (result != KERN_SUCCESS) {
453 fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
454 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
455 }
456 putTask(env, this_obj, gTask);
457
458 id symbolicator = nil;
459 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
460 if (jrsSymbolicator != nil) {
461 id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
462 symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
463 }
464 if (symbolicator != nil) {
465 CFRetain(symbolicator); // pin symbolicator while in java heap
466 }
467
468 putSymbolicator(env, this_obj, symbolicator);
469 if (symbolicator == nil) {
470 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
471 }
472
473 JNF_COCOA_EXIT(env);
474 }
475
476 /*
477 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
478 * Method: detach0
479 * Signature: ()V
480 */
481 JNIEXPORT void JNICALL
482 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
483 JNIEnv *env, jobject this_obj)
484 {
485 JNF_COCOA_ENTER(env);
486 if (debug) printf("detach0 called\n");
487
488 task_t gTask = getTask(env, this_obj);
489 mach_port_deallocate(mach_task_self(), gTask);
490 id symbolicator = getSymbolicator(env, this_obj);
491 if (symbolicator != nil) {
492 CFRelease(symbolicator);
493 }
494 JNF_COCOA_EXIT(env);
495 }
496
497 /*
498 * Class: sun_jvm_hotspot_asm_Disassembler
499 * Method: load_library
500 * Signature: (Ljava/lang/String;)L
501 */
502 JNIEXPORT jlong JNICALL
503 Java_sun_jvm_hotspot_asm_Disassembler_load_1library(
504 JNIEnv * env,
505 jclass disclass,
506 jstring jrepath_s,
507 jstring libname_s)
508 {
|
21 * questions.
22 *
23 */
24
25 #include <objc/objc-runtime.h>
26 #import <Foundation/Foundation.h>
27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
28
29 #include <JavaVM/jni.h>
30
31 #import <mach/mach.h>
32 #import <mach/mach_types.h>
33 #import <sys/sysctl.h>
34 #import <stdio.h>
35 #import <stdarg.h>
36 #import <stdlib.h>
37 #import <strings.h>
38 #import <dlfcn.h>
39 #import <limits.h>
40 #import <errno.h>
41 #import <sys/types.h>
42 #import <sys/ptrace.h>
43
44 jboolean debug = JNI_FALSE;
45
46 static jfieldID symbolicatorID = 0; // set in _init0
47 static jfieldID taskID = 0; // set in _init0
48
49 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
50 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
51 }
52
53 static id getSymbolicator(JNIEnv *env, jobject this_obj) {
54 jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
55 return (id)(intptr_t)ptr;
56 }
57
58 static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
59 (*env)->SetLongField(env, this_obj, taskID, (jlong)task);
60 }
61
62 static task_t getTask(JNIEnv *env, jobject this_obj) {
415
416 kern_return_t result;
417 thread_t foreign_tid, usable_tid;
418 mach_msg_type_name_t type;
419
420 foreign_tid = tid;
421
422 task_t gTask = getTask(env, this_obj);
423 result = mach_port_extract_right(gTask, foreign_tid,
424 MACH_MSG_TYPE_COPY_SEND,
425 &usable_tid, &type);
426 if (result != KERN_SUCCESS)
427 return -1;
428
429 if (debug)
430 printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
431
432 return (jint) usable_tid;
433 }
434
435
436 static bool ptrace_continue(pid_t pid, int signal) {
437 // pass the signal to the process so we don't swallow it
438 int res;
439 if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) {
440 fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);
441 return false;
442 }
443 return true;
444 }
445
446 // waits until the ATTACH has stopped the process
447 // by signal SIGSTOP
448 static bool ptrace_waitpid(pid_t pid) {
449 int ret;
450 int status;
451 while (true) {
452 // Wait for debuggee to stop.
453 ret = waitpid(pid, &status, 0);
454 if (ret >= 0) {
455 if (WIFSTOPPED(status)) {
456 // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
457 // will still be pending and delivered when the process is DETACHED and the process
458 // will go to sleep.
459 if (WSTOPSIG(status) == SIGSTOP) {
460 // Debuggee stopped by SIGSTOP.
461 return true;
462 }
463 if (!ptrace_continue(pid, WSTOPSIG(status))) {
464 fprintf(stderr, "attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
465 return false;
466 }
467 } else {
468 fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
469 return false;
470 }
471 } else {
472 switch (errno) {
473 case EINTR:
474 continue;
475 break;
476 case ECHILD:
477 fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);
478 break;
479 case EINVAL:
480 fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n");
481 break;
482 default:
483 fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno);
484 break;
485 }
486 return false;
487 }
488 }
489 }
490
491 // attach to a process/thread specified by "pid"
492 static bool ptrace_attach(pid_t pid) {
493 int res;
494 if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) {
495 fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);
496 return false;
497 } else {
498 return ptrace_waitpid(pid);
499 }
500 }
501
502 /*
503 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
504 * Method: attach0
505 * Signature: (I)V
506 */
507 JNIEXPORT void JNICALL
508 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
509 JNIEnv *env, jobject this_obj, jint jpid)
510 {
511 JNF_COCOA_ENTER(env);
512 if (getenv("JAVA_SAPROC_DEBUG") != NULL)
513 debug = JNI_TRUE;
514 else
515 debug = JNI_FALSE;
516 if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
517
518 // get the task from the pid
519 kern_return_t result;
520 task_t gTask = 0;
521 result = task_for_pid(mach_task_self(), jpid, &gTask);
522 if (result != KERN_SUCCESS) {
523 fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
524 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
525 }
526 putTask(env, this_obj, gTask);
527
528 // use ptrace to stop the process
529 // on os x, ptrace only needs to be called on the process, not the individual threads
530 if (ptrace_attach(jpid) != true) {
531 mach_port_deallocate(mach_task_self(), gTask);
532 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
533 }
534
535 id symbolicator = nil;
536 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
537 if (jrsSymbolicator != nil) {
538 id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
539 symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
540 }
541 if (symbolicator != nil) {
542 CFRetain(symbolicator); // pin symbolicator while in java heap
543 }
544
545 putSymbolicator(env, this_obj, symbolicator);
546 if (symbolicator == nil) {
547 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
548 }
549
550 JNF_COCOA_EXIT(env);
551 }
552
553 /*
554 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
555 * Method: detach0
556 * Signature: ()V
557 */
558 JNIEXPORT void JNICALL
559 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
560 JNIEnv *env, jobject this_obj)
561 {
562 JNF_COCOA_ENTER(env);
563 if (debug) printf("detach0 called\n");
564
565 task_t gTask = getTask(env, this_obj);
566
567 // detach from the ptraced process causing it to resume execution
568 int pid;
569 kern_return_t k_res;
570 k_res = pid_for_task(gTask, &pid);
571 if (k_res != KERN_SUCCESS) {
572 fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
573 }
574 else {
575 int res = ptrace(PT_DETACH, pid, 0, 0);
576 if (res < 0) {
577 fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
578 }
579 }
580
581 mach_port_deallocate(mach_task_self(), gTask);
582 id symbolicator = getSymbolicator(env, this_obj);
583 if (symbolicator != nil) {
584 CFRelease(symbolicator);
585 }
586 JNF_COCOA_EXIT(env);
587 }
588
589 /*
590 * Class: sun_jvm_hotspot_asm_Disassembler
591 * Method: load_library
592 * Signature: (Ljava/lang/String;)L
593 */
594 JNIEXPORT jlong JNICALL
595 Java_sun_jvm_hotspot_asm_Disassembler_load_1library(
596 JNIEnv * env,
597 jclass disclass,
598 jstring jrepath_s,
599 jstring libname_s)
600 {
|