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 #import <sys/types.h> 42 #import <sys/ptrace.h> 43 44 jboolean debug = JNI_FALSE; 45 46 static jfieldID symbolicatorID = 0; // set in _init0 47 static jfieldID taskID = 0; // set in _init0 48 49 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { 50 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); 51 } 52 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 } 57 58 static void putTask(JNIEnv *env, jobject this_obj, task_t task) { 59 (*env)->SetLongField(env, this_obj, taskID, (jlong)task); 60 } 61 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 } 66 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; } 74 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 } 78 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 96 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 } 108 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; 120 121 JNF_COCOA_ENTER(env); 122 NSString *symbolNameString = JNFJavaToNSString(env, symbolName); 123 124 if (debug) { 125 printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]); 126 } 127 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 } 133 134 if (debug) { 135 printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); 136 } 137 JNF_COCOA_EXIT(env); 138 139 return address; 140 } 141 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); 153 154 // must allocate storage instead of using former parameter buf 155 jboolean isCopy; 156 jbyteArray array; 157 jbyte *bufPtr; 158 159 array = (*env)->NewByteArray(env, numBytes); 160 CHECK_EXCEPTION_(0); 161 162 unsigned long alignedAddress; 163 unsigned long alignedLength = 0; 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; 171 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; 178 179 // Allocate storage for pages and flags. 180 pages = malloc(pageCount * sizeof(vm_offset_t)); 181 mapped = calloc(pageCount, sizeof(int)); 182 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 } 191 192 if (debug) fprintf(stderr, "%ld pages\n", pageCount); 193 194 remaining = numBytes; 195 196 for (i = 0; i < pageCount; i++) { 197 unsigned long len = vm_page_size; 198 unsigned long start = 0; 199 200 if (i == 0) { 201 start = addr - alignedAddress; 202 len = vm_page_size - start; 203 } 204 205 if (i == (pageCount - 1)) { 206 len = remaining; 207 } 208 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 } 214 215 remaining -= len; 216 } 217 218 free (pages); 219 free (mapped); 220 return array; 221 } 222 223 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 } 238 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; 243 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 } 252 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; 256 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 } 265 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 } 273 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); 276 277 return result_thread; 278 } 279 280 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"); 293 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); 303 304 tid = lookupThreadFromThreadId(gTask, thread_id); 305 306 result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); 307 308 if (result != KERN_SUCCESS) { 309 if (debug) 310 printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result); 311 return NULL; 312 } 313 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); 364 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; 393 394 if (debug) printf("set registers\n"); 395 396 (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); 397 #else 398 #error Unsupported architecture 399 #endif 400 401 return registerArray; 402 } 403 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); 415 416 kern_return_t result; 417 thread_t foreign_tid, usable_tid; 418 mach_msg_type_name_t type; 419 420 foreign_tid = tid; 421 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; 428 429 if (debug) 430 printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); 431 432 return (jint) usable_tid; 433 } 434 435 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 } 445 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 } 490 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 } 501 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); 517 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); 527 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 } 534 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 } 544 545 putSymbolicator(env, this_obj, symbolicator); 546 if (symbolicator == nil) { 547 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process"); 548 } 549 550 JNF_COCOA_EXIT(env); 551 } 552 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"); 564 565 task_t gTask = getTask(env, this_obj); 566 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 } 580 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 } 588 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; 606 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]; 610 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 } 625 626 (*env)->ReleaseStringUTFChars(env, libname_s, libname); 627 (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath); 628 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, (jlong)func); 634 } 635 return (jlong)func; 636 } 637 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); 646 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; 656 657 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 } 669 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; 679 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); 699 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 } 705 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); 726 727 decode_env denv; 728 denv.env = env; 729 denv.dis = dis; 730 denv.visitor = visitor; 731 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 736 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 741 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); 750 751 /* cleanup */ 752 (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); 753 (*env)->ReleaseStringUTFChars(env, options_s, options); 754 }