Mercurial > hg > truffle
comparison agent/src/os/bsd/MacosxDebuggerLocal.m @ 8750:39432a1cefdd
8003348: SA can not read core file on OS
Summary: Macosx uses Mach-O file format for binary files, not ELF format. Currently SA works on core files on other platforms, t his change enables SA work on core file generated on Darwin.
Reviewed-by: sla, sspitsyn
Contributed-by: yumin.qi@oracle.com
author | minqi |
---|---|
date | Thu, 14 Mar 2013 00:33:08 -0700 |
parents | 40b7c6b800ab |
children | 9f96b7a853bc |
comparison
equal
deleted
inserted
replaced
8719:c8b31b461e1a | 8750:39432a1cefdd |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 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 | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
38 #import <dlfcn.h> | 38 #import <dlfcn.h> |
39 #import <limits.h> | 39 #import <limits.h> |
40 #import <errno.h> | 40 #import <errno.h> |
41 #import <sys/types.h> | 41 #import <sys/types.h> |
42 #import <sys/ptrace.h> | 42 #import <sys/ptrace.h> |
43 | 43 #include "libproc_impl.h" |
44 jboolean debug = JNI_FALSE; | 44 |
45 #define UNSUPPORTED_ARCH "Unsupported architecture!" | |
46 | |
47 #if defined(x86_64) && !defined(amd64) | |
48 #define amd64 1 | |
49 #endif | |
50 | |
51 #if amd64 | |
52 #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" | |
53 #else | |
54 #error UNSUPPORTED_ARCH | |
55 #endif | |
45 | 56 |
46 static jfieldID symbolicatorID = 0; // set in _init0 | 57 static jfieldID symbolicatorID = 0; // set in _init0 |
47 static jfieldID taskID = 0; // set in _init0 | 58 static jfieldID taskID = 0; // set in _init0 |
59 | |
60 static jfieldID p_ps_prochandle_ID = 0; | |
61 static jfieldID loadObjectList_ID = 0; | |
62 static jmethodID listAdd_ID = 0; | |
63 | |
64 static jmethodID createClosestSymbol_ID = 0; | |
65 static jmethodID createLoadObject_ID = 0; | |
66 static jmethodID getJavaThreadsInfo_ID = 0; | |
67 | |
68 // indicator if thread id (lwpid_t) was set | |
69 static bool _threads_filled = false; | |
48 | 70 |
49 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { | 71 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { |
50 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); | 72 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); |
51 } | 73 } |
52 | 74 |
72 #define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; } | 94 #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; } | 95 #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } |
74 | 96 |
75 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { | 97 static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { |
76 (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); | 98 (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); |
99 } | |
100 | |
101 static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { | |
102 jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID); | |
103 return (struct ps_prochandle*)(intptr_t)ptr; | |
77 } | 104 } |
78 | 105 |
79 #if defined(__i386__) | 106 #if defined(__i386__) |
80 #define hsdb_thread_state_t x86_thread_state32_t | 107 #define hsdb_thread_state_t x86_thread_state32_t |
81 #define hsdb_float_state_t x86_float_state32_t | 108 #define hsdb_float_state_t x86_float_state32_t |
89 #define HSDB_THREAD_STATE x86_THREAD_STATE64 | 116 #define HSDB_THREAD_STATE x86_THREAD_STATE64 |
90 #define HSDB_FLOAT_STATE x86_FLOAT_STATE64 | 117 #define HSDB_FLOAT_STATE x86_FLOAT_STATE64 |
91 #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT | 118 #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT |
92 #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT | 119 #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT |
93 #else | 120 #else |
94 #error "Unsupported architecture" | 121 #error UNSUPPORTED_ARCH |
95 #endif | 122 #endif |
96 | 123 |
97 /* | 124 /* |
98 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | 125 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
99 * Method: init0 | 126 * Method: init0 |
102 JNIEXPORT void JNICALL | 129 JNIEXPORT void JNICALL |
103 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { | 130 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { |
104 symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); | 131 symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); |
105 taskID = (*env)->GetFieldID(env, cls, "task", "J"); | 132 taskID = (*env)->GetFieldID(env, cls, "task", "J"); |
106 CHECK_EXCEPTION; | 133 CHECK_EXCEPTION; |
134 | |
135 // for core file | |
136 p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); | |
137 CHECK_EXCEPTION; | |
138 loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); | |
139 CHECK_EXCEPTION; | |
140 | |
141 // methods we use | |
142 createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", | |
143 "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); | |
144 CHECK_EXCEPTION; | |
145 createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", | |
146 "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); | |
147 CHECK_EXCEPTION; | |
148 | |
149 // java.util.List method we call | |
150 jclass listClass = (*env)->FindClass(env, "java/util/List"); | |
151 CHECK_EXCEPTION; | |
152 listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); | |
153 CHECK_EXCEPTION; | |
154 getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo", | |
155 "()[J"); | |
156 CHECK_EXCEPTION; | |
157 | |
158 init_libproc(getenv("LIBSAPROC_DEBUG") != NULL); | |
159 } | |
160 | |
161 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize | |
162 (JNIEnv *env, jclass cls) | |
163 { | |
164 #ifdef _LP64 | |
165 return 8; | |
166 #else | |
167 #error UNSUPPORTED_ARCH | |
168 #endif | |
169 } | |
170 | |
171 /** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */ | |
172 jlong lookupByNameIncore( | |
173 JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName) | |
174 { | |
175 const char *objectName_cstr, *symbolName_cstr; | |
176 jlong addr; | |
177 jboolean isCopy; | |
178 objectName_cstr = NULL; | |
179 if (objectName != NULL) { | |
180 objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy); | |
181 CHECK_EXCEPTION_(0); | |
182 } | |
183 symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy); | |
184 CHECK_EXCEPTION_(0); | |
185 | |
186 print_debug("look for %s \n", symbolName_cstr); | |
187 addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr); | |
188 | |
189 if (objectName_cstr != NULL) { | |
190 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); | |
191 } | |
192 (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr); | |
193 return addr; | |
107 } | 194 } |
108 | 195 |
109 /* | 196 /* |
110 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | 197 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
111 * Method: lookupByName0 | 198 * Method: lookupByName0 |
114 JNIEXPORT jlong JNICALL | 201 JNIEXPORT jlong JNICALL |
115 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( | 202 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( |
116 JNIEnv *env, jobject this_obj, | 203 JNIEnv *env, jobject this_obj, |
117 jstring objectName, jstring symbolName) | 204 jstring objectName, jstring symbolName) |
118 { | 205 { |
206 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
207 if (ph->core != NULL) { | |
208 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); | |
209 } | |
210 | |
119 jlong address = 0; | 211 jlong address = 0; |
120 | 212 |
121 JNF_COCOA_ENTER(env); | 213 JNF_COCOA_ENTER(env); |
122 NSString *symbolNameString = JNFJavaToNSString(env, symbolName); | 214 NSString *symbolNameString = JNFJavaToNSString(env, symbolName); |
123 | 215 |
124 if (debug) { | 216 print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]); |
125 printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]); | |
126 } | |
127 | 217 |
128 id symbolicator = getSymbolicator(env, this_obj); | 218 id symbolicator = getSymbolicator(env, this_obj); |
129 if (symbolicator != nil) { | 219 if (symbolicator != nil) { |
130 uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend; | 220 uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend; |
131 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); | 221 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); |
132 } | 222 } |
133 | 223 |
134 if (debug) { | 224 print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); |
135 printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); | |
136 } | |
137 JNF_COCOA_EXIT(env); | 225 JNF_COCOA_EXIT(env); |
138 | 226 |
139 return address; | 227 return address; |
228 } | |
229 | |
230 /* | |
231 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | |
232 * Method: lookupByAddress0 | |
233 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; | |
234 */ | |
235 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0 | |
236 (JNIEnv *env, jobject this_obj, jlong addr) { | |
237 uintptr_t offset; | |
238 const char* sym = NULL; | |
239 | |
240 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
241 sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); | |
242 if (sym == NULL) return 0; | |
243 return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, | |
244 (*env)->NewStringUTF(env, sym), (jlong)offset); | |
245 } | |
246 | |
247 /** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */ | |
248 jbyteArray readBytesFromCore( | |
249 JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes) | |
250 { | |
251 jboolean isCopy; | |
252 jbyteArray array; | |
253 jbyte *bufPtr; | |
254 ps_err_e err; | |
255 | |
256 array = (*env)->NewByteArray(env, numBytes); | |
257 CHECK_EXCEPTION_(0); | |
258 bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); | |
259 CHECK_EXCEPTION_(0); | |
260 | |
261 err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); | |
262 (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); | |
263 return (err == PS_OK)? array : 0; | |
140 } | 264 } |
141 | 265 |
142 /* | 266 /* |
143 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | 267 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
144 * Method: readBytesFromProcess0 | 268 * Method: readBytesFromProcess0 |
147 JNIEXPORT jbyteArray JNICALL | 271 JNIEXPORT jbyteArray JNICALL |
148 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( | 272 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( |
149 JNIEnv *env, jobject this_obj, | 273 JNIEnv *env, jobject this_obj, |
150 jlong addr, jlong numBytes) | 274 jlong addr, jlong numBytes) |
151 { | 275 { |
152 if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); | 276 print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); |
153 | 277 |
154 // must allocate storage instead of using former parameter buf | 278 // must allocate storage instead of using former parameter buf |
155 jboolean isCopy; | |
156 jbyteArray array; | 279 jbyteArray array; |
157 jbyte *bufPtr; | 280 |
281 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
282 if (ph->core != NULL) { | |
283 return readBytesFromCore(env, ph, this_obj, addr, numBytes); | |
284 } | |
158 | 285 |
159 array = (*env)->NewByteArray(env, numBytes); | 286 array = (*env)->NewByteArray(env, numBytes); |
160 CHECK_EXCEPTION_(0); | 287 CHECK_EXCEPTION_(0); |
161 | 288 |
162 unsigned long alignedAddress; | 289 unsigned long alignedAddress; |
187 &pages[i], &byteCount); | 314 &pages[i], &byteCount); |
188 mapped[i] = (result == KERN_SUCCESS); | 315 mapped[i] = (result == KERN_SUCCESS); |
189 // assume all failures are unmapped pages | 316 // assume all failures are unmapped pages |
190 } | 317 } |
191 | 318 |
192 if (debug) fprintf(stderr, "%ld pages\n", pageCount); | 319 print_debug("%ld pages\n", pageCount); |
193 | 320 |
194 remaining = numBytes; | 321 remaining = numBytes; |
195 | 322 |
196 for (i = 0; i < pageCount; i++) { | 323 for (i = 0; i < pageCount; i++) { |
197 unsigned long len = vm_page_size; | 324 unsigned long len = vm_page_size; |
205 if (i == (pageCount - 1)) { | 332 if (i == (pageCount - 1)) { |
206 len = remaining; | 333 len = remaining; |
207 } | 334 } |
208 | 335 |
209 if (mapped[i]) { | 336 if (mapped[i]) { |
210 if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start); | 337 print_debug("page %d mapped (len %ld start %ld)\n", i, len, start); |
211 (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start)); | 338 (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start)); |
212 vm_deallocate(mach_task_self(), pages[i], vm_page_size); | 339 vm_deallocate(mach_task_self(), pages[i], vm_page_size); |
213 } | 340 } |
214 | 341 |
215 remaining -= len; | 342 remaining -= len; |
218 free (pages); | 345 free (pages); |
219 free (mapped); | 346 free (mapped); |
220 return array; | 347 return array; |
221 } | 348 } |
222 | 349 |
350 /** Only used for core file reading, set thread_id for threads which is got after core file parsed. | |
351 * Thread context is available in Mach-O core file but thread id is not. We can get thread id | |
352 * from Threads which store all java threads information when they are created. Here we can identify | |
353 * them as java threads by checking if a thread's rsp or rbp within a java thread's stack. | |
354 * Note Macosx uses unique_thread_id which is different from other platforms though printed ids | |
355 * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long | |
356 * integers to host all java threads' id, stack_start, stack_end as: | |
357 * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] | |
358 * | |
359 * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). | |
360 * This function should be called only once if succeeded | |
361 */ | |
362 bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { | |
363 int n = 0, i = 0, j; | |
364 struct reg regs; | |
365 | |
366 jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); | |
367 CHECK_EXCEPTION_(false); | |
368 int len = (int)(*env)->GetArrayLength(env, thrinfos); | |
369 uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); | |
370 CHECK_EXCEPTION_(false); | |
371 n = get_num_threads(ph); | |
372 print_debug("fill_java_threads called, num_of_thread = %d\n", n); | |
373 for (i = 0; i < n; i++) { | |
374 if (!get_nth_lwp_regs(ph, i, ®s)) { | |
375 print_debug("Could not get regs of thread %d, already set!\n", i); | |
376 return false; | |
377 } | |
378 for (j = 0; j < len; j += 3) { | |
379 lwpid_t uid = cinfos[j]; | |
380 uint64_t beg = cinfos[j + 1]; | |
381 uint64_t end = cinfos[j + 2]; | |
382 if ((regs.r_rsp < end && regs.r_rsp >= beg) || | |
383 (regs.r_rbp < end && regs.r_rbp >= beg)) { | |
384 set_lwp_id(ph, i, uid); | |
385 break; | |
386 } | |
387 } | |
388 } | |
389 (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0); | |
390 CHECK_EXCEPTION_(false); | |
391 return true; | |
392 } | |
393 | |
394 /* For core file only, called from | |
395 * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0 | |
396 */ | |
397 jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) { | |
398 if (!_threads_filled) { | |
399 if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) { | |
400 throw_new_debugger_exception(env, "Failed to fill in threads"); | |
401 return 0; | |
402 } else { | |
403 _threads_filled = true; | |
404 } | |
405 } | |
406 | |
407 struct reg gregs; | |
408 jboolean isCopy; | |
409 jlongArray array; | |
410 jlong *regs; | |
411 | |
412 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
413 if (get_lwp_regs(ph, lwp_id, &gregs) != true) { | |
414 THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0); | |
415 } | |
416 | |
417 #undef NPRGREG | |
418 #undef REG_INDEX | |
419 #if amd64 | |
420 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG | |
421 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg | |
422 | |
423 array = (*env)->NewLongArray(env, NPRGREG); | |
424 CHECK_EXCEPTION_(0); | |
425 regs = (*env)->GetLongArrayElements(env, array, &isCopy); | |
426 | |
427 regs[REG_INDEX(R15)] = gregs.r_r15; | |
428 regs[REG_INDEX(R14)] = gregs.r_r14; | |
429 regs[REG_INDEX(R13)] = gregs.r_r13; | |
430 regs[REG_INDEX(R12)] = gregs.r_r12; | |
431 regs[REG_INDEX(RBP)] = gregs.r_rbp; | |
432 regs[REG_INDEX(RBX)] = gregs.r_rbx; | |
433 regs[REG_INDEX(R11)] = gregs.r_r11; | |
434 regs[REG_INDEX(R10)] = gregs.r_r10; | |
435 regs[REG_INDEX(R9)] = gregs.r_r9; | |
436 regs[REG_INDEX(R8)] = gregs.r_r8; | |
437 regs[REG_INDEX(RAX)] = gregs.r_rax; | |
438 regs[REG_INDEX(RCX)] = gregs.r_rcx; | |
439 regs[REG_INDEX(RDX)] = gregs.r_rdx; | |
440 regs[REG_INDEX(RSI)] = gregs.r_rsi; | |
441 regs[REG_INDEX(RDI)] = gregs.r_rdi; | |
442 regs[REG_INDEX(RIP)] = gregs.r_rip; | |
443 regs[REG_INDEX(CS)] = gregs.r_cs; | |
444 regs[REG_INDEX(RSP)] = gregs.r_rsp; | |
445 regs[REG_INDEX(SS)] = gregs.r_ss; | |
446 regs[REG_INDEX(FSBASE)] = 0; | |
447 regs[REG_INDEX(GSBASE)] = 0; | |
448 regs[REG_INDEX(DS)] = gregs.r_ds; | |
449 regs[REG_INDEX(ES)] = gregs.r_es; | |
450 regs[REG_INDEX(FS)] = gregs.r_fs; | |
451 regs[REG_INDEX(GS)] = gregs.r_gs; | |
452 regs[REG_INDEX(TRAPNO)] = gregs.r_trapno; | |
453 regs[REG_INDEX(RFL)] = gregs.r_rflags; | |
454 | |
455 #endif /* amd64 */ | |
456 (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); | |
457 return array; | |
458 } | |
223 | 459 |
224 /* | 460 /* |
225 * Lookup the thread_t that corresponds to the given thread_id. | 461 * 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 | 462 * 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. | 463 * and reading the m_ident_info.thread_id returned. |
230 * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self() | 466 * 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. | 467 * in the VM, but that thread port is not valid for a remote debugger to access the thread. |
232 */ | 468 */ |
233 thread_t | 469 thread_t |
234 lookupThreadFromThreadId(task_t task, jlong thread_id) { | 470 lookupThreadFromThreadId(task_t task, jlong thread_id) { |
235 if (debug) { | 471 print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); |
236 printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); | |
237 } | |
238 | 472 |
239 thread_array_t thread_list = NULL; | 473 thread_array_t thread_list = NULL; |
240 mach_msg_type_number_t thread_list_count = 0; | 474 mach_msg_type_number_t thread_list_count = 0; |
241 thread_t result_thread = 0; | 475 thread_t result_thread = 0; |
242 int i; | 476 int i; |
243 | 477 |
244 // get the list of all the send rights | 478 // get the list of all the send rights |
245 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); | 479 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); |
246 if (result != KERN_SUCCESS) { | 480 if (result != KERN_SUCCESS) { |
247 if (debug) { | 481 print_debug("task_threads returned 0x%x\n", result); |
248 printf("task_threads returned 0x%x\n", result); | |
249 } | |
250 return 0; | 482 return 0; |
251 } | 483 } |
252 | 484 |
253 for(i = 0 ; i < thread_list_count; i++) { | 485 for(i = 0 ; i < thread_list_count; i++) { |
254 thread_identifier_info_data_t m_ident_info; | 486 thread_identifier_info_data_t m_ident_info; |
255 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; | 487 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; |
256 | 488 |
257 // get the THREAD_IDENTIFIER_INFO for the send right | 489 // 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); | 490 result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); |
259 if (result != KERN_SUCCESS) { | 491 if (result != KERN_SUCCESS) { |
260 if (debug) { | 492 print_debug("thread_info returned 0x%x\n", result); |
261 printf("thread_info returned 0x%x\n", result); | |
262 } | |
263 break; | 493 break; |
264 } | 494 } |
265 | 495 |
266 // if this is the one we're looking for, return the send right | 496 // if this is the one we're looking for, return the send right |
267 if (thread_id == m_ident_info.thread_id) | 497 if (thread_id == m_ident_info.thread_id) |
286 JNIEXPORT jlongArray JNICALL | 516 JNIEXPORT jlongArray JNICALL |
287 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( | 517 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( |
288 JNIEnv *env, jobject this_obj, | 518 JNIEnv *env, jobject this_obj, |
289 jlong thread_id) | 519 jlong thread_id) |
290 { | 520 { |
291 if (debug) | 521 print_debug("getThreadRegisterSet0 called\n"); |
292 printf("getThreadRegisterSet0 called\n"); | 522 |
523 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
524 if (ph->core != NULL) { | |
525 return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id); | |
526 } | |
293 | 527 |
294 kern_return_t result; | 528 kern_return_t result; |
295 thread_t tid; | 529 thread_t tid; |
296 mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT; | 530 mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT; |
297 hsdb_thread_state_t state; | 531 hsdb_thread_state_t state; |
298 unsigned int *r; | |
299 int i; | |
300 jlongArray registerArray; | 532 jlongArray registerArray; |
301 jlong *primitiveArray; | 533 jlong *primitiveArray; |
302 task_t gTask = getTask(env, this_obj); | 534 task_t gTask = getTask(env, this_obj); |
303 | 535 |
304 tid = lookupThreadFromThreadId(gTask, thread_id); | 536 tid = lookupThreadFromThreadId(gTask, thread_id); |
305 | 537 |
306 result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); | 538 result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); |
307 | 539 |
308 if (result != KERN_SUCCESS) { | 540 if (result != KERN_SUCCESS) { |
309 if (debug) | 541 print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result); |
310 printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result); | |
311 return NULL; | 542 return NULL; |
312 } | 543 } |
313 | 544 |
314 // 40 32-bit registers on ppc, 16 on x86. | 545 #if amd64 |
315 // Output order is the same as the order in the ppc_thread_state/i386_thread_state struct. | 546 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG |
316 #if defined(__i386__) | 547 #undef REG_INDEX |
317 r = (unsigned int *)&state; | 548 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg |
318 registerArray = (*env)->NewLongArray(env, 8); | 549 |
319 primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); | 550 // 64 bit |
320 primitiveArray[0] = r[0]; // eax | 551 print_debug("Getting threads for a 64-bit process\n"); |
321 primitiveArray[1] = r[2]; // ecx | 552 registerArray = (*env)->NewLongArray(env, NPRGREG); |
322 primitiveArray[2] = r[3]; // edx | 553 CHECK_EXCEPTION_(0); |
323 primitiveArray[3] = r[1]; // ebx | 554 primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); |
324 primitiveArray[4] = r[7]; // esp | 555 |
325 primitiveArray[5] = r[6]; // ebp | 556 primitiveArray[REG_INDEX(R15)] = state.__r15; |
326 primitiveArray[6] = r[5]; // esi | 557 primitiveArray[REG_INDEX(R14)] = state.__r14; |
327 primitiveArray[7] = r[4]; // edi | 558 primitiveArray[REG_INDEX(R13)] = state.__r13; |
328 (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); | 559 primitiveArray[REG_INDEX(R12)] = state.__r12; |
329 #elif defined(__x86_64__) | 560 primitiveArray[REG_INDEX(R11)] = state.__r11; |
330 /* From AMD64ThreadContext.java | 561 primitiveArray[REG_INDEX(R10)] = state.__r10; |
331 public static final int R15 = 0; | 562 primitiveArray[REG_INDEX(R9)] = state.__r9; |
332 public static final int R14 = 1; | 563 primitiveArray[REG_INDEX(R8)] = state.__r8; |
333 public static final int R13 = 2; | 564 primitiveArray[REG_INDEX(RDI)] = state.__rdi; |
334 public static final int R12 = 3; | 565 primitiveArray[REG_INDEX(RSI)] = state.__rsi; |
335 public static final int R11 = 4; | 566 primitiveArray[REG_INDEX(RBP)] = state.__rbp; |
336 public static final int R10 = 5; | 567 primitiveArray[REG_INDEX(RBX)] = state.__rbx; |
337 public static final int R9 = 6; | 568 primitiveArray[REG_INDEX(RDX)] = state.__rdx; |
338 public static final int R8 = 7; | 569 primitiveArray[REG_INDEX(RCX)] = state.__rcx; |
339 public static final int RDI = 8; | 570 primitiveArray[REG_INDEX(RAX)] = state.__rax; |
340 public static final int RSI = 9; | 571 primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used |
341 public static final int RBP = 10; | 572 primitiveArray[REG_INDEX(ERR)] = 0; // err, not used |
342 public static final int RBX = 11; | 573 primitiveArray[REG_INDEX(RIP)] = state.__rip; |
343 public static final int RDX = 12; | 574 primitiveArray[REG_INDEX(CS)] = state.__cs; |
344 public static final int RCX = 13; | 575 primitiveArray[REG_INDEX(RFL)] = state.__rflags; |
345 public static final int RAX = 14; | 576 primitiveArray[REG_INDEX(RSP)] = state.__rsp; |
346 public static final int TRAPNO = 15; | 577 primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS |
347 public static final int ERR = 16; | 578 primitiveArray[REG_INDEX(FS)] = state.__fs; |
348 public static final int RIP = 17; | 579 primitiveArray[REG_INDEX(GS)] = state.__gs; |
349 public static final int CS = 18; | 580 primitiveArray[REG_INDEX(ES)] = 0; |
350 public static final int RFL = 19; | 581 primitiveArray[REG_INDEX(DS)] = 0; |
351 public static final int RSP = 20; | 582 primitiveArray[REG_INDEX(FSBASE)] = 0; |
352 public static final int SS = 21; | 583 primitiveArray[REG_INDEX(GSBASE)] = 0; |
353 public static final int FS = 22; | 584 print_debug("set registers\n"); |
354 public static final int GS = 23; | 585 |
355 public static final int ES = 24; | 586 (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); |
356 public static final int DS = 25; | 587 |
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 | 588 #else |
398 #error Unsupported architecture | 589 #error UNSUPPORTED_ARCH |
399 #endif | 590 #endif /* amd64 */ |
400 | 591 |
401 return registerArray; | 592 return registerArray; |
402 } | 593 } |
403 | 594 |
404 /* | 595 /* |
408 */ | 599 */ |
409 JNIEXPORT jint JNICALL | 600 JNIEXPORT jint JNICALL |
410 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( | 601 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( |
411 JNIEnv *env, jobject this_obj, jint tid) | 602 JNIEnv *env, jobject this_obj, jint tid) |
412 { | 603 { |
413 if (debug) | 604 print_debug("translateTID0 called on tid = 0x%x\n", (int)tid); |
414 printf("translateTID0 called on tid = 0x%x\n", (int)tid); | |
415 | 605 |
416 kern_return_t result; | 606 kern_return_t result; |
417 thread_t foreign_tid, usable_tid; | 607 thread_t foreign_tid, usable_tid; |
418 mach_msg_type_name_t type; | 608 mach_msg_type_name_t type; |
419 | 609 |
424 MACH_MSG_TYPE_COPY_SEND, | 614 MACH_MSG_TYPE_COPY_SEND, |
425 &usable_tid, &type); | 615 &usable_tid, &type); |
426 if (result != KERN_SUCCESS) | 616 if (result != KERN_SUCCESS) |
427 return -1; | 617 return -1; |
428 | 618 |
429 if (debug) | 619 print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); |
430 printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); | |
431 | 620 |
432 return (jint) usable_tid; | 621 return (jint) usable_tid; |
433 } | 622 } |
434 | 623 |
435 | 624 |
436 static bool ptrace_continue(pid_t pid, int signal) { | 625 static bool ptrace_continue(pid_t pid, int signal) { |
437 // pass the signal to the process so we don't swallow it | 626 // pass the signal to the process so we don't swallow it |
438 int res; | 627 int res; |
439 if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) { | 628 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); | 629 print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); |
441 return false; | 630 return false; |
442 } | 631 } |
443 return true; | 632 return true; |
444 } | 633 } |
445 | 634 |
459 if (WSTOPSIG(status) == SIGSTOP) { | 648 if (WSTOPSIG(status) == SIGSTOP) { |
460 // Debuggee stopped by SIGSTOP. | 649 // Debuggee stopped by SIGSTOP. |
461 return true; | 650 return true; |
462 } | 651 } |
463 if (!ptrace_continue(pid, WSTOPSIG(status))) { | 652 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)); | 653 print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); |
465 return false; | 654 return false; |
466 } | 655 } |
467 } else { | 656 } else { |
468 fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); | 657 print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); |
469 return false; | 658 return false; |
470 } | 659 } |
471 } else { | 660 } else { |
472 switch (errno) { | 661 switch (errno) { |
473 case EINTR: | 662 case EINTR: |
474 continue; | 663 continue; |
475 break; | 664 break; |
476 case ECHILD: | 665 case ECHILD: |
477 fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); | 666 print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); |
478 break; | 667 break; |
479 case EINVAL: | 668 case EINVAL: |
480 fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n"); | 669 print_error("attach: waitpid() failed. Invalid options argument.\n"); |
481 break; | 670 break; |
482 default: | 671 default: |
483 fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno); | 672 print_error("attach: waitpid() failed. Unexpected error %d\n",errno); |
484 break; | 673 break; |
485 } | 674 } |
486 return false; | 675 return false; |
487 } | 676 } |
488 } | 677 } |
490 | 679 |
491 // attach to a process/thread specified by "pid" | 680 // attach to a process/thread specified by "pid" |
492 static bool ptrace_attach(pid_t pid) { | 681 static bool ptrace_attach(pid_t pid) { |
493 int res; | 682 int res; |
494 if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { | 683 if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { |
495 fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); | 684 print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); |
496 return false; | 685 return false; |
497 } else { | 686 } else { |
498 return ptrace_waitpid(pid); | 687 return ptrace_waitpid(pid); |
499 } | 688 } |
500 } | 689 } |
502 /* | 691 /* |
503 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | 692 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
504 * Method: attach0 | 693 * Method: attach0 |
505 * Signature: (I)V | 694 * Signature: (I)V |
506 */ | 695 */ |
507 JNIEXPORT void JNICALL | 696 JNIEXPORT void JNICALL |
508 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( | 697 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( |
509 JNIEnv *env, jobject this_obj, jint jpid) | 698 JNIEnv *env, jobject this_obj, jint jpid) |
510 { | 699 { |
700 print_debug("attach0 called for jpid=%d\n", (int)jpid); | |
701 | |
511 JNF_COCOA_ENTER(env); | 702 JNF_COCOA_ENTER(env); |
512 if (getenv("JAVA_SAPROC_DEBUG") != NULL) | 703 |
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; | 704 kern_return_t result; |
520 task_t gTask = 0; | 705 task_t gTask = 0; |
521 result = task_for_pid(mach_task_self(), jpid, &gTask); | 706 result = task_for_pid(mach_task_self(), jpid, &gTask); |
522 if (result != KERN_SUCCESS) { | 707 if (result != KERN_SUCCESS) { |
523 fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); | 708 print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); |
524 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); | 709 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); |
525 } | 710 } |
526 putTask(env, this_obj, gTask); | 711 putTask(env, this_obj, gTask); |
527 | 712 |
528 // use ptrace to stop the process | 713 // use ptrace to stop the process |
548 } | 733 } |
549 | 734 |
550 JNF_COCOA_EXIT(env); | 735 JNF_COCOA_EXIT(env); |
551 } | 736 } |
552 | 737 |
738 /** For core file, | |
739 called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */ | |
740 static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { | |
741 int n = 0, i = 0; | |
742 | |
743 // add load objects | |
744 n = get_num_libs(ph); | |
745 for (i = 0; i < n; i++) { | |
746 uintptr_t base; | |
747 const char* name; | |
748 jobject loadObject; | |
749 jobject loadObjectList; | |
750 | |
751 base = get_lib_base(ph, i); | |
752 name = get_lib_name(ph, i); | |
753 loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, | |
754 (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); | |
755 CHECK_EXCEPTION; | |
756 loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); | |
757 CHECK_EXCEPTION; | |
758 (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); | |
759 CHECK_EXCEPTION; | |
760 } | |
761 } | |
762 | |
763 /* | |
764 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | |
765 * Method: attach0 | |
766 * Signature: (Ljava/lang/String;Ljava/lang/String;)V | |
767 */ | |
768 JNIEXPORT void JNICALL | |
769 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2( | |
770 JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) | |
771 { | |
772 const char *execName_cstr; | |
773 const char *coreName_cstr; | |
774 jboolean isCopy; | |
775 struct ps_prochandle* ph; | |
776 | |
777 execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); | |
778 CHECK_EXCEPTION; | |
779 coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); | |
780 CHECK_EXCEPTION; | |
781 | |
782 print_debug("attach: %s %s\n", execName_cstr, coreName_cstr); | |
783 | |
784 if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { | |
785 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); | |
786 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); | |
787 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); | |
788 } | |
789 (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); | |
790 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); | |
791 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); | |
792 fillLoadObjects(env, this_obj, ph); | |
793 } | |
794 | |
553 /* | 795 /* |
554 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal | 796 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal |
555 * Method: detach0 | 797 * Method: detach0 |
556 * Signature: ()V | 798 * Signature: ()V |
557 */ | 799 */ |
558 JNIEXPORT void JNICALL | 800 JNIEXPORT void JNICALL |
559 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( | 801 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( |
560 JNIEnv *env, jobject this_obj) | 802 JNIEnv *env, jobject this_obj) |
561 { | 803 { |
804 print_debug("detach0 called\n"); | |
805 struct ps_prochandle* ph = get_proc_handle(env, this_obj); | |
806 if (ph != NULL && ph->core != NULL) { | |
807 Prelease(ph); | |
808 return; | |
809 } | |
562 JNF_COCOA_ENTER(env); | 810 JNF_COCOA_ENTER(env); |
563 if (debug) printf("detach0 called\n"); | |
564 | |
565 task_t gTask = getTask(env, this_obj); | 811 task_t gTask = getTask(env, this_obj); |
566 | 812 |
567 // detach from the ptraced process causing it to resume execution | 813 // detach from the ptraced process causing it to resume execution |
568 int pid; | 814 int pid; |
569 kern_return_t k_res; | 815 kern_return_t k_res; |
570 k_res = pid_for_task(gTask, &pid); | 816 k_res = pid_for_task(gTask, &pid); |
571 if (k_res != KERN_SUCCESS) { | 817 if (k_res != KERN_SUCCESS) { |
572 fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res); | 818 print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); |
573 } | 819 } |
574 else { | 820 else { |
575 int res = ptrace(PT_DETACH, pid, 0, 0); | 821 int res = ptrace(PT_DETACH, pid, 0, 0); |
576 if (res < 0) { | 822 if (res < 0) { |
577 fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); | 823 print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); |
578 } | 824 } |
579 } | 825 } |
580 | 826 |
581 mach_port_deallocate(mach_task_self(), gTask); | 827 mach_port_deallocate(mach_task_self(), gTask); |
582 id symbolicator = getSymbolicator(env, this_obj); | 828 id symbolicator = getSymbolicator(env, this_obj); |
583 if (symbolicator != nil) { | 829 if (symbolicator != nil) { |
584 CFRelease(symbolicator); | 830 CFRelease(symbolicator); |
585 } | 831 } |
586 JNF_COCOA_EXIT(env); | 832 JNF_COCOA_EXIT(env); |
587 } | 833 } |
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 } |