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