67 static jmethodID getJavaThreadsInfo_ID = 0; |
68 static jmethodID getJavaThreadsInfo_ID = 0; |
68 |
69 |
69 // indicator if thread id (lwpid_t) was set |
70 // indicator if thread id (lwpid_t) was set |
70 static bool _threads_filled = false; |
71 static bool _threads_filled = false; |
71 |
72 |
|
73 // mach_exc_server defined in the generated mach_excServer.c |
|
74 extern boolean_t mach_exc_server(mach_msg_header_t *input_msg_hdr, |
|
75 mach_msg_header_t *output_msg_hdr); |
|
76 |
|
77 kern_return_t catch_mach_exception_raise( |
|
78 mach_port_t exception_port, mach_port_t thread, |
|
79 mach_port_t task, exception_type_t exception, |
|
80 mach_exception_data_t code, |
|
81 mach_msg_type_number_t code_cnt); |
|
82 |
|
83 kern_return_t catch_mach_exception_raise_state( |
|
84 mach_port_t exception_port, exception_type_t exception, |
|
85 const mach_exception_data_t code, mach_msg_type_number_t code_cnt, |
|
86 int *flavor, const thread_state_t old_state, |
|
87 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, |
|
88 mach_msg_type_number_t *new_state_cnt); |
|
89 |
|
90 kern_return_t catch_mach_exception_raise_state_identity( |
|
91 mach_port_t exception_port, mach_port_t thread, mach_port_t task, |
|
92 exception_type_t exception, mach_exception_data_t code, |
|
93 mach_msg_type_number_t code_cnt, int *flavor, thread_state_t old_state, |
|
94 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, |
|
95 mach_msg_type_number_t *new_state_cnt); |
|
96 |
|
97 static struct exception_saved_state { |
|
98 exception_mask_t saved_masks[EXC_TYPES_COUNT]; |
|
99 mach_port_t saved_ports[EXC_TYPES_COUNT]; |
|
100 exception_behavior_t saved_behaviors[EXC_TYPES_COUNT]; |
|
101 thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT]; |
|
102 mach_msg_type_number_t saved_exception_types_count; |
|
103 } exception_saved_state; |
|
104 |
|
105 static mach_port_t tgt_exception_port; |
|
106 |
|
107 // Mirrors __Reply__mach_exception_raise_t generated in mach_excServer.c |
|
108 static struct rep_msg { |
|
109 mach_msg_header_t header; |
|
110 NDR_record_t ndr; |
|
111 kern_return_t ret_code; |
|
112 } rep_msg; |
|
113 |
|
114 // Mirrors __Request__mach_exception_raise_t generated in mach_excServer.c |
|
115 // with a large trailing pad to avoid MACH_MSG_RCV_TOO_LARGE |
|
116 static struct exc_msg { |
|
117 mach_msg_header_t header; |
|
118 // start of the kernel processed data |
|
119 mach_msg_body_t msgh_body; |
|
120 mach_msg_port_descriptor_t thread; |
|
121 mach_msg_port_descriptor_t task; |
|
122 // end of the kernel processed data |
|
123 NDR_record_t ndr; |
|
124 exception_type_t exception; |
|
125 mach_msg_type_number_t code_cnt; |
|
126 mach_exception_data_t code; // an array of int64_t |
|
127 char pad[512]; |
|
128 } exc_msg; |
|
129 |
72 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { |
130 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { |
73 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); |
131 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); |
74 } |
132 } |
75 |
133 |
76 static id getSymbolicator(JNIEnv *env, jobject this_obj) { |
134 static id getSymbolicator(JNIEnv *env, jobject this_obj) { |
89 |
147 |
90 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; } |
148 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; } |
91 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;} |
149 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;} |
92 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; } |
150 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; } |
93 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;} |
151 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;} |
94 #define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); } |
152 #define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); } |
95 #define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; } |
153 #define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; } |
96 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } |
154 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } |
97 |
155 |
98 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { |
156 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { |
99 jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); |
157 jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); |
100 CHECK_EXCEPTION; |
158 CHECK_EXCEPTION; |
101 (*env)->ThrowNew(env, exceptionClass, errMsg); |
159 (*env)->ThrowNew(env, exceptionClass, errMsg); |
200 /* |
258 /* |
201 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
259 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
202 * Method: lookupByName0 |
260 * Method: lookupByName0 |
203 * Signature: (Ljava/lang/String;Ljava/lang/String;)J |
261 * Signature: (Ljava/lang/String;Ljava/lang/String;)J |
204 */ |
262 */ |
205 JNIEXPORT jlong JNICALL |
263 JNIEXPORT jlong JNICALL |
206 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( |
264 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( |
207 JNIEnv *env, jobject this_obj, |
265 JNIEnv *env, jobject this_obj, |
208 jstring objectName, jstring symbolName) |
266 jstring objectName, jstring symbolName) |
209 { |
267 { |
210 struct ps_prochandle* ph = get_proc_handle(env, this_obj); |
268 struct ps_prochandle* ph = get_proc_handle(env, this_obj); |
211 if (ph != NULL && ph->core != NULL) { |
269 if (ph != NULL && ph->core != NULL) { |
212 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); |
270 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); |
213 } |
271 } |
318 mapped = calloc(pageCount, sizeof(int)); |
376 mapped = calloc(pageCount, sizeof(int)); |
319 |
377 |
320 task_t gTask = getTask(env, this_obj); |
378 task_t gTask = getTask(env, this_obj); |
321 // Try to read each of the pages. |
379 // Try to read each of the pages. |
322 for (i = 0; i < pageCount; i++) { |
380 for (i = 0; i < pageCount; i++) { |
323 result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, |
381 result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, |
324 &pages[i], &byteCount); |
382 &pages[i], &byteCount); |
325 mapped[i] = (result == KERN_SUCCESS); |
383 mapped[i] = (result == KERN_SUCCESS); |
326 // assume all failures are unmapped pages |
384 // assume all failures are unmapped pages |
327 } |
385 } |
328 |
386 |
329 print_debug("%ld pages\n", pageCount); |
387 print_debug("%ld pages\n", pageCount); |
330 |
388 |
331 remaining = numBytes; |
389 remaining = numBytes; |
332 |
390 |
333 for (i = 0; i < pageCount; i++) { |
391 for (i = 0; i < pageCount; i++) { |
334 unsigned long len = vm_page_size; |
392 unsigned long len = vm_page_size; |
335 unsigned long start = 0; |
393 unsigned long start = 0; |
336 |
394 |
337 if (i == 0) { |
395 if (i == 0) { |
364 * Note Macosx uses unique_thread_id which is different from other platforms though printed ids |
422 * Note Macosx uses unique_thread_id which is different from other platforms though printed ids |
365 * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long |
423 * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long |
366 * integers to host all java threads' id, stack_start, stack_end as: |
424 * integers to host all java threads' id, stack_start, stack_end as: |
367 * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] |
425 * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] |
368 * |
426 * |
369 * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). |
427 * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). |
370 * This function should be called only once if succeeded |
428 * This function should be called only once if succeeded |
371 */ |
429 */ |
372 bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { |
430 bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { |
373 int n = 0, i = 0, j; |
431 int n = 0, i = 0, j; |
374 struct reg regs; |
432 struct reg regs; |
375 |
433 |
376 jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); |
434 jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); |
377 CHECK_EXCEPTION_(false); |
435 CHECK_EXCEPTION_(false); |
378 int len = (int)(*env)->GetArrayLength(env, thrinfos); |
436 int len = (int)(*env)->GetArrayLength(env, thrinfos); |
379 uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); |
437 uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); |
380 CHECK_EXCEPTION_(false); |
438 CHECK_EXCEPTION_(false); |
381 n = get_num_threads(ph); |
439 n = get_num_threads(ph); |
382 print_debug("fill_java_threads called, num_of_thread = %d\n", n); |
440 print_debug("fill_java_threads called, num_of_thread = %d\n", n); |
383 for (i = 0; i < n; i++) { |
441 for (i = 0; i < n; i++) { |
384 if (!get_nth_lwp_regs(ph, i, ®s)) { |
442 if (!get_nth_lwp_regs(ph, i, ®s)) { |
385 print_debug("Could not get regs of thread %d, already set!\n", i); |
443 print_debug("Could not get regs of thread %d, already set!\n", i); |
386 return false; |
444 return false; |
387 } |
445 } |
388 for (j = 0; j < len; j += 3) { |
446 for (j = 0; j < len; j += 3) { |
389 lwpid_t uid = cinfos[j]; |
447 lwpid_t uid = cinfos[j]; |
390 uint64_t beg = cinfos[j + 1]; |
448 uint64_t beg = cinfos[j + 1]; |
391 uint64_t end = cinfos[j + 2]; |
449 uint64_t end = cinfos[j + 2]; |
392 if ((regs.r_rsp < end && regs.r_rsp >= beg) || |
450 if ((regs.r_rsp < end && regs.r_rsp >= beg) || |
393 (regs.r_rbp < end && regs.r_rbp >= beg)) { |
451 (regs.r_rbp < end && regs.r_rbp >= beg)) { |
394 set_lwp_id(ph, i, uid); |
452 set_lwp_id(ph, i, uid); |
395 break; |
453 break; |
396 } |
454 } |
476 * in the VM, but that thread port is not valid for a remote debugger to access the thread. |
534 * in the VM, but that thread port is not valid for a remote debugger to access the thread. |
477 */ |
535 */ |
478 thread_t |
536 thread_t |
479 lookupThreadFromThreadId(task_t task, jlong thread_id) { |
537 lookupThreadFromThreadId(task_t task, jlong thread_id) { |
480 print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); |
538 print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); |
481 |
539 |
482 thread_array_t thread_list = NULL; |
540 thread_array_t thread_list = NULL; |
483 mach_msg_type_number_t thread_list_count = 0; |
541 mach_msg_type_number_t thread_list_count = 0; |
484 thread_t result_thread = 0; |
542 thread_t result_thread = 0; |
485 int i; |
543 int i; |
486 |
544 |
487 // get the list of all the send rights |
545 // get the list of all the send rights |
488 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); |
546 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); |
489 if (result != KERN_SUCCESS) { |
547 if (result != KERN_SUCCESS) { |
490 print_debug("task_threads returned 0x%x\n", result); |
548 print_debug("task_threads returned 0x%x\n", result); |
491 return 0; |
549 return 0; |
492 } |
550 } |
493 |
551 |
494 for(i = 0 ; i < thread_list_count; i++) { |
552 for(i = 0 ; i < thread_list_count; i++) { |
495 thread_identifier_info_data_t m_ident_info; |
553 thread_identifier_info_data_t m_ident_info; |
496 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; |
554 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; |
497 |
555 |
498 // get the THREAD_IDENTIFIER_INFO for the send right |
556 // get the THREAD_IDENTIFIER_INFO for the send right |
499 result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); |
557 result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); |
500 if (result != KERN_SUCCESS) { |
558 if (result != KERN_SUCCESS) { |
501 print_debug("thread_info returned 0x%x\n", result); |
559 print_debug("thread_info returned 0x%x\n", result); |
502 break; |
560 break; |
503 } |
561 } |
504 |
562 |
505 // if this is the one we're looking for, return the send right |
563 // if this is the one we're looking for, return the send right |
506 if (thread_id == m_ident_info.thread_id) |
564 if (thread_id == m_ident_info.thread_id) |
507 { |
565 { |
508 result_thread = thread_list[i]; |
566 result_thread = thread_list[i]; |
509 break; |
567 break; |
510 } |
568 } |
511 } |
569 } |
512 |
570 |
513 vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); |
571 vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); |
514 vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count); |
572 vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count); |
515 |
573 |
516 return result_thread; |
574 return result_thread; |
517 } |
575 } |
518 |
576 |
519 |
577 |
520 /* |
578 /* |
521 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
579 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
522 * Method: getThreadIntegerRegisterSet0 |
580 * Method: getThreadIntegerRegisterSet0 |
523 * Signature: (J)[J |
581 * Signature: (J)[J |
524 */ |
582 */ |
525 JNIEXPORT jlongArray JNICALL |
583 JNIEXPORT jlongArray JNICALL |
526 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( |
584 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( |
527 JNIEnv *env, jobject this_obj, |
585 JNIEnv *env, jobject this_obj, |
528 jlong thread_id) |
586 jlong thread_id) |
529 { |
587 { |
530 print_debug("getThreadRegisterSet0 called\n"); |
588 print_debug("getThreadRegisterSet0 called\n"); |
531 |
589 |
532 struct ps_prochandle* ph = get_proc_handle(env, this_obj); |
590 struct ps_prochandle* ph = get_proc_handle(env, this_obj); |
533 if (ph != NULL && ph->core != NULL) { |
591 if (ph != NULL && ph->core != NULL) { |
628 print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); |
686 print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); |
629 |
687 |
630 return (jint) usable_tid; |
688 return (jint) usable_tid; |
631 } |
689 } |
632 |
690 |
633 |
|
634 static bool ptrace_continue(pid_t pid, int signal) { |
|
635 // pass the signal to the process so we don't swallow it |
|
636 int res; |
|
637 if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) { |
|
638 print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); |
|
639 return false; |
|
640 } |
|
641 return true; |
|
642 } |
|
643 |
|
644 // waits until the ATTACH has stopped the process |
|
645 // by signal SIGSTOP |
|
646 static bool ptrace_waitpid(pid_t pid) { |
|
647 int ret; |
|
648 int status; |
|
649 while (true) { |
|
650 // Wait for debuggee to stop. |
|
651 ret = waitpid(pid, &status, 0); |
|
652 if (ret >= 0) { |
|
653 if (WIFSTOPPED(status)) { |
|
654 // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP |
|
655 // will still be pending and delivered when the process is DETACHED and the process |
|
656 // will go to sleep. |
|
657 if (WSTOPSIG(status) == SIGSTOP) { |
|
658 // Debuggee stopped by SIGSTOP. |
|
659 return true; |
|
660 } |
|
661 if (!ptrace_continue(pid, WSTOPSIG(status))) { |
|
662 print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); |
|
663 return false; |
|
664 } |
|
665 } else { |
|
666 print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); |
|
667 return false; |
|
668 } |
|
669 } else { |
|
670 switch (errno) { |
|
671 case EINTR: |
|
672 continue; |
|
673 break; |
|
674 case ECHILD: |
|
675 print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); |
|
676 break; |
|
677 case EINVAL: |
|
678 print_error("attach: waitpid() failed. Invalid options argument.\n"); |
|
679 break; |
|
680 default: |
|
681 print_error("attach: waitpid() failed. Unexpected error %d\n",errno); |
|
682 break; |
|
683 } |
|
684 return false; |
|
685 } |
|
686 } |
|
687 } |
|
688 |
|
689 // attach to a process/thread specified by "pid" |
691 // attach to a process/thread specified by "pid" |
690 static bool ptrace_attach(pid_t pid) { |
692 static bool ptrace_attach(pid_t pid) { |
691 int res; |
693 errno = 0; |
692 #ifdef __clang__ |
694 ptrace(PT_ATTACHEXC, pid, 0, 0); |
693 #pragma clang diagnostic push |
695 |
694 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
696 if (errno != 0) { |
695 #endif |
697 print_error("ptrace_attach: ptrace(PT_ATTACHEXC,...) failed: %s", strerror(errno)); |
696 if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { |
|
697 print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); |
|
698 #ifdef __clang__ |
|
699 #pragma clang diagnostic pop |
|
700 #endif |
|
701 return false; |
698 return false; |
702 } else { |
699 } |
703 return ptrace_waitpid(pid); |
700 return true; |
704 } |
701 } |
|
702 |
|
703 kern_return_t catch_mach_exception_raise( |
|
704 mach_port_t exception_port, mach_port_t thread_port, mach_port_t task_port, |
|
705 exception_type_t exception_type, mach_exception_data_t codes, |
|
706 mach_msg_type_number_t num_codes) { |
|
707 |
|
708 print_debug("catch_mach_exception_raise: Exception port = %d thread_port = %d " |
|
709 "task port %d exc type = %d num_codes %d\n", |
|
710 exception_port, thread_port, task_port, exception_type, num_codes); |
|
711 |
|
712 // This message should denote a Unix soft signal, with |
|
713 // 1. the exception type = EXC_SOFTWARE |
|
714 // 2. codes[0] (which is the code) = EXC_SOFT_SIGNAL |
|
715 // 3. codes[1] (which is the sub-code) = SIGSTOP |
|
716 if (!(exception_type == EXC_SOFTWARE && |
|
717 codes[0] == EXC_SOFT_SIGNAL && |
|
718 codes[num_codes -1] == SIGSTOP)) { |
|
719 print_error("catch_mach_exception_raise: Message doesn't denote a Unix " |
|
720 "soft signal. exception_type = %d, codes[0] = %d, " |
|
721 "codes[num_codes -1] = %d, num_codes = %d\n", |
|
722 exception_type, codes[0], codes[num_codes - 1], num_codes); |
|
723 return MACH_RCV_INVALID_TYPE; |
|
724 } |
|
725 return KERN_SUCCESS; |
|
726 } |
|
727 |
|
728 kern_return_t catch_mach_exception_raise_state( |
|
729 mach_port_t exception_port, exception_type_t exception, const mach_exception_data_t code, |
|
730 mach_msg_type_number_t code_cnt, int *flavor, const thread_state_t old_state, |
|
731 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, |
|
732 mach_msg_type_number_t *new_state_cnt) { |
|
733 return MACH_RCV_INVALID_TYPE; |
|
734 } |
|
735 |
|
736 |
|
737 kern_return_t catch_mach_exception_raise_state_identity( |
|
738 mach_port_t exception_port, mach_port_t thread, mach_port_t task, |
|
739 exception_type_t exception, mach_exception_data_t code, |
|
740 mach_msg_type_number_t code_cnt, int *flavor, |
|
741 thread_state_t old_state, mach_msg_type_number_t old_state_cnt, |
|
742 thread_state_t new_state, mach_msg_type_number_t *new_state_cnt) { |
|
743 return MACH_RCV_INVALID_TYPE; |
|
744 } |
|
745 |
|
746 // wait to receive an exception message |
|
747 static bool wait_for_exception() { |
|
748 kern_return_t result; |
|
749 |
|
750 result = mach_msg(&exc_msg.header, |
|
751 MACH_RCV_MSG, |
|
752 0, |
|
753 sizeof(exc_msg), |
|
754 tgt_exception_port, |
|
755 MACH_MSG_TIMEOUT_NONE, |
|
756 MACH_PORT_NULL); |
|
757 |
|
758 if (result != MACH_MSG_SUCCESS) { |
|
759 print_error("attach: wait_for_exception: mach_msg() failed: '%s' (%d)\n", |
|
760 mach_error_string(result), result); |
|
761 return false; |
|
762 } |
|
763 |
|
764 if (mach_exc_server(&exc_msg.header, &rep_msg.header) == false || |
|
765 rep_msg.ret_code != KERN_SUCCESS) { |
|
766 print_error("attach: wait_for_exception: mach_exc_server failure\n"); |
|
767 if (rep_msg.ret_code != KERN_SUCCESS) { |
|
768 print_error("catch_mach_exception_raise() failed '%s' (%d)\n", |
|
769 mach_error_string(rep_msg.ret_code), rep_msg.ret_code); |
|
770 } |
|
771 return false; |
|
772 } |
|
773 |
|
774 print_debug("reply msg from mach_exc_server: (msg->{bits = %#x, size = %u, " |
|
775 "remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x},)", |
|
776 rep_msg.header.msgh_bits, rep_msg.header.msgh_size, |
|
777 rep_msg.header.msgh_remote_port, rep_msg.header.msgh_local_port, |
|
778 rep_msg.header.msgh_reserved, rep_msg.header.msgh_id); |
|
779 |
|
780 return true; |
705 } |
781 } |
706 |
782 |
707 /* |
783 /* |
708 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
784 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
709 * Method: attach0 |
785 * Method: attach0 |
717 |
793 |
718 JNF_COCOA_ENTER(env); |
794 JNF_COCOA_ENTER(env); |
719 |
795 |
720 kern_return_t result; |
796 kern_return_t result; |
721 task_t gTask = 0; |
797 task_t gTask = 0; |
|
798 |
722 result = task_for_pid(mach_task_self(), jpid, &gTask); |
799 result = task_for_pid(mach_task_self(), jpid, &gTask); |
723 if (result != KERN_SUCCESS) { |
800 if (result != KERN_SUCCESS) { |
724 print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result); |
801 print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result); |
725 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges."); |
802 THROW_NEW_DEBUGGER_EXCEPTION( |
|
803 "Can't attach to the process. Could be caused by an incorrect pid or lack of privileges."); |
726 } |
804 } |
727 putTask(env, this_obj, gTask); |
805 putTask(env, this_obj, gTask); |
|
806 |
|
807 // Allocate an exception port. |
|
808 result = mach_port_allocate(mach_task_self(), |
|
809 MACH_PORT_RIGHT_RECEIVE, |
|
810 &tgt_exception_port); |
|
811 if (result != KERN_SUCCESS) { |
|
812 print_error("attach: mach_port_allocate() for tgt_exception_port failed: '%s' (%d)\n", |
|
813 mach_error_string(result), result); |
|
814 THROW_NEW_DEBUGGER_EXCEPTION( |
|
815 "Can't attach to the process. Couldn't allocate an exception port."); |
|
816 } |
|
817 |
|
818 // Enable the new exception port to send messages. |
|
819 result = mach_port_insert_right (mach_task_self(), |
|
820 tgt_exception_port, |
|
821 tgt_exception_port, |
|
822 MACH_MSG_TYPE_MAKE_SEND); |
|
823 if (result != KERN_SUCCESS) { |
|
824 print_error("attach: mach_port_insert_right() failed for port 0x%x: '%s' (%d)\n", |
|
825 tgt_exception_port, mach_error_string(result), result); |
|
826 THROW_NEW_DEBUGGER_EXCEPTION( |
|
827 "Can't attach to the process. Couldn't add send privileges to the exception port."); |
|
828 } |
|
829 |
|
830 // Save the existing original exception ports registered with the target |
|
831 // process (for later restoration while detaching from the process). |
|
832 result = task_get_exception_ports(gTask, |
|
833 EXC_MASK_ALL, |
|
834 exception_saved_state.saved_masks, |
|
835 &exception_saved_state.saved_exception_types_count, |
|
836 exception_saved_state.saved_ports, |
|
837 exception_saved_state.saved_behaviors, |
|
838 exception_saved_state.saved_flavors); |
|
839 |
|
840 if (result != KERN_SUCCESS) { |
|
841 print_error("attach: task_get_exception_ports() failed: '%s' (%d)\n", |
|
842 mach_error_string(result), result); |
|
843 THROW_NEW_DEBUGGER_EXCEPTION( |
|
844 "Can't attach to the process. Could not get the target exception ports."); |
|
845 } |
|
846 |
|
847 // register the exception port to be used for all future exceptions with the |
|
848 // target process. |
|
849 result = task_set_exception_ports(gTask, |
|
850 EXC_MASK_ALL, |
|
851 tgt_exception_port, |
|
852 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, |
|
853 THREAD_STATE_NONE); |
|
854 |
|
855 if (result != KERN_SUCCESS) { |
|
856 print_error("attach: task_set_exception_ports() failed -- port 0x%x: '%s' (%d)\n", |
|
857 tgt_exception_port, mach_error_string(result), result); |
|
858 mach_port_deallocate(mach_task_self(), gTask); |
|
859 mach_port_deallocate(mach_task_self(), tgt_exception_port); |
|
860 THROW_NEW_DEBUGGER_EXCEPTION( |
|
861 "Can't attach to the process. Could not register the exception port " |
|
862 "with the target process."); |
|
863 } |
728 |
864 |
729 // use ptrace to stop the process |
865 // use ptrace to stop the process |
730 // on os x, ptrace only needs to be called on the process, not the individual threads |
866 // on os x, ptrace only needs to be called on the process, not the individual threads |
731 if (ptrace_attach(jpid) != true) { |
867 if (ptrace_attach(jpid) != true) { |
|
868 print_error("attach: ptrace failure in attaching to %d\n", (int)jpid); |
732 mach_port_deallocate(mach_task_self(), gTask); |
869 mach_port_deallocate(mach_task_self(), gTask); |
733 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); |
870 mach_port_deallocate(mach_task_self(), tgt_exception_port); |
|
871 THROW_NEW_DEBUGGER_EXCEPTION("Can't ptrace attach to the process"); |
|
872 } |
|
873 |
|
874 if (wait_for_exception() != true) { |
|
875 mach_port_deallocate(mach_task_self(), gTask); |
|
876 mach_port_deallocate(mach_task_self(), tgt_exception_port); |
|
877 THROW_NEW_DEBUGGER_EXCEPTION( |
|
878 "Can't attach to the process. Issues with reception of the exception message."); |
|
879 } |
|
880 |
|
881 // suspend all the threads in the task |
|
882 result = task_suspend(gTask); |
|
883 if (result != KERN_SUCCESS) { |
|
884 print_error("attach: task_suspend() failed: '%s' (%d)\n", |
|
885 mach_error_string(result), result); |
|
886 mach_port_deallocate(mach_task_self(), gTask); |
|
887 mach_port_deallocate(mach_task_self(), tgt_exception_port); |
|
888 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach. Unable to suspend all the threads in the task."); |
734 } |
889 } |
735 |
890 |
736 id symbolicator = nil; |
891 id symbolicator = nil; |
737 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator"); |
892 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator"); |
738 if (jrsSymbolicator != nil) { |
893 if (jrsSymbolicator != nil) { |
825 if (ph != NULL && ph->core != NULL) { |
995 if (ph != NULL && ph->core != NULL) { |
826 Prelease(ph); |
996 Prelease(ph); |
827 return; |
997 return; |
828 } |
998 } |
829 JNF_COCOA_ENTER(env); |
999 JNF_COCOA_ENTER(env); |
|
1000 |
830 task_t gTask = getTask(env, this_obj); |
1001 task_t gTask = getTask(env, this_obj); |
|
1002 kern_return_t k_res = 0; |
|
1003 |
|
1004 // Restore the pre-saved original exception ports registered with the target process |
|
1005 for (uint32_t i = 0; i < exception_saved_state.saved_exception_types_count; ++i) { |
|
1006 k_res = task_set_exception_ports(gTask, |
|
1007 exception_saved_state.saved_masks[i], |
|
1008 exception_saved_state.saved_ports[i], |
|
1009 exception_saved_state.saved_behaviors[i], |
|
1010 exception_saved_state.saved_flavors[i]); |
|
1011 if (k_res != KERN_SUCCESS) { |
|
1012 print_error("detach: task_set_exception_ports failed with %d while " |
|
1013 "restoring the target exception ports.\n", k_res); |
|
1014 detach_cleanup(gTask, env, this_obj, true); |
|
1015 } |
|
1016 } |
831 |
1017 |
832 // detach from the ptraced process causing it to resume execution |
1018 // detach from the ptraced process causing it to resume execution |
833 int pid; |
1019 int pid; |
834 kern_return_t k_res; |
|
835 k_res = pid_for_task(gTask, &pid); |
1020 k_res = pid_for_task(gTask, &pid); |
836 if (k_res != KERN_SUCCESS) { |
1021 if (k_res != KERN_SUCCESS) { |
837 print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); |
1022 print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); |
|
1023 detach_cleanup(gTask, env, this_obj, true); |
838 } |
1024 } |
839 else { |
1025 else { |
840 int res = ptrace(PT_DETACH, pid, 0, 0); |
1026 errno = 0; |
841 if (res < 0) { |
1027 ptrace(PT_DETACH, pid, (caddr_t)1, 0); |
842 print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); |
1028 if (errno != 0) { |
|
1029 print_error("detach: ptrace(PT_DETACH,...) failed: %s", strerror(errno)); |
|
1030 detach_cleanup(gTask, env, this_obj, true); |
843 } |
1031 } |
844 } |
1032 } |
845 |
1033 |
846 mach_port_deallocate(mach_task_self(), gTask); |
1034 // reply to the previous exception message |
847 id symbolicator = getSymbolicator(env, this_obj); |
1035 k_res = mach_msg(&rep_msg.header, |
848 if (symbolicator != nil) { |
1036 MACH_SEND_MSG| MACH_SEND_INTERRUPT, |
849 CFRelease(symbolicator); |
1037 rep_msg.header.msgh_size, |
850 } |
1038 0, |
|
1039 MACH_PORT_NULL, |
|
1040 MACH_MSG_TIMEOUT_NONE, |
|
1041 MACH_PORT_NULL); |
|
1042 if (k_res != MACH_MSG_SUCCESS) { |
|
1043 print_error("detach: mach_msg() for replying to pending exceptions failed: '%s' (%d)\n", |
|
1044 mach_error_string(k_res), k_res); |
|
1045 detach_cleanup(gTask, env, this_obj, true); |
|
1046 } |
|
1047 |
|
1048 detach_cleanup(gTask, env, this_obj, false); |
|
1049 |
851 JNF_COCOA_EXIT(env); |
1050 JNF_COCOA_EXIT(env); |
852 } |
1051 } |