rev 54099 : 8257988: Remove JNF dependency from libsaproc/MacosxDebuggerLocal.m
Reviewed-by: yan

   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, &regs)) {
 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 }
--- EOF ---