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

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

mercurial