1 /* 2 * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include <objc/objc-runtime.h> 26 #import <Foundation/Foundation.h> 27 28 #include <jni.h> 29 30 #import <mach/mach.h> 31 #import <mach/mach_types.h> 32 #import <sys/sysctl.h> 33 #import <stdio.h> 34 #import <string.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 #include "libproc_impl.h" 44 45 #define UNSUPPORTED_ARCH "Unsupported architecture!" 46 47 #if defined(x86_64) && !defined(amd64) 48 #define amd64 1 49 #endif 50 51 #if amd64 52 #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" 53 #else 54 #error UNSUPPORTED_ARCH 55 #endif 56 57 static jfieldID symbolicatorID = 0; // set in _init0 58 static jfieldID taskID = 0; // set in _init0 59 60 static jfieldID p_ps_prochandle_ID = 0; 61 static jfieldID loadObjectList_ID = 0; 62 static jmethodID listAdd_ID = 0; 63 64 static jmethodID createClosestSymbol_ID = 0; 65 static jmethodID createLoadObject_ID = 0; 66 static jmethodID getJavaThreadsInfo_ID = 0; 67 68 // indicator if thread id (lwpid_t) was set 69 static bool _threads_filled = false; 70 71 // mach_exc_server defined in the generated mach_excServer.c 72 extern boolean_t mach_exc_server(mach_msg_header_t *input_msg_hdr, 73 mach_msg_header_t *output_msg_hdr); 74 75 kern_return_t catch_mach_exception_raise( 76 mach_port_t exception_port, mach_port_t thread, 77 mach_port_t task, exception_type_t exception, 78 mach_exception_data_t code, 79 mach_msg_type_number_t code_cnt); 80 81 kern_return_t catch_mach_exception_raise_state( 82 mach_port_t exception_port, exception_type_t exception, 83 const mach_exception_data_t code, mach_msg_type_number_t code_cnt, 84 int *flavor, const thread_state_t old_state, 85 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, 86 mach_msg_type_number_t *new_state_cnt); 87 88 kern_return_t catch_mach_exception_raise_state_identity( 89 mach_port_t exception_port, mach_port_t thread, mach_port_t task, 90 exception_type_t exception, mach_exception_data_t code, 91 mach_msg_type_number_t code_cnt, int *flavor, thread_state_t old_state, 92 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, 93 mach_msg_type_number_t *new_state_cnt); 94 95 static struct exception_saved_state { 96 exception_mask_t saved_masks[EXC_TYPES_COUNT]; 97 mach_port_t saved_ports[EXC_TYPES_COUNT]; 98 exception_behavior_t saved_behaviors[EXC_TYPES_COUNT]; 99 thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT]; 100 mach_msg_type_number_t saved_exception_types_count; 101 } exception_saved_state; 102 103 static mach_port_t tgt_exception_port; 104 105 // Mirrors __Reply__mach_exception_raise_t generated in mach_excServer.c 106 static struct rep_msg { 107 mach_msg_header_t header; 108 NDR_record_t ndr; 109 kern_return_t ret_code; 110 } rep_msg; 111 112 // Mirrors __Request__mach_exception_raise_t generated in mach_excServer.c 113 // with a large trailing pad to avoid MACH_MSG_RCV_TOO_LARGE 114 static struct exc_msg { 115 mach_msg_header_t header; 116 // start of the kernel processed data 117 mach_msg_body_t msgh_body; 118 mach_msg_port_descriptor_t thread; 119 mach_msg_port_descriptor_t task; 120 // end of the kernel processed data 121 NDR_record_t ndr; 122 exception_type_t exception; 123 mach_msg_type_number_t code_cnt; 124 mach_exception_data_t code; // an array of int64_t 125 char pad[512]; 126 } exc_msg; 127 128 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { 129 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); 130 } 131 132 static id getSymbolicator(JNIEnv *env, jobject this_obj) { 133 jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID); 134 return (id)(intptr_t)ptr; 135 } 136 137 static void putTask(JNIEnv *env, jobject this_obj, task_t task) { 138 (*env)->SetLongField(env, this_obj, taskID, (jlong)task); 139 } 140 141 static task_t getTask(JNIEnv *env, jobject this_obj) { 142 jlong ptr = (*env)->GetLongField(env, this_obj, taskID); 143 return (task_t)ptr; 144 } 145 146 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; } 147 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;} 148 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; } 149 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;} 150 #define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); } 151 #define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; } 152 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } 153 154 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { 155 jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); 156 CHECK_EXCEPTION; 157 (*env)->ThrowNew(env, exceptionClass, errMsg); 158 } 159 160 static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { 161 jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID); 162 return (struct ps_prochandle*)(intptr_t)ptr; 163 } 164 165 #if defined(__i386__) 166 #define hsdb_thread_state_t x86_thread_state32_t 167 #define hsdb_float_state_t x86_float_state32_t 168 #define HSDB_THREAD_STATE x86_THREAD_STATE32 169 #define HSDB_FLOAT_STATE x86_FLOAT_STATE32 170 #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT 171 #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE32_COUNT 172 #elif defined(__x86_64__) 173 #define hsdb_thread_state_t x86_thread_state64_t 174 #define hsdb_float_state_t x86_float_state64_t 175 #define HSDB_THREAD_STATE x86_THREAD_STATE64 176 #define HSDB_FLOAT_STATE x86_FLOAT_STATE64 177 #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT 178 #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT 179 #else 180 #error UNSUPPORTED_ARCH 181 #endif 182 183 /* 184 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 185 * Method: init0 186 * Signature: ()V 187 */ 188 JNIEXPORT void JNICALL 189 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { 190 symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); 191 CHECK_EXCEPTION; 192 taskID = (*env)->GetFieldID(env, cls, "task", "J"); 193 CHECK_EXCEPTION; 194 195 // for core file 196 p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); 197 CHECK_EXCEPTION; 198 loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); 199 CHECK_EXCEPTION; 200 201 // methods we use 202 createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", 203 "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); 204 CHECK_EXCEPTION; 205 createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", 206 "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); 207 CHECK_EXCEPTION; 208 209 // java.util.List method we call 210 jclass listClass = (*env)->FindClass(env, "java/util/List"); 211 CHECK_EXCEPTION; 212 listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); 213 CHECK_EXCEPTION; 214 getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo", 215 "()[J"); 216 CHECK_EXCEPTION; 217 218 init_libproc(getenv("LIBSAPROC_DEBUG") != NULL); 219 } 220 221 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize 222 (JNIEnv *env, jclass cls) 223 { 224 #ifdef _LP64 225 return 8; 226 #else 227 #error UNSUPPORTED_ARCH 228 #endif 229 } 230 231 /** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */ 232 jlong lookupByNameIncore( 233 JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName) 234 { 235 const char *objectName_cstr, *symbolName_cstr; 236 jlong addr; 237 jboolean isCopy; 238 objectName_cstr = NULL; 239 if (objectName != NULL) { 240 objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy); 241 CHECK_EXCEPTION_(0); 242 } 243 symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy); 244 if ((*env)->ExceptionOccurred(env)) { 245 if (objectName_cstr != NULL) { 246 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); 247 } 248 return 0; 249 } 250 251 print_debug("look for %s \n", symbolName_cstr); 252 addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr); 253 254 if (objectName_cstr != NULL) { 255 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); 256 } 257 (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr); 258 return addr; 259 } 260 261 /* Create a pool and initiate a try block to catch any exception */ 262 #define JNI_COCOA_ENTER(env) \ 263 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \ 264 @try { 265 266 /* Don't allow NSExceptions to escape to Java. 267 * If there is a Java exception that has been thrown that should escape. 268 * And ensure we drain the auto-release pool. 269 */ 270 #define JNI_COCOA_EXIT(env) \ 271 } \ 272 @catch (NSException *e) { \ 273 NSLog(@"%@", [e callStackSymbols]); \ 274 } \ 275 @finally { \ 276 [pool drain]; \ 277 }; 278 279 static NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) { 280 281 if (jstr == NULL) { 282 return NULL; 283 } 284 jsize len = (*env)->GetStringLength(env, jstr); 285 const jchar *chars = (*env)->GetStringChars(env, jstr, NULL); 286 if (chars == NULL) { 287 return NULL; 288 } 289 NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len]; 290 (*env)->ReleaseStringChars(env, jstr, chars); 291 return result; 292 } 293 294 /* 295 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 296 * Method: lookupByName0 297 * Signature: (Ljava/lang/String;Ljava/lang/String;)J 298 */ 299 JNIEXPORT jlong JNICALL 300 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( 301 JNIEnv *env, jobject this_obj, 302 jstring objectName, jstring symbolName) 303 { 304 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 305 if (ph != NULL && ph->core != NULL) { 306 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); 307 } 308 309 jlong address = 0; 310 311 JNI_COCOA_ENTER(env); 312 313 NSString *symbolNameString = JavaStringToNSString(env, symbolName); 314 315 print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]); 316 317 id symbolicator = getSymbolicator(env, this_obj); 318 if (symbolicator != nil) { 319 uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend; 320 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); 321 } 322 323 print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); 324 JNI_COCOA_EXIT(env); 325 326 return address; 327 } 328 329 /* 330 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 331 * Method: lookupByAddress0 332 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; 333 */ 334 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0 335 (JNIEnv *env, jobject this_obj, jlong addr) { 336 uintptr_t offset; 337 const char* sym = NULL; 338 jstring sym_string; 339 340 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 341 if (ph != NULL && ph->core != NULL) { 342 sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); 343 if (sym == NULL) return 0; 344 sym_string = (*env)->NewStringUTF(env, sym); 345 CHECK_EXCEPTION_(0); 346 return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, 347 sym_string, (jlong)offset); 348 } 349 return 0; 350 } 351 352 /** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */ 353 jbyteArray readBytesFromCore( 354 JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes) 355 { 356 jboolean isCopy; 357 jbyteArray array; 358 jbyte *bufPtr; 359 ps_err_e err; 360 361 array = (*env)->NewByteArray(env, numBytes); 362 CHECK_EXCEPTION_(0); 363 bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); 364 CHECK_EXCEPTION_(0); 365 366 err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); 367 (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); 368 return (err == PS_OK)? array : 0; 369 } 370 371 /* 372 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 373 * Method: readBytesFromProcess0 374 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; 375 */ 376 JNIEXPORT jbyteArray JNICALL 377 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( 378 JNIEnv *env, jobject this_obj, 379 jlong addr, jlong numBytes) 380 { 381 print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); 382 383 // must allocate storage instead of using former parameter buf 384 jbyteArray array; 385 386 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 387 if (ph != NULL && ph->core != NULL) { 388 return readBytesFromCore(env, ph, this_obj, addr, numBytes); 389 } 390 391 array = (*env)->NewByteArray(env, numBytes); 392 CHECK_EXCEPTION_(0); 393 394 unsigned long alignedAddress; 395 unsigned long alignedLength = 0; 396 kern_return_t result; 397 vm_offset_t *pages; 398 int *mapped; 399 long pageCount; 400 uint byteCount; 401 int i; 402 unsigned long remaining; 403 404 alignedAddress = trunc_page(addr); 405 if (addr != alignedAddress) { 406 alignedLength += addr - alignedAddress; 407 } 408 alignedLength = round_page(numBytes); 409 pageCount = alignedLength/vm_page_size; 410 411 // Allocate storage for pages and flags. 412 pages = malloc(pageCount * sizeof(vm_offset_t)); 413 if (pages == NULL) { 414 (*env)->DeleteLocalRef(env, array); 415 return NULL; 416 } 417 mapped = calloc(pageCount, sizeof(int)); 418 if (mapped == NULL) { 419 (*env)->DeleteLocalRef(env, array); 420 free(pages); 421 return NULL; 422 } 423 424 task_t gTask = getTask(env, this_obj); 425 // Try to read each of the pages. 426 for (i = 0; i < pageCount; i++) { 427 result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, 428 &pages[i], &byteCount); 429 mapped[i] = (result == KERN_SUCCESS); 430 // assume all failures are unmapped pages 431 } 432 433 print_debug("%ld pages\n", pageCount); 434 435 remaining = numBytes; 436 437 for (i = 0; i < pageCount; i++) { 438 unsigned long len = vm_page_size; 439 unsigned long start = 0; 440 441 if (i == 0) { 442 start = addr - alignedAddress; 443 len = vm_page_size - start; 444 } 445 446 if (i == (pageCount - 1)) { 447 len = remaining; 448 } 449 450 if (mapped[i]) { 451 print_debug("page %d mapped (len %ld start %ld)\n", i, len, start); 452 (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start)); 453 vm_deallocate(mach_task_self(), pages[i], vm_page_size); 454 } 455 456 remaining -= len; 457 } 458 459 free (pages); 460 free (mapped); 461 return array; 462 } 463 464 /** Only used for core file reading, set thread_id for threads which is got after core file parsed. 465 * Thread context is available in Mach-O core file but thread id is not. We can get thread id 466 * from Threads which store all java threads information when they are created. Here we can identify 467 * them as java threads by checking if a thread's rsp or rbp within a java thread's stack. 468 * Note Macosx uses unique_thread_id which is different from other platforms though printed ids 469 * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long 470 * integers to host all java threads' id, stack_start, stack_end as: 471 * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] 472 * 473 * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). 474 * This function should be called only once if succeeded 475 */ 476 bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { 477 int n = 0, i = 0, j; 478 struct reg regs; 479 480 jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); 481 CHECK_EXCEPTION_(false); 482 int len = (int)(*env)->GetArrayLength(env, thrinfos); 483 uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); 484 CHECK_EXCEPTION_(false); 485 n = get_num_threads(ph); 486 print_debug("fill_java_threads called, num_of_thread = %d\n", n); 487 for (i = 0; i < n; i++) { 488 if (!get_nth_lwp_regs(ph, i, ®s)) { 489 print_debug("Could not get regs of thread %d, already set!\n", i); 490 return false; 491 } 492 for (j = 0; j < len; j += 3) { 493 lwpid_t uid = cinfos[j]; 494 uint64_t beg = cinfos[j + 1]; 495 uint64_t end = cinfos[j + 2]; 496 if ((regs.r_rsp < end && regs.r_rsp >= beg) || 497 (regs.r_rbp < end && regs.r_rbp >= beg)) { 498 set_lwp_id(ph, i, uid); 499 break; 500 } 501 } 502 } 503 (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0); 504 CHECK_EXCEPTION_(false); 505 return true; 506 } 507 508 /* For core file only, called from 509 * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0 510 */ 511 jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) { 512 if (!_threads_filled) { 513 if (!fill_java_threads(env, this_obj, ph)) { 514 throw_new_debugger_exception(env, "Failed to fill in threads"); 515 return 0; 516 } else { 517 _threads_filled = true; 518 } 519 } 520 521 struct reg gregs; 522 jboolean isCopy; 523 jlongArray array; 524 jlong *regs; 525 526 if (get_lwp_regs(ph, lwp_id, &gregs) != true) { 527 THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0); 528 } 529 530 #undef NPRGREG 531 #undef REG_INDEX 532 #if amd64 533 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG 534 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg 535 536 array = (*env)->NewLongArray(env, NPRGREG); 537 CHECK_EXCEPTION_(0); 538 regs = (*env)->GetLongArrayElements(env, array, &isCopy); 539 540 regs[REG_INDEX(R15)] = gregs.r_r15; 541 regs[REG_INDEX(R14)] = gregs.r_r14; 542 regs[REG_INDEX(R13)] = gregs.r_r13; 543 regs[REG_INDEX(R12)] = gregs.r_r12; 544 regs[REG_INDEX(RBP)] = gregs.r_rbp; 545 regs[REG_INDEX(RBX)] = gregs.r_rbx; 546 regs[REG_INDEX(R11)] = gregs.r_r11; 547 regs[REG_INDEX(R10)] = gregs.r_r10; 548 regs[REG_INDEX(R9)] = gregs.r_r9; 549 regs[REG_INDEX(R8)] = gregs.r_r8; 550 regs[REG_INDEX(RAX)] = gregs.r_rax; 551 regs[REG_INDEX(RCX)] = gregs.r_rcx; 552 regs[REG_INDEX(RDX)] = gregs.r_rdx; 553 regs[REG_INDEX(RSI)] = gregs.r_rsi; 554 regs[REG_INDEX(RDI)] = gregs.r_rdi; 555 regs[REG_INDEX(RIP)] = gregs.r_rip; 556 regs[REG_INDEX(CS)] = gregs.r_cs; 557 regs[REG_INDEX(RSP)] = gregs.r_rsp; 558 regs[REG_INDEX(SS)] = gregs.r_ss; 559 regs[REG_INDEX(FSBASE)] = 0; 560 regs[REG_INDEX(GSBASE)] = 0; 561 regs[REG_INDEX(DS)] = gregs.r_ds; 562 regs[REG_INDEX(ES)] = gregs.r_es; 563 regs[REG_INDEX(FS)] = gregs.r_fs; 564 regs[REG_INDEX(GS)] = gregs.r_gs; 565 regs[REG_INDEX(TRAPNO)] = gregs.r_trapno; 566 regs[REG_INDEX(RFL)] = gregs.r_rflags; 567 568 #endif /* amd64 */ 569 (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); 570 return array; 571 } 572 573 /* 574 * Lookup the thread_t that corresponds to the given thread_id. 575 * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO 576 * and reading the m_ident_info.thread_id returned. 577 * The returned thread_t is the mach send right to the kernel port for the corresponding thread. 578 * 579 * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self() 580 * in the VM, but that thread port is not valid for a remote debugger to access the thread. 581 */ 582 thread_t 583 lookupThreadFromThreadId(task_t task, jlong thread_id) { 584 print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); 585 586 thread_array_t thread_list = NULL; 587 mach_msg_type_number_t thread_list_count = 0; 588 thread_t result_thread = 0; 589 int i; 590 591 // get the list of all the send rights 592 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); 593 if (result != KERN_SUCCESS) { 594 print_debug("task_threads returned 0x%x\n", result); 595 return 0; 596 } 597 598 for(i = 0 ; i < thread_list_count; i++) { 599 thread_identifier_info_data_t m_ident_info; 600 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 601 602 // get the THREAD_IDENTIFIER_INFO for the send right 603 result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); 604 if (result != KERN_SUCCESS) { 605 print_debug("thread_info returned 0x%x\n", result); 606 break; 607 } 608 609 // if this is the one we're looking for, return the send right 610 if (thread_id == m_ident_info.thread_id) 611 { 612 result_thread = thread_list[i]; 613 break; 614 } 615 } 616 617 vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); 618 vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count); 619 620 return result_thread; 621 } 622 623 624 /* 625 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 626 * Method: getThreadIntegerRegisterSet0 627 * Signature: (J)[J 628 */ 629 JNIEXPORT jlongArray JNICALL 630 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( 631 JNIEnv *env, jobject this_obj, 632 jlong thread_id) 633 { 634 print_debug("getThreadRegisterSet0 called\n"); 635 636 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 637 if (ph != NULL && ph->core != NULL) { 638 return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph); 639 } 640 641 kern_return_t result; 642 thread_t tid; 643 mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT; 644 hsdb_thread_state_t state; 645 jlongArray registerArray; 646 jlong *primitiveArray; 647 task_t gTask = getTask(env, this_obj); 648 649 tid = lookupThreadFromThreadId(gTask, thread_id); 650 651 result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); 652 653 if (result != KERN_SUCCESS) { 654 print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result); 655 return NULL; 656 } 657 658 #if amd64 659 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG 660 #undef REG_INDEX 661 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg 662 663 // 64 bit 664 print_debug("Getting threads for a 64-bit process\n"); 665 registerArray = (*env)->NewLongArray(env, NPRGREG); 666 CHECK_EXCEPTION_(0); 667 primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); 668 669 primitiveArray[REG_INDEX(R15)] = state.__r15; 670 primitiveArray[REG_INDEX(R14)] = state.__r14; 671 primitiveArray[REG_INDEX(R13)] = state.__r13; 672 primitiveArray[REG_INDEX(R12)] = state.__r12; 673 primitiveArray[REG_INDEX(R11)] = state.__r11; 674 primitiveArray[REG_INDEX(R10)] = state.__r10; 675 primitiveArray[REG_INDEX(R9)] = state.__r9; 676 primitiveArray[REG_INDEX(R8)] = state.__r8; 677 primitiveArray[REG_INDEX(RDI)] = state.__rdi; 678 primitiveArray[REG_INDEX(RSI)] = state.__rsi; 679 primitiveArray[REG_INDEX(RBP)] = state.__rbp; 680 primitiveArray[REG_INDEX(RBX)] = state.__rbx; 681 primitiveArray[REG_INDEX(RDX)] = state.__rdx; 682 primitiveArray[REG_INDEX(RCX)] = state.__rcx; 683 primitiveArray[REG_INDEX(RAX)] = state.__rax; 684 primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used 685 primitiveArray[REG_INDEX(ERR)] = 0; // err, not used 686 primitiveArray[REG_INDEX(RIP)] = state.__rip; 687 primitiveArray[REG_INDEX(CS)] = state.__cs; 688 primitiveArray[REG_INDEX(RFL)] = state.__rflags; 689 primitiveArray[REG_INDEX(RSP)] = state.__rsp; 690 primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS 691 primitiveArray[REG_INDEX(FS)] = state.__fs; 692 primitiveArray[REG_INDEX(GS)] = state.__gs; 693 primitiveArray[REG_INDEX(ES)] = 0; 694 primitiveArray[REG_INDEX(DS)] = 0; 695 primitiveArray[REG_INDEX(FSBASE)] = 0; 696 primitiveArray[REG_INDEX(GSBASE)] = 0; 697 print_debug("set registers\n"); 698 699 (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); 700 701 #else 702 #error UNSUPPORTED_ARCH 703 #endif /* amd64 */ 704 705 return registerArray; 706 } 707 708 /* 709 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 710 * Method: translateTID0 711 * Signature: (I)I 712 */ 713 JNIEXPORT jint JNICALL 714 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( 715 JNIEnv *env, jobject this_obj, jint tid) 716 { 717 print_debug("translateTID0 called on tid = 0x%x\n", (int)tid); 718 719 kern_return_t result; 720 thread_t foreign_tid, usable_tid; 721 mach_msg_type_name_t type; 722 723 foreign_tid = tid; 724 725 task_t gTask = getTask(env, this_obj); 726 result = mach_port_extract_right(gTask, foreign_tid, 727 MACH_MSG_TYPE_COPY_SEND, 728 &usable_tid, &type); 729 if (result != KERN_SUCCESS) 730 return -1; 731 732 print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); 733 734 return (jint) usable_tid; 735 } 736 737 // attach to a process/thread specified by "pid" 738 static bool ptrace_attach(pid_t pid) { 739 errno = 0; 740 ptrace(PT_ATTACHEXC, pid, 0, 0); 741 742 if (errno != 0) { 743 print_error("ptrace_attach: ptrace(PT_ATTACHEXC,...) failed: %s", strerror(errno)); 744 return false; 745 } 746 return true; 747 } 748 749 kern_return_t catch_mach_exception_raise( 750 mach_port_t exception_port, mach_port_t thread_port, mach_port_t task_port, 751 exception_type_t exception_type, mach_exception_data_t codes, 752 mach_msg_type_number_t num_codes) { 753 754 print_debug("catch_mach_exception_raise: Exception port = %d thread_port = %d " 755 "task port %d exc type = %d num_codes %d\n", 756 exception_port, thread_port, task_port, exception_type, num_codes); 757 758 // This message should denote a Unix soft signal, with 759 // 1. the exception type = EXC_SOFTWARE 760 // 2. codes[0] (which is the code) = EXC_SOFT_SIGNAL 761 // 3. codes[1] (which is the sub-code) = SIGSTOP 762 if (!(exception_type == EXC_SOFTWARE && 763 codes[0] == EXC_SOFT_SIGNAL && 764 codes[num_codes -1] == SIGSTOP)) { 765 print_error("catch_mach_exception_raise: Message doesn't denote a Unix " 766 "soft signal. exception_type = %d, codes[0] = %d, " 767 "codes[num_codes -1] = %d, num_codes = %d\n", 768 exception_type, codes[0], codes[num_codes - 1], num_codes); 769 return MACH_RCV_INVALID_TYPE; 770 } 771 return KERN_SUCCESS; 772 } 773 774 kern_return_t catch_mach_exception_raise_state( 775 mach_port_t exception_port, exception_type_t exception, const mach_exception_data_t code, 776 mach_msg_type_number_t code_cnt, int *flavor, const thread_state_t old_state, 777 mach_msg_type_number_t old_state_cnt, thread_state_t new_state, 778 mach_msg_type_number_t *new_state_cnt) { 779 return MACH_RCV_INVALID_TYPE; 780 } 781 782 783 kern_return_t catch_mach_exception_raise_state_identity( 784 mach_port_t exception_port, mach_port_t thread, mach_port_t task, 785 exception_type_t exception, mach_exception_data_t code, 786 mach_msg_type_number_t code_cnt, int *flavor, 787 thread_state_t old_state, mach_msg_type_number_t old_state_cnt, 788 thread_state_t new_state, mach_msg_type_number_t *new_state_cnt) { 789 return MACH_RCV_INVALID_TYPE; 790 } 791 792 // wait to receive an exception message 793 static bool wait_for_exception() { 794 kern_return_t result; 795 796 result = mach_msg(&exc_msg.header, 797 MACH_RCV_MSG, 798 0, 799 sizeof(exc_msg), 800 tgt_exception_port, 801 MACH_MSG_TIMEOUT_NONE, 802 MACH_PORT_NULL); 803 804 if (result != MACH_MSG_SUCCESS) { 805 print_error("attach: wait_for_exception: mach_msg() failed: '%s' (%d)\n", 806 mach_error_string(result), result); 807 return false; 808 } 809 810 if (mach_exc_server(&exc_msg.header, &rep_msg.header) == false || 811 rep_msg.ret_code != KERN_SUCCESS) { 812 print_error("attach: wait_for_exception: mach_exc_server failure\n"); 813 if (rep_msg.ret_code != KERN_SUCCESS) { 814 print_error("catch_mach_exception_raise() failed '%s' (%d)\n", 815 mach_error_string(rep_msg.ret_code), rep_msg.ret_code); 816 } 817 return false; 818 } 819 820 print_debug("reply msg from mach_exc_server: (msg->{bits = %#x, size = %u, " 821 "remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x},)", 822 rep_msg.header.msgh_bits, rep_msg.header.msgh_size, 823 rep_msg.header.msgh_remote_port, rep_msg.header.msgh_local_port, 824 rep_msg.header.msgh_reserved, rep_msg.header.msgh_id); 825 826 return true; 827 } 828 829 /* 830 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 831 * Method: attach0 832 * Signature: (I)V 833 */ 834 JNIEXPORT void JNICALL 835 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( 836 JNIEnv *env, jobject this_obj, jint jpid) 837 { 838 print_debug("attach0 called for jpid=%d\n", (int)jpid); 839 840 JNI_COCOA_ENTER(env); 841 842 kern_return_t result; 843 task_t gTask = 0; 844 845 result = task_for_pid(mach_task_self(), jpid, &gTask); 846 if (result != KERN_SUCCESS) { 847 print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result); 848 THROW_NEW_DEBUGGER_EXCEPTION( 849 "Can't attach to the process. Could be caused by an incorrect pid or lack of privileges."); 850 } 851 putTask(env, this_obj, gTask); 852 853 // Allocate an exception port. 854 result = mach_port_allocate(mach_task_self(), 855 MACH_PORT_RIGHT_RECEIVE, 856 &tgt_exception_port); 857 if (result != KERN_SUCCESS) { 858 print_error("attach: mach_port_allocate() for tgt_exception_port failed: '%s' (%d)\n", 859 mach_error_string(result), result); 860 THROW_NEW_DEBUGGER_EXCEPTION( 861 "Can't attach to the process. Couldn't allocate an exception port."); 862 } 863 864 // Enable the new exception port to send messages. 865 result = mach_port_insert_right (mach_task_self(), 866 tgt_exception_port, 867 tgt_exception_port, 868 MACH_MSG_TYPE_MAKE_SEND); 869 if (result != KERN_SUCCESS) { 870 print_error("attach: mach_port_insert_right() failed for port 0x%x: '%s' (%d)\n", 871 tgt_exception_port, mach_error_string(result), result); 872 THROW_NEW_DEBUGGER_EXCEPTION( 873 "Can't attach to the process. Couldn't add send privileges to the exception port."); 874 } 875 876 // Save the existing original exception ports registered with the target 877 // process (for later restoration while detaching from the process). 878 result = task_get_exception_ports(gTask, 879 EXC_MASK_ALL, 880 exception_saved_state.saved_masks, 881 &exception_saved_state.saved_exception_types_count, 882 exception_saved_state.saved_ports, 883 exception_saved_state.saved_behaviors, 884 exception_saved_state.saved_flavors); 885 886 if (result != KERN_SUCCESS) { 887 print_error("attach: task_get_exception_ports() failed: '%s' (%d)\n", 888 mach_error_string(result), result); 889 THROW_NEW_DEBUGGER_EXCEPTION( 890 "Can't attach to the process. Could not get the target exception ports."); 891 } 892 893 // register the exception port to be used for all future exceptions with the 894 // target process. 895 result = task_set_exception_ports(gTask, 896 EXC_MASK_ALL, 897 tgt_exception_port, 898 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, 899 THREAD_STATE_NONE); 900 901 if (result != KERN_SUCCESS) { 902 print_error("attach: task_set_exception_ports() failed -- port 0x%x: '%s' (%d)\n", 903 tgt_exception_port, mach_error_string(result), result); 904 mach_port_deallocate(mach_task_self(), gTask); 905 mach_port_deallocate(mach_task_self(), tgt_exception_port); 906 THROW_NEW_DEBUGGER_EXCEPTION( 907 "Can't attach to the process. Could not register the exception port " 908 "with the target process."); 909 } 910 911 // use ptrace to stop the process 912 // on os x, ptrace only needs to be called on the process, not the individual threads 913 if (ptrace_attach(jpid) != true) { 914 print_error("attach: ptrace failure in attaching to %d\n", (int)jpid); 915 mach_port_deallocate(mach_task_self(), gTask); 916 mach_port_deallocate(mach_task_self(), tgt_exception_port); 917 THROW_NEW_DEBUGGER_EXCEPTION("Can't ptrace attach to the process"); 918 } 919 920 if (wait_for_exception() != true) { 921 mach_port_deallocate(mach_task_self(), gTask); 922 mach_port_deallocate(mach_task_self(), tgt_exception_port); 923 THROW_NEW_DEBUGGER_EXCEPTION( 924 "Can't attach to the process. Issues with reception of the exception message."); 925 } 926 927 // suspend all the threads in the task 928 result = task_suspend(gTask); 929 if (result != KERN_SUCCESS) { 930 print_error("attach: task_suspend() failed: '%s' (%d)\n", 931 mach_error_string(result), result); 932 mach_port_deallocate(mach_task_self(), gTask); 933 mach_port_deallocate(mach_task_self(), tgt_exception_port); 934 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach. Unable to suspend all the threads in the task."); 935 } 936 937 id symbolicator = nil; 938 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator"); 939 if (jrsSymbolicator != nil) { 940 id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend; 941 symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid); 942 } 943 if (symbolicator != nil) { 944 CFRetain(symbolicator); // pin symbolicator while in java heap 945 } 946 947 putSymbolicator(env, this_obj, symbolicator); 948 if (symbolicator == nil) { 949 mach_port_deallocate(mach_task_self(), gTask); 950 mach_port_deallocate(mach_task_self(), tgt_exception_port); 951 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process"); 952 } 953 954 JNI_COCOA_EXIT(env); 955 } 956 957 /** For core file, 958 called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */ 959 static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { 960 int n = 0, i = 0; 961 962 // add load objects 963 n = get_num_libs(ph); 964 for (i = 0; i < n; i++) { 965 uintptr_t base; 966 const char* name; 967 jobject loadObject; 968 jobject loadObjectList; 969 jstring nameString; 970 971 base = get_lib_base(ph, i); 972 name = get_lib_name(ph, i); 973 nameString = (*env)->NewStringUTF(env, name); 974 CHECK_EXCEPTION; 975 loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, 976 nameString, (jlong)0, (jlong)base); 977 CHECK_EXCEPTION; 978 loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); 979 CHECK_EXCEPTION; 980 (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); 981 CHECK_EXCEPTION; 982 } 983 } 984 985 /* 986 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 987 * Method: attach0 988 * Signature: (Ljava/lang/String;Ljava/lang/String;)V 989 */ 990 JNIEXPORT void JNICALL 991 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2( 992 JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) 993 { 994 const char *execName_cstr; 995 const char *coreName_cstr; 996 jboolean isCopy; 997 struct ps_prochandle* ph; 998 999 execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); 1000 CHECK_EXCEPTION; 1001 coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); 1002 if ((*env)->ExceptionOccurred(env)) { 1003 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 1004 return; 1005 } 1006 1007 print_debug("attach: %s %s\n", execName_cstr, coreName_cstr); 1008 1009 if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { 1010 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 1011 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 1012 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); 1013 } 1014 (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); 1015 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 1016 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 1017 fillLoadObjects(env, this_obj, ph); 1018 } 1019 1020 static void detach_cleanup(task_t gTask, JNIEnv *env, jobject this_obj, bool throw_exception) { 1021 mach_port_deallocate(mach_task_self(), tgt_exception_port); 1022 mach_port_deallocate(mach_task_self(), gTask); 1023 1024 id symbolicator = getSymbolicator(env, this_obj); 1025 if (symbolicator != nil) { 1026 CFRelease(symbolicator); 1027 } 1028 if (throw_exception) { 1029 THROW_NEW_DEBUGGER_EXCEPTION("Cannot detach."); 1030 } 1031 } 1032 1033 /* 1034 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 1035 * Method: detach0 1036 * Signature: ()V 1037 */ 1038 JNIEXPORT void JNICALL 1039 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( 1040 JNIEnv *env, jobject this_obj) 1041 { 1042 print_debug("detach0 called\n"); 1043 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1044 if (ph != NULL && ph->core != NULL) { 1045 Prelease(ph); 1046 return; 1047 } 1048 1049 JNI_COCOA_ENTER(env); 1050 1051 task_t gTask = getTask(env, this_obj); 1052 kern_return_t k_res = 0; 1053 1054 // Restore the pre-saved original exception ports registered with the target process 1055 for (uint32_t i = 0; i < exception_saved_state.saved_exception_types_count; ++i) { 1056 k_res = task_set_exception_ports(gTask, 1057 exception_saved_state.saved_masks[i], 1058 exception_saved_state.saved_ports[i], 1059 exception_saved_state.saved_behaviors[i], 1060 exception_saved_state.saved_flavors[i]); 1061 if (k_res != KERN_SUCCESS) { 1062 print_error("detach: task_set_exception_ports failed with %d while " 1063 "restoring the target exception ports.\n", k_res); 1064 detach_cleanup(gTask, env, this_obj, true); 1065 } 1066 } 1067 1068 // detach from the ptraced process causing it to resume execution 1069 int pid; 1070 k_res = pid_for_task(gTask, &pid); 1071 if (k_res != KERN_SUCCESS) { 1072 print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); 1073 detach_cleanup(gTask, env, this_obj, true); 1074 } 1075 else { 1076 errno = 0; 1077 ptrace(PT_DETACH, pid, (caddr_t)1, 0); 1078 if (errno != 0) { 1079 print_error("detach: ptrace(PT_DETACH,...) failed: %s", strerror(errno)); 1080 detach_cleanup(gTask, env, this_obj, true); 1081 } 1082 } 1083 1084 // reply to the previous exception message 1085 k_res = mach_msg(&rep_msg.header, 1086 MACH_SEND_MSG| MACH_SEND_INTERRUPT, 1087 rep_msg.header.msgh_size, 1088 0, 1089 MACH_PORT_NULL, 1090 MACH_MSG_TIMEOUT_NONE, 1091 MACH_PORT_NULL); 1092 if (k_res != MACH_MSG_SUCCESS) { 1093 print_error("detach: mach_msg() for replying to pending exceptions failed: '%s' (%d)\n", 1094 mach_error_string(k_res), k_res); 1095 detach_cleanup(gTask, env, this_obj, true); 1096 } 1097 1098 detach_cleanup(gTask, env, this_obj, false); 1099 1100 JNI_COCOA_EXIT(env); 1101 }