agent/src/os/bsd/MacosxDebuggerLocal.m

Fri, 15 Feb 2013 08:54:12 +0100

author
sla
date
Fri, 15 Feb 2013 08:54:12 +0100
changeset 4603
5d5c577296fd
parent 4564
758935f7c23f
child 4688
40b7c6b800ab
permissions
-rw-r--r--

8008102: SA on OS X does not stop the attached process
Reviewed-by: dholmes, rbackman

     1 /*
     2  * Copyright (c) 2002, 2012, 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  */
    25 #include <objc/objc-runtime.h>
    26 #import <Foundation/Foundation.h>
    27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
    29 #include <JavaVM/jni.h>
    31 #import <mach/mach.h>
    32 #import <mach/mach_types.h>
    33 #import <sys/sysctl.h>
    34 #import <stdio.h>
    35 #import <stdarg.h>
    36 #import <stdlib.h>
    37 #import <strings.h>
    38 #import <dlfcn.h>
    39 #import <limits.h>
    40 #import <errno.h>
    41 #import <sys/types.h>
    42 #import <sys/ptrace.h>
    44 jboolean debug = JNI_FALSE;
    46 static jfieldID symbolicatorID = 0; // set in _init0
    47 static jfieldID taskID = 0; // set in _init0
    49 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
    50   (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
    51 }
    53 static id getSymbolicator(JNIEnv *env, jobject this_obj) {
    54   jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
    55   return (id)(intptr_t)ptr;
    56 }
    58 static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
    59   (*env)->SetLongField(env, this_obj, taskID, (jlong)task);
    60 }
    62 static task_t getTask(JNIEnv *env, jobject this_obj) {
    63   jlong ptr = (*env)->GetLongField(env, this_obj, taskID);
    64   return (task_t)ptr;
    65 }
    67 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }
    68 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}
    69 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }
    70 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
    71 #define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); } 
    72 #define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; } 
    73 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } 
    75 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
    76   (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
    77 }
    79 #if defined(__i386__)
    80     #define hsdb_thread_state_t     x86_thread_state32_t
    81     #define hsdb_float_state_t      x86_float_state32_t
    82     #define HSDB_THREAD_STATE       x86_THREAD_STATE32
    83     #define HSDB_FLOAT_STATE        x86_FLOAT_STATE32
    84     #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
    85     #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE32_COUNT
    86 #elif defined(__x86_64__)
    87     #define hsdb_thread_state_t     x86_thread_state64_t
    88     #define hsdb_float_state_t      x86_float_state64_t
    89     #define HSDB_THREAD_STATE       x86_THREAD_STATE64
    90     #define HSDB_FLOAT_STATE        x86_FLOAT_STATE64
    91     #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
    92     #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE64_COUNT
    93 #else
    94     #error "Unsupported architecture"
    95 #endif
    97 /*
    98  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
    99  * Method:    init0
   100  * Signature: ()V
   101  */
   102 JNIEXPORT void JNICALL 
   103 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
   104   symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
   105   taskID = (*env)->GetFieldID(env, cls, "task", "J");
   106   CHECK_EXCEPTION;
   107 }
   109 /*
   110  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   111  * Method:    lookupByName0
   112  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
   113  */
   114 JNIEXPORT jlong JNICALL 
   115 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
   116   JNIEnv *env, jobject this_obj, 
   117   jstring objectName, jstring symbolName) 
   118 {
   119   jlong address = 0;
   121 JNF_COCOA_ENTER(env);
   122   NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
   124   if (debug) {
   125     printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
   126   }
   128   id symbolicator = getSymbolicator(env, this_obj);
   129   if (symbolicator != nil) {
   130     uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
   131     address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
   132   }
   134   if (debug) {
   135     printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
   136   }
   137 JNF_COCOA_EXIT(env);
   139   return address;
   140 }
   142 /*
   143  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   144  * Method:    readBytesFromProcess0
   145  * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
   146  */
   147 JNIEXPORT jbyteArray JNICALL
   148 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
   149   JNIEnv *env, jobject this_obj, 
   150   jlong addr, jlong numBytes) 
   151 {
   152   if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
   154   // must allocate storage instead of using former parameter buf
   155   jboolean isCopy;
   156   jbyteArray array;
   157   jbyte *bufPtr;
   159   array = (*env)->NewByteArray(env, numBytes);
   160   CHECK_EXCEPTION_(0);
   162   unsigned long alignedAddress;
   163   unsigned long alignedLength;
   164   kern_return_t result;
   165   vm_offset_t *pages;
   166   int *mapped;
   167   long pageCount;
   168   uint byteCount;
   169   int i;
   170   unsigned long remaining;
   172   alignedAddress = trunc_page(addr);
   173   if (addr != alignedAddress) {
   174     alignedLength += addr - alignedAddress;
   175   }
   176   alignedLength = round_page(numBytes);
   177   pageCount = alignedLength/vm_page_size;
   179   // Allocate storage for pages and flags.
   180   pages = malloc(pageCount * sizeof(vm_offset_t));
   181   mapped = calloc(pageCount, sizeof(int));
   183   task_t gTask = getTask(env, this_obj);
   184   // Try to read each of the pages.
   185   for (i = 0; i < pageCount; i++) {
   186     result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, 
   187 		     &pages[i], &byteCount);
   188     mapped[i] = (result == KERN_SUCCESS); 
   189     // assume all failures are unmapped pages
   190   }
   192   if (debug) fprintf(stderr, "%ld pages\n", pageCount);
   194   remaining = numBytes;
   196   for (i = 0; i < pageCount; i++) {
   197     unsigned long len = vm_page_size;
   198     unsigned long start = 0;
   200     if (i == 0) {
   201       start = addr - alignedAddress;
   202       len = vm_page_size - start;
   203     }
   205     if (i == (pageCount - 1)) {
   206       len = remaining;
   207     }
   209     if (mapped[i]) {
   210       if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start);
   211       (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
   212       vm_deallocate(mach_task_self(), pages[i], vm_page_size);
   213     }
   215     remaining -= len;
   216   }
   218   free (pages);
   219   free (mapped);
   220   return array;
   221 }
   224 /*
   225  * Lookup the thread_t that corresponds to the given thread_id.
   226  * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO
   227  * and reading the m_ident_info.thread_id returned.
   228  * The returned thread_t is the mach send right to the kernel port for the corresponding thread.
   229  *
   230  * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()
   231  * in the VM, but that thread port is not valid for a remote debugger to access the thread.
   232  */
   233 thread_t
   234 lookupThreadFromThreadId(task_t task, jlong thread_id) {
   235   if (debug) {
   236     printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
   237   }
   239   thread_array_t thread_list = NULL;
   240   mach_msg_type_number_t thread_list_count = 0;
   241   thread_t result_thread = 0;
   242   int i;
   244   // get the list of all the send rights
   245   kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
   246   if (result != KERN_SUCCESS) {
   247     if (debug) {
   248       printf("task_threads returned 0x%x\n", result);
   249     }
   250     return 0;
   251   }
   253   for(i = 0 ; i < thread_list_count; i++) {
   254     thread_identifier_info_data_t m_ident_info;
   255     mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
   257     // get the THREAD_IDENTIFIER_INFO for the send right
   258     result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
   259     if (result != KERN_SUCCESS) {
   260       if (debug) {
   261         printf("thread_info returned 0x%x\n", result);
   262       }
   263       break;
   264     }
   266     // if this is the one we're looking for, return the send right
   267     if (thread_id == m_ident_info.thread_id)
   268     {
   269       result_thread = thread_list[i];
   270       break;
   271     }
   272   }
   274   vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
   275   vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);
   277   return result_thread;
   278 }
   281 /*
   282  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   283  * Method:    getThreadIntegerRegisterSet0
   284  * Signature: (J)[J
   285  */
   286 JNIEXPORT jlongArray JNICALL 
   287 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
   288   JNIEnv *env, jobject this_obj, 
   289   jlong thread_id) 
   290 {
   291   if (debug)
   292     printf("getThreadRegisterSet0 called\n");
   294   kern_return_t result;
   295   thread_t tid;
   296   mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
   297   hsdb_thread_state_t state;
   298   unsigned int *r;
   299   int i;
   300   jlongArray registerArray;
   301   jlong *primitiveArray;
   302   task_t gTask = getTask(env, this_obj);
   304   tid = lookupThreadFromThreadId(gTask, thread_id);
   306   result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
   308   if (result != KERN_SUCCESS) {
   309     if (debug)
   310       printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
   311     return NULL;
   312   }
   314   // 40 32-bit registers on ppc, 16 on x86. 
   315   // Output order is the same as the order in the ppc_thread_state/i386_thread_state struct.
   316 #if defined(__i386__)
   317 	r = (unsigned int *)&state;
   318 	registerArray = (*env)->NewLongArray(env, 8);
   319 	primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
   320 	primitiveArray[0] = r[0];  // eax
   321 	primitiveArray[1] = r[2];  // ecx
   322 	primitiveArray[2] = r[3];  // edx
   323 	primitiveArray[3] = r[1];  // ebx
   324 	primitiveArray[4] = r[7];  // esp
   325 	primitiveArray[5] = r[6];  // ebp
   326 	primitiveArray[6] = r[5];  // esi
   327 	primitiveArray[7] = r[4];  // edi
   328 	(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
   329 #elif defined(__x86_64__)
   330 	/* From AMD64ThreadContext.java
   331 	   public static final int R15 = 0;
   332 	   public static final int R14 = 1;
   333 	   public static final int R13 = 2;
   334 	   public static final int R12 = 3;
   335 	   public static final int R11 = 4;
   336 	   public static final int R10 = 5;
   337 	   public static final int R9  = 6;
   338 	   public static final int R8  = 7;
   339 	   public static final int RDI = 8;
   340 	   public static final int RSI = 9;
   341 	   public static final int RBP = 10;
   342 	   public static final int RBX = 11;
   343 	   public static final int RDX = 12;
   344 	   public static final int RCX = 13;
   345 	   public static final int RAX = 14;
   346 	   public static final int TRAPNO = 15;
   347 	   public static final int ERR = 16;
   348 	   public static final int RIP = 17;
   349 	   public static final int CS = 18;
   350 	   public static final int RFL = 19;
   351 	   public static final int RSP = 20;
   352 	   public static final int SS = 21;
   353 	   public static final int FS = 22;
   354 	   public static final int GS = 23;
   355 	   public static final int ES = 24;
   356 	   public static final int DS = 25;
   357 	   public static final int FSBASE = 26;
   358 	   public static final int GSBASE = 27;
   359 	 */
   360 	// 64 bit
   361 	if (debug) printf("Getting threads for a 64-bit process\n");
   362 	registerArray = (*env)->NewLongArray(env, 28);
   363 	primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
   365 	primitiveArray[0] = state.__r15;
   366 	primitiveArray[1] = state.__r14;
   367 	primitiveArray[2] = state.__r13;
   368 	primitiveArray[3] = state.__r12;
   369 	primitiveArray[4] = state.__r11;
   370 	primitiveArray[5] = state.__r10;
   371 	primitiveArray[6] = state.__r9;
   372 	primitiveArray[7] = state.__r8;
   373 	primitiveArray[8] = state.__rdi;
   374 	primitiveArray[9] = state.__rsi;
   375 	primitiveArray[10] = state.__rbp;
   376 	primitiveArray[11] = state.__rbx;
   377 	primitiveArray[12] = state.__rdx;
   378 	primitiveArray[13] = state.__rcx;
   379 	primitiveArray[14] = state.__rax;
   380 	primitiveArray[15] = 0;             // trapno ?
   381 	primitiveArray[16] = 0;             // err ?
   382 	primitiveArray[17] = state.__rip;
   383 	primitiveArray[18] = state.__cs;
   384 	primitiveArray[19] = state.__rflags;
   385 	primitiveArray[20] = state.__rsp;
   386 	primitiveArray[21] = 0;            // We don't have SS
   387 	primitiveArray[22] = state.__fs;
   388 	primitiveArray[23] = state.__gs;
   389 	primitiveArray[24] = 0;
   390 	primitiveArray[25] = 0;
   391 	primitiveArray[26] = 0;
   392 	primitiveArray[27] = 0;
   394 	if (debug) printf("set registers\n");
   396 	(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
   397 #else
   398 #error Unsupported architecture
   399 #endif
   401   return registerArray;
   402 }
   404 /*
   405  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   406  * Method:    translateTID0
   407  * Signature: (I)I
   408  */
   409 JNIEXPORT jint JNICALL
   410 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
   411   JNIEnv *env, jobject this_obj, jint tid) 
   412 {
   413   if (debug)
   414     printf("translateTID0 called on tid = 0x%x\n", (int)tid);
   416   kern_return_t result;
   417   thread_t foreign_tid, usable_tid;
   418   mach_msg_type_name_t type;
   420   foreign_tid = tid;
   422   task_t gTask = getTask(env, this_obj);
   423   result = mach_port_extract_right(gTask, foreign_tid, 
   424 				   MACH_MSG_TYPE_COPY_SEND, 
   425 				   &usable_tid, &type);
   426   if (result != KERN_SUCCESS)
   427     return -1;
   429   if (debug)
   430     printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
   432   return (jint) usable_tid;
   433 }
   436 static bool ptrace_continue(pid_t pid, int signal) {
   437   // pass the signal to the process so we don't swallow it
   438   int res;
   439   if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) {
   440     fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);
   441     return false;
   442   }
   443   return true;
   444 }
   446 // waits until the ATTACH has stopped the process
   447 // by signal SIGSTOP
   448 static bool ptrace_waitpid(pid_t pid) {
   449   int ret;
   450   int status;
   451   while (true) {
   452     // Wait for debuggee to stop.
   453     ret = waitpid(pid, &status, 0);
   454     if (ret >= 0) {
   455       if (WIFSTOPPED(status)) {
   456         // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
   457         // will still be pending and delivered when the process is DETACHED and the process
   458         // will go to sleep.
   459         if (WSTOPSIG(status) == SIGSTOP) {
   460           // Debuggee stopped by SIGSTOP.
   461           return true;
   462         }
   463         if (!ptrace_continue(pid, WSTOPSIG(status))) {
   464           fprintf(stderr, "attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
   465           return false;
   466         }
   467       } else {
   468         fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
   469         return false;
   470       }
   471     } else {
   472       switch (errno) {
   473         case EINTR:
   474           continue;
   475           break;
   476         case ECHILD:
   477           fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);
   478           break;
   479         case EINVAL:
   480           fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n");
   481           break;
   482         default:
   483           fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno);
   484           break;
   485       }
   486       return false;
   487     }
   488   }
   489 }
   491 // attach to a process/thread specified by "pid"
   492 static bool ptrace_attach(pid_t pid) {
   493   int res;
   494   if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) {
   495     fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);
   496     return false;
   497   } else {
   498     return ptrace_waitpid(pid);
   499   }
   500 }
   502 /*
   503  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   504  * Method:    attach0
   505  * Signature: (I)V
   506  */
   507 JNIEXPORT void JNICALL 
   508 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
   509   JNIEnv *env, jobject this_obj, jint jpid) 
   510 {
   511 JNF_COCOA_ENTER(env);
   512   if (getenv("JAVA_SAPROC_DEBUG") != NULL)
   513     debug = JNI_TRUE;
   514   else
   515     debug = JNI_FALSE;
   516   if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
   518   // get the task from the pid
   519   kern_return_t result;
   520   task_t gTask = 0;
   521   result = task_for_pid(mach_task_self(), jpid, &gTask);
   522   if (result != KERN_SUCCESS) {
   523     fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
   524     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
   525   }
   526   putTask(env, this_obj, gTask);
   528   // use ptrace to stop the process
   529   // on os x, ptrace only needs to be called on the process, not the individual threads
   530   if (ptrace_attach(jpid) != true) {
   531     mach_port_deallocate(mach_task_self(), gTask);
   532     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
   533   }
   535   id symbolicator = nil;
   536   id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
   537   if (jrsSymbolicator != nil) {
   538     id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
   539     symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
   540   }
   541   if (symbolicator != nil) {
   542     CFRetain(symbolicator); // pin symbolicator while in java heap
   543   }
   545   putSymbolicator(env, this_obj, symbolicator);
   546   if (symbolicator == nil) {
   547     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
   548   }
   550 JNF_COCOA_EXIT(env);
   551 }
   553 /*
   554  * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
   555  * Method:    detach0
   556  * Signature: ()V
   557  */
   558 JNIEXPORT void JNICALL 
   559 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
   560   JNIEnv *env, jobject this_obj) 
   561 {
   562 JNF_COCOA_ENTER(env);
   563   if (debug) printf("detach0 called\n");
   565   task_t gTask = getTask(env, this_obj);
   567   // detach from the ptraced process causing it to resume execution
   568   int pid;
   569   kern_return_t k_res;
   570   k_res = pid_for_task(gTask, &pid);
   571   if (k_res != KERN_SUCCESS) {
   572     fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
   573   }
   574   else {
   575     int res = ptrace(PT_DETACH, pid, 0, 0);
   576     if (res < 0) {
   577       fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
   578     }
   579   }
   581   mach_port_deallocate(mach_task_self(), gTask);
   582   id symbolicator = getSymbolicator(env, this_obj);
   583   if (symbolicator != nil) {
   584     CFRelease(symbolicator);
   585   }
   586 JNF_COCOA_EXIT(env);
   587 }
   589 /*
   590  * Class:     sun_jvm_hotspot_asm_Disassembler
   591  * Method:    load_library
   592  * Signature: (Ljava/lang/String;)L
   593  */
   594 JNIEXPORT jlong JNICALL
   595 Java_sun_jvm_hotspot_asm_Disassembler_load_1library(
   596   JNIEnv * env, 
   597   jclass disclass,
   598   jstring jrepath_s,
   599   jstring libname_s) 
   600 {
   601   uintptr_t func = 0;
   602   const char* error_message = NULL;
   603   const char* java_home;
   604   jboolean isCopy;
   605   uintptr_t *handle = NULL;
   607   const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/
   608   const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy);
   609   char buffer[128];
   611   /* Load the hsdis library */
   612   void* hsdis_handle;
   613   hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
   614   if (hsdis_handle == NULL) {
   615     snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);
   616     hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL);
   617   }
   618   if (hsdis_handle != NULL) {
   619     func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual");
   620   }
   621   if (func == 0) {
   622     error_message = dlerror();
   623     fprintf(stderr, "%s\n", error_message);
   624   }
   626   (*env)->ReleaseStringUTFChars(env, libname_s, libname);
   627   (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath);
   629   if (func == 0) {
   630     /* Couldn't find entry point.  error_message should contain some
   631      * platform dependent error message.
   632      */
   633     THROW_NEW_DEBUGGER_EXCEPTION(error_message);
   634   }
   635   return (jlong)func;
   636 }
   638 /* signature of decode_instructions_virtual from hsdis.h */
   639 typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,
   640                              unsigned char* start, uintptr_t length,
   641                              void* (*event_callback)(void*, const char*, void*),
   642                              void* event_stream,
   643                              int (*printf_callback)(void*, const char*, ...),
   644                              void* printf_stream,
   645                              const char* options);
   647 /* container for call back state when decoding instructions */
   648 typedef struct {
   649   JNIEnv* env;
   650   jobject dis;
   651   jobject visitor;
   652   jmethodID handle_event;
   653   jmethodID raw_print;
   654   char buffer[4096];
   655 } decode_env;
   658 /* event callback binding to Disassembler.handleEvent */
   659 static void* event_to_env(void* env_pv, const char* event, void* arg) {
   660   decode_env* denv = (decode_env*)env_pv;
   661   JNIEnv* env = denv->env;
   662   jstring event_string = (*env)->NewStringUTF(env, event);
   663   jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor,
   664                                         event_string, (jlong) (uintptr_t)arg);
   665   /* ignore exceptions for now */
   666   CHECK_EXCEPTION_CLEAR_((void *)0);
   667   return (void*)(uintptr_t)result;
   668 }
   670 /* printing callback binding to Disassembler.rawPrint */
   671 static int printf_to_env(void* env_pv, const char* format, ...) {
   672   jstring output;
   673   va_list ap;
   674   int cnt;
   675   decode_env* denv = (decode_env*)env_pv;
   676   JNIEnv* env = denv->env;
   677   size_t flen = strlen(format);
   678   const char* raw = NULL;
   680   if (flen == 0)  return 0;
   681   if (flen < 2 ||
   682       strchr(format, '%') == NULL) {
   683     raw = format;
   684   } else if (format[0] == '%' && format[1] == '%' &&
   685              strchr(format+2, '%') == NULL) {
   686     // happens a lot on machines with names like %foo
   687     flen--;
   688     raw = format+1;
   689   }
   690   if (raw != NULL) {
   691     jstring output = (*env)->NewStringUTF(env, raw);
   692     (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
   693     CHECK_EXCEPTION_CLEAR;
   694     return (int) flen;
   695   }
   696   va_start(ap, format);
   697   cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap);
   698   va_end(ap);
   700   output = (*env)->NewStringUTF(env, denv->buffer);
   701   (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
   702   CHECK_EXCEPTION_CLEAR;
   703   return cnt;
   704 }
   706 /*
   707  * Class:     sun_jvm_hotspot_asm_Disassembler
   708  * Method:    decode
   709  * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V
   710  */
   711 JNIEXPORT void JNICALL
   712 Java_sun_jvm_hotspot_asm_Disassembler_decode(
   713    JNIEnv * env,
   714    jobject dis,
   715    jobject visitor,
   716    jlong startPc,
   717    jbyteArray code,
   718    jstring options_s,
   719    jlong decode_instructions_virtual) 
   720 {
   721   jboolean isCopy;
   722   jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy);
   723   jbyte* end = start + (*env)->GetArrayLength(env, code);
   724   const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy);
   725   jclass disclass = (*env)->GetObjectClass(env, dis);
   727   decode_env denv;
   728   denv.env = env;
   729   denv.dis = dis;
   730   denv.visitor = visitor;
   732   /* find Disassembler.handleEvent callback */
   733   denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent",
   734                                           "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J");
   735   CHECK_EXCEPTION_CLEAR_VOID
   737   /* find Disassembler.rawPrint callback */
   738   denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint",
   739                                        "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V");
   740   CHECK_EXCEPTION_CLEAR_VOID
   742   /* decode the buffer */
   743   (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc,
   744                                                          startPc + end - start,
   745                                                          (unsigned char*)start,
   746                                                          end - start,
   747                                                          &event_to_env,  (void*) &denv,
   748                                                          &printf_to_env, (void*) &denv,
   749                                                          options);
   751   /* cleanup */
   752   (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
   753   (*env)->ReleaseStringUTFChars(env, options_s, options);
   754 }

mercurial