agent/src/os/bsd/MacosxDebuggerLocal.m

Print this page
rev 4136 : 8008102: SA on OS X does not stop the attached process
Reviewed-by:


  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 {