1 /*
   2  * Copyright (c) 2002, 2016, 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 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  28 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  29 
  30 #include <jni.h>
  31 
  32 #import <mach/mach.h>
  33 #import <mach/mach_types.h>
  34 #import <sys/sysctl.h>
  35 #import <stdio.h>
  36 #import <stdarg.h>
  37 #import <stdlib.h>
  38 #import <strings.h>
  39 #import <dlfcn.h>
  40 #import <limits.h>
  41 #import <errno.h>
  42 #import <sys/types.h>
  43 #import <sys/ptrace.h>
  44 #include "libproc_impl.h"
  45 
  46 #define UNSUPPORTED_ARCH "Unsupported architecture!"
  47 
  48 #if defined(x86_64) && !defined(amd64)
  49 #define amd64 1
  50 #endif
  51 
  52 #if amd64
  53 #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
  54 #else
  55 #error UNSUPPORTED_ARCH
  56 #endif
  57 
  58 static jfieldID symbolicatorID = 0; // set in _init0
  59 static jfieldID taskID = 0; // set in _init0
  60 
  61 static jfieldID p_ps_prochandle_ID = 0;
  62 static jfieldID loadObjectList_ID = 0;
  63 static jmethodID listAdd_ID = 0;
  64 
  65 static jmethodID createClosestSymbol_ID = 0;
  66 static jmethodID createLoadObject_ID = 0;
  67 static jmethodID getJavaThreadsInfo_ID = 0;
  68 
  69 // indicator if thread id (lwpid_t) was set
  70 static bool _threads_filled = false;
  71 
  72 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
  73   (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
  74 }
  75 
  76 static id getSymbolicator(JNIEnv *env, jobject this_obj) {
  77   jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
  78   return (id)(intptr_t)ptr;
  79 }
  80 
  81 static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
  82   (*env)->SetLongField(env, this_obj, taskID, (jlong)task);
  83 }
  84 
  85 static task_t getTask(JNIEnv *env, jobject this_obj) {
  86   jlong ptr = (*env)->GetLongField(env, this_obj, taskID);
  87   return (task_t)ptr;
  88 }
  89 
  90 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
  91 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
  92 #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;}
  94 #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; } 
  96 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } 
  97 
  98 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
  99   jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");
 100   CHECK_EXCEPTION;
 101   (*env)->ThrowNew(env, exceptionClass, errMsg);
 102 }
 103 
 104 static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
 105   jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);
 106   return (struct ps_prochandle*)(intptr_t)ptr;
 107 }
 108 
 109 #if defined(__i386__)
 110     #define hsdb_thread_state_t     x86_thread_state32_t
 111     #define hsdb_float_state_t      x86_float_state32_t
 112     #define HSDB_THREAD_STATE       x86_THREAD_STATE32
 113     #define HSDB_FLOAT_STATE        x86_FLOAT_STATE32
 114     #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
 115     #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE32_COUNT
 116 #elif defined(__x86_64__)
 117     #define hsdb_thread_state_t     x86_thread_state64_t
 118     #define hsdb_float_state_t      x86_float_state64_t
 119     #define HSDB_THREAD_STATE       x86_THREAD_STATE64
 120     #define HSDB_FLOAT_STATE        x86_FLOAT_STATE64
 121     #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
 122     #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE64_COUNT
 123 #else
 124     #error UNSUPPORTED_ARCH
 125 #endif
 126 
 127 /*
 128  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 129  * Method:    init0
 130  * Signature: ()V
 131  */
 132 JNIEXPORT void JNICALL 
 133 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
 134   symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
 135   CHECK_EXCEPTION;
 136   taskID = (*env)->GetFieldID(env, cls, "task", "J");
 137   CHECK_EXCEPTION;
 138 
 139   // for core file
 140   p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");
 141   CHECK_EXCEPTION;
 142   loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");
 143   CHECK_EXCEPTION;
 144 
 145   // methods we use
 146   createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",
 147                     "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
 148   CHECK_EXCEPTION;
 149   createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",
 150                     "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
 151   CHECK_EXCEPTION;
 152 
 153   // java.util.List method we call
 154   jclass listClass = (*env)->FindClass(env, "java/util/List");
 155   CHECK_EXCEPTION;
 156   listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");
 157   CHECK_EXCEPTION;
 158   getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo",
 159                                                      "()[J");
 160   CHECK_EXCEPTION;
 161 
 162   init_libproc(getenv("LIBSAPROC_DEBUG") != NULL);
 163 }
 164 
 165 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
 166   (JNIEnv *env, jclass cls)
 167 {
 168 #ifdef _LP64
 169   return 8;
 170 #else
 171   #error UNSUPPORTED_ARCH
 172 #endif
 173 }
 174 
 175 /** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */
 176 jlong lookupByNameIncore(
 177   JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName)
 178 {
 179   const char *objectName_cstr, *symbolName_cstr;
 180   jlong addr;
 181   jboolean isCopy;
 182   objectName_cstr = NULL;
 183   if (objectName != NULL) {
 184     objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);
 185     CHECK_EXCEPTION_(0);
 186   }
 187   symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
 188   CHECK_EXCEPTION_(0);
 189 
 190   print_debug("look for %s \n", symbolName_cstr);
 191   addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
 192 
 193   if (objectName_cstr != NULL) {
 194     (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
 195   }
 196   (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
 197   return addr;
 198 }
 199 
 200 /*
 201  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 202  * Method:    lookupByName0
 203  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
 204  */
 205 JNIEXPORT jlong JNICALL 
 206 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
 207   JNIEnv *env, jobject this_obj, 
 208   jstring objectName, jstring symbolName) 
 209 {
 210   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
 211   if (ph != NULL && ph->core != NULL) {
 212     return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
 213   }
 214 
 215   jlong address = 0;
 216 
 217 JNF_COCOA_ENTER(env);
 218   NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
 219 
 220   print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
 221 
 222   id symbolicator = getSymbolicator(env, this_obj);
 223   if (symbolicator != nil) {
 224     uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
 225     address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
 226   }
 227 
 228   print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
 229 JNF_COCOA_EXIT(env);
 230 
 231   return address;
 232 }
 233 
 234 /*
 235  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 236  * Method:    lookupByAddress0
 237  * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
 238  */
 239 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
 240   (JNIEnv *env, jobject this_obj, jlong addr) {
 241   uintptr_t offset;
 242   const char* sym = NULL;
 243   jstring sym_string;
 244 
 245   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
 246   if (ph != NULL && ph->core != NULL) {
 247     sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
 248     if (sym == NULL) return 0;
 249     sym_string = (*env)->NewStringUTF(env, sym);
 250     CHECK_EXCEPTION_(0);
 251     return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
 252                                                 sym_string, (jlong)offset);
 253   }
 254   return 0;
 255 }
 256 
 257 /** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */
 258 jbyteArray readBytesFromCore(
 259   JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes)
 260 {
 261   jboolean isCopy;
 262   jbyteArray array;
 263   jbyte *bufPtr;
 264   ps_err_e err;
 265 
 266   array = (*env)->NewByteArray(env, numBytes);
 267   CHECK_EXCEPTION_(0);
 268   bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
 269   CHECK_EXCEPTION_(0);
 270 
 271   err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
 272   (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
 273   return (err == PS_OK)? array : 0;
 274 }
 275 
 276 /*
 277  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 278  * Method:    readBytesFromProcess0
 279  * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
 280  */
 281 JNIEXPORT jbyteArray JNICALL
 282 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
 283   JNIEnv *env, jobject this_obj, 
 284   jlong addr, jlong numBytes) 
 285 {
 286   print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
 287 
 288   // must allocate storage instead of using former parameter buf
 289   jbyteArray array;
 290 
 291   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
 292   if (ph != NULL && ph->core != NULL) {
 293     return readBytesFromCore(env, ph, this_obj, addr, numBytes);
 294   }
 295 
 296   array = (*env)->NewByteArray(env, numBytes);
 297   CHECK_EXCEPTION_(0);
 298 
 299   unsigned long alignedAddress;
 300   unsigned long alignedLength = 0;
 301   kern_return_t result;
 302   vm_offset_t *pages;
 303   int *mapped;
 304   long pageCount;
 305   uint byteCount;
 306   int i;
 307   unsigned long remaining;
 308 
 309   alignedAddress = trunc_page(addr);
 310   if (addr != alignedAddress) {
 311     alignedLength += addr - alignedAddress;
 312   }
 313   alignedLength = round_page(numBytes);
 314   pageCount = alignedLength/vm_page_size;
 315 
 316   // Allocate storage for pages and flags.
 317   pages = malloc(pageCount * sizeof(vm_offset_t));
 318   mapped = calloc(pageCount, sizeof(int));
 319 
 320   task_t gTask = getTask(env, this_obj);
 321   // Try to read each of the pages.
 322   for (i = 0; i < pageCount; i++) {
 323     result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, 
 324                      &pages[i], &byteCount);
 325     mapped[i] = (result == KERN_SUCCESS); 
 326     // assume all failures are unmapped pages
 327   }
 328 
 329   print_debug("%ld pages\n", pageCount);
 330         
 331   remaining = numBytes;
 332         
 333   for (i = 0; i < pageCount; i++) {
 334     unsigned long len = vm_page_size;
 335     unsigned long start = 0;
 336 
 337     if (i == 0) {
 338       start = addr - alignedAddress;
 339       len = vm_page_size - start;
 340     }
 341 
 342     if (i == (pageCount - 1)) {
 343       len = remaining;
 344     }
 345 
 346     if (mapped[i]) {
 347       print_debug("page %d mapped (len %ld start %ld)\n", i, len, start);
 348       (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
 349       vm_deallocate(mach_task_self(), pages[i], vm_page_size);
 350     }
 351 
 352     remaining -= len;
 353   }
 354 
 355   free (pages);
 356   free (mapped);
 357   return array;
 358 }
 359 
 360 /** Only used for core file reading, set thread_id for threads which is got after core file parsed.
 361   * Thread context is available in Mach-O core file but thread id is not. We can get thread id
 362   * from Threads which store all java threads information when they are created. Here we can identify
 363   * them as java threads by checking if a thread's rsp or rbp within a java thread's stack.
 364   * 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
 366   * integers to host all java threads' id, stack_start, stack_end as:
 367   * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...]
 368   *
 369   * 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
 371   */ 
 372 bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
 373   int n = 0, i = 0, j;
 374   struct reg regs;
 375   
 376   jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID);
 377   CHECK_EXCEPTION_(false);
 378   int len = (int)(*env)->GetArrayLength(env, thrinfos);
 379   uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL);
 380   CHECK_EXCEPTION_(false); 
 381   n = get_num_threads(ph);
 382   print_debug("fill_java_threads called, num_of_thread = %d\n", n);
 383   for (i = 0; i < n; i++) {
 384     if (!get_nth_lwp_regs(ph, i, &regs)) {
 385       print_debug("Could not get regs of thread %d, already set!\n", i);
 386       return false;
 387     }
 388     for (j = 0; j < len; j += 3) {
 389       lwpid_t  uid = cinfos[j];
 390       uint64_t beg = cinfos[j + 1];
 391       uint64_t end = cinfos[j + 2]; 
 392       if ((regs.r_rsp < end && regs.r_rsp >= beg) ||
 393           (regs.r_rbp < end && regs.r_rbp >= beg)) {
 394         set_lwp_id(ph, i, uid);
 395         break;
 396       }
 397     }
 398   }
 399   (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);
 400   CHECK_EXCEPTION_(false);
 401   return true;
 402 }
 403 
 404 /* For core file only, called from
 405  * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
 406  */
 407 jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {
 408   if (!_threads_filled)  {
 409     if (!fill_java_threads(env, this_obj, ph)) {
 410       throw_new_debugger_exception(env, "Failed to fill in threads");
 411       return 0;
 412     } else {
 413       _threads_filled = true;
 414     }
 415   }
 416 
 417   struct reg gregs;
 418   jboolean isCopy;
 419   jlongArray array;
 420   jlong *regs;
 421 
 422   if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
 423     THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
 424   }
 425 
 426 #undef NPRGREG
 427 #undef REG_INDEX
 428 #if amd64
 429 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
 430 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
 431 
 432   array = (*env)->NewLongArray(env, NPRGREG);
 433   CHECK_EXCEPTION_(0);
 434   regs = (*env)->GetLongArrayElements(env, array, &isCopy);
 435 
 436   regs[REG_INDEX(R15)] = gregs.r_r15;
 437   regs[REG_INDEX(R14)] = gregs.r_r14;
 438   regs[REG_INDEX(R13)] = gregs.r_r13;
 439   regs[REG_INDEX(R12)] = gregs.r_r12;
 440   regs[REG_INDEX(RBP)] = gregs.r_rbp;
 441   regs[REG_INDEX(RBX)] = gregs.r_rbx;
 442   regs[REG_INDEX(R11)] = gregs.r_r11;
 443   regs[REG_INDEX(R10)] = gregs.r_r10;
 444   regs[REG_INDEX(R9)]  = gregs.r_r9;
 445   regs[REG_INDEX(R8)]  = gregs.r_r8;
 446   regs[REG_INDEX(RAX)] = gregs.r_rax;
 447   regs[REG_INDEX(RCX)] = gregs.r_rcx;
 448   regs[REG_INDEX(RDX)] = gregs.r_rdx;
 449   regs[REG_INDEX(RSI)] = gregs.r_rsi;
 450   regs[REG_INDEX(RDI)] = gregs.r_rdi;
 451   regs[REG_INDEX(RIP)] = gregs.r_rip;
 452   regs[REG_INDEX(CS)]  = gregs.r_cs;
 453   regs[REG_INDEX(RSP)] = gregs.r_rsp;
 454   regs[REG_INDEX(SS)]  = gregs.r_ss;
 455   regs[REG_INDEX(FSBASE)] = 0;
 456   regs[REG_INDEX(GSBASE)] = 0;
 457   regs[REG_INDEX(DS)] = gregs.r_ds;
 458   regs[REG_INDEX(ES)] = gregs.r_es;
 459   regs[REG_INDEX(FS)] = gregs.r_fs;
 460   regs[REG_INDEX(GS)] = gregs.r_gs;
 461   regs[REG_INDEX(TRAPNO)] = gregs.r_trapno;
 462   regs[REG_INDEX(RFL)]    = gregs.r_rflags;
 463 
 464 #endif /* amd64 */
 465   (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
 466   return array;
 467 }
 468 
 469 /*
 470  * Lookup the thread_t that corresponds to the given thread_id.
 471  * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO
 472  * and reading the m_ident_info.thread_id returned.
 473  * The returned thread_t is the mach send right to the kernel port for the corresponding thread.
 474  *
 475  * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()
 476  * in the VM, but that thread port is not valid for a remote debugger to access the thread.
 477  */
 478 thread_t
 479 lookupThreadFromThreadId(task_t task, jlong thread_id) {
 480   print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
 481   
 482   thread_array_t thread_list = NULL;
 483   mach_msg_type_number_t thread_list_count = 0;
 484   thread_t result_thread = 0;
 485   int i;
 486   
 487   // get the list of all the send rights
 488   kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
 489   if (result != KERN_SUCCESS) {
 490     print_debug("task_threads returned 0x%x\n", result);
 491     return 0;
 492   }
 493   
 494   for(i = 0 ; i < thread_list_count; i++) {
 495     thread_identifier_info_data_t m_ident_info;
 496     mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
 497 
 498     // 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);
 500     if (result != KERN_SUCCESS) {
 501       print_debug("thread_info returned 0x%x\n", result);
 502       break;
 503     }
 504     
 505     // if this is the one we're looking for, return the send right
 506     if (thread_id == m_ident_info.thread_id)
 507     {
 508       result_thread = thread_list[i];
 509       break;
 510     }
 511   }
 512   
 513   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);
 515   
 516   return result_thread;
 517 }
 518 
 519 
 520 /*
 521  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 522  * Method:    getThreadIntegerRegisterSet0
 523  * Signature: (J)[J
 524  */
 525 JNIEXPORT jlongArray JNICALL 
 526 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
 527   JNIEnv *env, jobject this_obj, 
 528   jlong thread_id) 
 529 {
 530   print_debug("getThreadRegisterSet0 called\n");
 531 
 532   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
 533   if (ph != NULL && ph->core != NULL) {
 534     return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);
 535   }
 536 
 537   kern_return_t result;
 538   thread_t tid;
 539   mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
 540   hsdb_thread_state_t state;
 541   jlongArray registerArray;
 542   jlong *primitiveArray;
 543   task_t gTask = getTask(env, this_obj);
 544 
 545   tid = lookupThreadFromThreadId(gTask, thread_id);
 546 
 547   result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
 548 
 549   if (result != KERN_SUCCESS) {
 550     print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
 551     return NULL;
 552   }
 553 
 554 #if amd64
 555 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
 556 #undef REG_INDEX
 557 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
 558 
 559   // 64 bit
 560   print_debug("Getting threads for a 64-bit process\n");
 561   registerArray = (*env)->NewLongArray(env, NPRGREG);
 562   CHECK_EXCEPTION_(0);
 563   primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
 564 
 565   primitiveArray[REG_INDEX(R15)] = state.__r15;
 566   primitiveArray[REG_INDEX(R14)] = state.__r14;
 567   primitiveArray[REG_INDEX(R13)] = state.__r13;
 568   primitiveArray[REG_INDEX(R12)] = state.__r12;
 569   primitiveArray[REG_INDEX(R11)] = state.__r11;
 570   primitiveArray[REG_INDEX(R10)] = state.__r10;
 571   primitiveArray[REG_INDEX(R9)]  = state.__r9;
 572   primitiveArray[REG_INDEX(R8)]  = state.__r8;
 573   primitiveArray[REG_INDEX(RDI)] = state.__rdi;
 574   primitiveArray[REG_INDEX(RSI)] = state.__rsi;
 575   primitiveArray[REG_INDEX(RBP)] = state.__rbp;
 576   primitiveArray[REG_INDEX(RBX)] = state.__rbx;
 577   primitiveArray[REG_INDEX(RDX)] = state.__rdx;
 578   primitiveArray[REG_INDEX(RCX)] = state.__rcx;
 579   primitiveArray[REG_INDEX(RAX)] = state.__rax;
 580   primitiveArray[REG_INDEX(TRAPNO)] = 0;            // trapno, not used
 581   primitiveArray[REG_INDEX(ERR)]    = 0;            // err, not used 
 582   primitiveArray[REG_INDEX(RIP)] = state.__rip;
 583   primitiveArray[REG_INDEX(CS)]  = state.__cs;
 584   primitiveArray[REG_INDEX(RFL)] = state.__rflags;
 585   primitiveArray[REG_INDEX(RSP)] = state.__rsp;
 586   primitiveArray[REG_INDEX(SS)] = 0;                // We don't have SS
 587   primitiveArray[REG_INDEX(FS)] = state.__fs;
 588   primitiveArray[REG_INDEX(GS)] = state.__gs;
 589   primitiveArray[REG_INDEX(ES)] = 0;
 590   primitiveArray[REG_INDEX(DS)] = 0;
 591   primitiveArray[REG_INDEX(FSBASE)] = 0;
 592   primitiveArray[REG_INDEX(GSBASE)] = 0;
 593   print_debug("set registers\n");
 594 
 595   (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
 596 
 597 #else
 598 #error UNSUPPORTED_ARCH
 599 #endif /* amd64 */
 600 
 601   return registerArray;
 602 }
 603 
 604 /*
 605  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 606  * Method:    translateTID0
 607  * Signature: (I)I
 608  */
 609 JNIEXPORT jint JNICALL
 610 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
 611   JNIEnv *env, jobject this_obj, jint tid) 
 612 {
 613   print_debug("translateTID0 called on tid = 0x%x\n", (int)tid);
 614 
 615   kern_return_t result;
 616   thread_t foreign_tid, usable_tid;
 617   mach_msg_type_name_t type;
 618   
 619   foreign_tid = tid;
 620     
 621   task_t gTask = getTask(env, this_obj);
 622   result = mach_port_extract_right(gTask, foreign_tid, 
 623                                    MACH_MSG_TYPE_COPY_SEND, 
 624                                    &usable_tid, &type);
 625   if (result != KERN_SUCCESS)
 626     return -1;
 627     
 628   print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
 629     
 630   return (jint) usable_tid;
 631 }
 632 
 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"
 690 static bool ptrace_attach(pid_t pid) {
 691   int res;
 692   if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) {
 693     print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);
 694     return false;
 695   } else {
 696     return ptrace_waitpid(pid);
 697   }
 698 }
 699 
 700 /*
 701  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 702  * Method:    attach0
 703  * Signature: (I)V
 704  */
 705 JNIEXPORT void JNICALL
 706 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
 707   JNIEnv *env, jobject this_obj, jint jpid)
 708 {
 709   print_debug("attach0 called for jpid=%d\n", (int)jpid);
 710 
 711 JNF_COCOA_ENTER(env);
 712 
 713   kern_return_t result;
 714   task_t gTask = 0;
 715   result = task_for_pid(mach_task_self(), jpid, &gTask);
 716   if (result != KERN_SUCCESS) {
 717     print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
 718     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
 719   }
 720   putTask(env, this_obj, gTask);
 721 
 722   // use ptrace to stop the process
 723   // on os x, ptrace only needs to be called on the process, not the individual threads
 724   if (ptrace_attach(jpid) != true) {
 725     mach_port_deallocate(mach_task_self(), gTask);
 726     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
 727   }
 728 
 729   id symbolicator = nil;
 730   id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
 731   if (jrsSymbolicator != nil) {
 732     id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
 733     symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
 734   }
 735   if (symbolicator != nil) {
 736     CFRetain(symbolicator); // pin symbolicator while in java heap
 737   }
 738 
 739   putSymbolicator(env, this_obj, symbolicator);
 740   if (symbolicator == nil) {
 741     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
 742   }
 743 
 744 JNF_COCOA_EXIT(env);
 745 }
 746 
 747 /** For core file, 
 748     called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */
 749 static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
 750   int n = 0, i = 0;
 751 
 752   // add load objects
 753   n = get_num_libs(ph);
 754   for (i = 0; i < n; i++) {
 755      uintptr_t base;
 756      const char* name;
 757      jobject loadObject;
 758      jobject loadObjectList;
 759      jstring nameString;
 760 
 761      base = get_lib_base(ph, i);
 762      name = get_lib_name(ph, i);
 763      nameString = (*env)->NewStringUTF(env, name);
 764      CHECK_EXCEPTION;
 765      loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
 766                                             nameString, (jlong)0, (jlong)base);
 767      CHECK_EXCEPTION;
 768      loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
 769      CHECK_EXCEPTION;
 770      (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);
 771      CHECK_EXCEPTION;
 772   }
 773 }
 774 
 775 /*
 776  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 777  * Method:    attach0
 778  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
 779  */
 780 JNIEXPORT void JNICALL
 781 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(
 782   JNIEnv *env, jobject this_obj, jstring execName, jstring coreName)
 783 {
 784   const char *execName_cstr;
 785   const char *coreName_cstr;
 786   jboolean isCopy;
 787   struct ps_prochandle* ph;
 788 
 789   execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);
 790   CHECK_EXCEPTION;
 791   coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
 792   CHECK_EXCEPTION;
 793 
 794   print_debug("attach: %s %s\n", execName_cstr, coreName_cstr);
 795 
 796   if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
 797     (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
 798     (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
 799     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
 800   }
 801   (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
 802   (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
 803   (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
 804   fillLoadObjects(env, this_obj, ph);
 805 }
 806 
 807 /*
 808  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
 809  * Method:    detach0
 810  * Signature: ()V
 811  */
 812 JNIEXPORT void JNICALL
 813 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
 814   JNIEnv *env, jobject this_obj)
 815 {
 816   print_debug("detach0 called\n");
 817   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
 818   if (ph != NULL && ph->core != NULL) {
 819      Prelease(ph);
 820      return;
 821   }
 822 JNF_COCOA_ENTER(env);
 823   task_t gTask = getTask(env, this_obj);
 824 
 825   // detach from the ptraced process causing it to resume execution
 826   int pid;
 827   kern_return_t k_res;
 828   k_res = pid_for_task(gTask, &pid);
 829   if (k_res != KERN_SUCCESS) {
 830     print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
 831   }
 832   else {
 833     int res = ptrace(PT_DETACH, pid, 0, 0);
 834     if (res < 0) {
 835       print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
 836     }
 837   }
 838 
 839   mach_port_deallocate(mach_task_self(), gTask);
 840   id symbolicator = getSymbolicator(env, this_obj);
 841   if (symbolicator != nil) {
 842     CFRelease(symbolicator);
 843   }
 844 JNF_COCOA_EXIT(env);
 845 }