Sun, 17 Mar 2013 08:57:56 -0700
Merge
src/share/vm/memory/metaspace.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/agent/src/os/bsd/MacosxDebuggerLocal.m Fri Mar 15 11:44:33 2013 -0700 1.2 +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m Sun Mar 17 08:57:56 2013 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -40,12 +40,34 @@ 1.11 #import <errno.h> 1.12 #import <sys/types.h> 1.13 #import <sys/ptrace.h> 1.14 +#include "libproc_impl.h" 1.15 1.16 -jboolean debug = JNI_FALSE; 1.17 +#define UNSUPPORTED_ARCH "Unsupported architecture!" 1.18 + 1.19 +#if defined(x86_64) && !defined(amd64) 1.20 +#define amd64 1 1.21 +#endif 1.22 + 1.23 +#if amd64 1.24 +#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" 1.25 +#else 1.26 +#error UNSUPPORTED_ARCH 1.27 +#endif 1.28 1.29 static jfieldID symbolicatorID = 0; // set in _init0 1.30 static jfieldID taskID = 0; // set in _init0 1.31 1.32 +static jfieldID p_ps_prochandle_ID = 0; 1.33 +static jfieldID loadObjectList_ID = 0; 1.34 +static jmethodID listAdd_ID = 0; 1.35 + 1.36 +static jmethodID createClosestSymbol_ID = 0; 1.37 +static jmethodID createLoadObject_ID = 0; 1.38 +static jmethodID getJavaThreadsInfo_ID = 0; 1.39 + 1.40 +// indicator if thread id (lwpid_t) was set 1.41 +static bool _threads_filled = false; 1.42 + 1.43 static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { 1.44 (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); 1.45 } 1.46 @@ -76,6 +98,11 @@ 1.47 (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); 1.48 } 1.49 1.50 +static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { 1.51 + jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID); 1.52 + return (struct ps_prochandle*)(intptr_t)ptr; 1.53 +} 1.54 + 1.55 #if defined(__i386__) 1.56 #define hsdb_thread_state_t x86_thread_state32_t 1.57 #define hsdb_float_state_t x86_float_state32_t 1.58 @@ -91,7 +118,7 @@ 1.59 #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT 1.60 #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT 1.61 #else 1.62 - #error "Unsupported architecture" 1.63 + #error UNSUPPORTED_ARCH 1.64 #endif 1.65 1.66 /* 1.67 @@ -104,6 +131,66 @@ 1.68 symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); 1.69 taskID = (*env)->GetFieldID(env, cls, "task", "J"); 1.70 CHECK_EXCEPTION; 1.71 + 1.72 + // for core file 1.73 + p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); 1.74 + CHECK_EXCEPTION; 1.75 + loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); 1.76 + CHECK_EXCEPTION; 1.77 + 1.78 + // methods we use 1.79 + createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", 1.80 + "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); 1.81 + CHECK_EXCEPTION; 1.82 + createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", 1.83 + "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); 1.84 + CHECK_EXCEPTION; 1.85 + 1.86 + // java.util.List method we call 1.87 + jclass listClass = (*env)->FindClass(env, "java/util/List"); 1.88 + CHECK_EXCEPTION; 1.89 + listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); 1.90 + CHECK_EXCEPTION; 1.91 + getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo", 1.92 + "()[J"); 1.93 + CHECK_EXCEPTION; 1.94 + 1.95 + init_libproc(getenv("LIBSAPROC_DEBUG") != NULL); 1.96 +} 1.97 + 1.98 +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize 1.99 + (JNIEnv *env, jclass cls) 1.100 +{ 1.101 +#ifdef _LP64 1.102 + return 8; 1.103 +#else 1.104 + #error UNSUPPORTED_ARCH 1.105 +#endif 1.106 +} 1.107 + 1.108 +/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */ 1.109 +jlong lookupByNameIncore( 1.110 + JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName) 1.111 +{ 1.112 + const char *objectName_cstr, *symbolName_cstr; 1.113 + jlong addr; 1.114 + jboolean isCopy; 1.115 + objectName_cstr = NULL; 1.116 + if (objectName != NULL) { 1.117 + objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy); 1.118 + CHECK_EXCEPTION_(0); 1.119 + } 1.120 + symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy); 1.121 + CHECK_EXCEPTION_(0); 1.122 + 1.123 + print_debug("look for %s \n", symbolName_cstr); 1.124 + addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr); 1.125 + 1.126 + if (objectName_cstr != NULL) { 1.127 + (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); 1.128 + } 1.129 + (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr); 1.130 + return addr; 1.131 } 1.132 1.133 /* 1.134 @@ -116,14 +203,17 @@ 1.135 JNIEnv *env, jobject this_obj, 1.136 jstring objectName, jstring symbolName) 1.137 { 1.138 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.139 + if (ph->core != NULL) { 1.140 + return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); 1.141 + } 1.142 + 1.143 jlong address = 0; 1.144 1.145 JNF_COCOA_ENTER(env); 1.146 NSString *symbolNameString = JNFJavaToNSString(env, symbolName); 1.147 1.148 - if (debug) { 1.149 - printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]); 1.150 - } 1.151 + print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]); 1.152 1.153 id symbolicator = getSymbolicator(env, this_obj); 1.154 if (symbolicator != nil) { 1.155 @@ -131,9 +221,7 @@ 1.156 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); 1.157 } 1.158 1.159 - if (debug) { 1.160 - printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); 1.161 - } 1.162 + print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); 1.163 JNF_COCOA_EXIT(env); 1.164 1.165 return address; 1.166 @@ -141,6 +229,42 @@ 1.167 1.168 /* 1.169 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 1.170 + * Method: lookupByAddress0 1.171 + * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; 1.172 + */ 1.173 +JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0 1.174 + (JNIEnv *env, jobject this_obj, jlong addr) { 1.175 + uintptr_t offset; 1.176 + const char* sym = NULL; 1.177 + 1.178 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.179 + sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); 1.180 + if (sym == NULL) return 0; 1.181 + return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, 1.182 + (*env)->NewStringUTF(env, sym), (jlong)offset); 1.183 +} 1.184 + 1.185 +/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */ 1.186 +jbyteArray readBytesFromCore( 1.187 + JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes) 1.188 +{ 1.189 + jboolean isCopy; 1.190 + jbyteArray array; 1.191 + jbyte *bufPtr; 1.192 + ps_err_e err; 1.193 + 1.194 + array = (*env)->NewByteArray(env, numBytes); 1.195 + CHECK_EXCEPTION_(0); 1.196 + bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); 1.197 + CHECK_EXCEPTION_(0); 1.198 + 1.199 + err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); 1.200 + (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); 1.201 + return (err == PS_OK)? array : 0; 1.202 +} 1.203 + 1.204 +/* 1.205 + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 1.206 * Method: readBytesFromProcess0 1.207 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; 1.208 */ 1.209 @@ -149,12 +273,15 @@ 1.210 JNIEnv *env, jobject this_obj, 1.211 jlong addr, jlong numBytes) 1.212 { 1.213 - if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); 1.214 + print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); 1.215 1.216 // must allocate storage instead of using former parameter buf 1.217 - jboolean isCopy; 1.218 jbyteArray array; 1.219 - jbyte *bufPtr; 1.220 + 1.221 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.222 + if (ph->core != NULL) { 1.223 + return readBytesFromCore(env, ph, this_obj, addr, numBytes); 1.224 + } 1.225 1.226 array = (*env)->NewByteArray(env, numBytes); 1.227 CHECK_EXCEPTION_(0); 1.228 @@ -189,7 +316,7 @@ 1.229 // assume all failures are unmapped pages 1.230 } 1.231 1.232 - if (debug) fprintf(stderr, "%ld pages\n", pageCount); 1.233 + print_debug("%ld pages\n", pageCount); 1.234 1.235 remaining = numBytes; 1.236 1.237 @@ -207,7 +334,7 @@ 1.238 } 1.239 1.240 if (mapped[i]) { 1.241 - if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start); 1.242 + print_debug("page %d mapped (len %ld start %ld)\n", i, len, start); 1.243 (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start)); 1.244 vm_deallocate(mach_task_self(), pages[i], vm_page_size); 1.245 } 1.246 @@ -220,6 +347,115 @@ 1.247 return array; 1.248 } 1.249 1.250 +/** Only used for core file reading, set thread_id for threads which is got after core file parsed. 1.251 + * Thread context is available in Mach-O core file but thread id is not. We can get thread id 1.252 + * from Threads which store all java threads information when they are created. Here we can identify 1.253 + * them as java threads by checking if a thread's rsp or rbp within a java thread's stack. 1.254 + * Note Macosx uses unique_thread_id which is different from other platforms though printed ids 1.255 + * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long 1.256 + * integers to host all java threads' id, stack_start, stack_end as: 1.257 + * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] 1.258 + * 1.259 + * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). 1.260 + * This function should be called only once if succeeded 1.261 + */ 1.262 +bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { 1.263 + int n = 0, i = 0, j; 1.264 + struct reg regs; 1.265 + 1.266 + jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); 1.267 + CHECK_EXCEPTION_(false); 1.268 + int len = (int)(*env)->GetArrayLength(env, thrinfos); 1.269 + uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); 1.270 + CHECK_EXCEPTION_(false); 1.271 + n = get_num_threads(ph); 1.272 + print_debug("fill_java_threads called, num_of_thread = %d\n", n); 1.273 + for (i = 0; i < n; i++) { 1.274 + if (!get_nth_lwp_regs(ph, i, ®s)) { 1.275 + print_debug("Could not get regs of thread %d, already set!\n", i); 1.276 + return false; 1.277 + } 1.278 + for (j = 0; j < len; j += 3) { 1.279 + lwpid_t uid = cinfos[j]; 1.280 + uint64_t beg = cinfos[j + 1]; 1.281 + uint64_t end = cinfos[j + 2]; 1.282 + if ((regs.r_rsp < end && regs.r_rsp >= beg) || 1.283 + (regs.r_rbp < end && regs.r_rbp >= beg)) { 1.284 + set_lwp_id(ph, i, uid); 1.285 + break; 1.286 + } 1.287 + } 1.288 + } 1.289 + (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0); 1.290 + CHECK_EXCEPTION_(false); 1.291 + return true; 1.292 +} 1.293 + 1.294 +/* For core file only, called from 1.295 + * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0 1.296 + */ 1.297 +jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) { 1.298 + if (!_threads_filled) { 1.299 + if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) { 1.300 + throw_new_debugger_exception(env, "Failed to fill in threads"); 1.301 + return 0; 1.302 + } else { 1.303 + _threads_filled = true; 1.304 + } 1.305 + } 1.306 + 1.307 + struct reg gregs; 1.308 + jboolean isCopy; 1.309 + jlongArray array; 1.310 + jlong *regs; 1.311 + 1.312 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.313 + if (get_lwp_regs(ph, lwp_id, &gregs) != true) { 1.314 + THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0); 1.315 + } 1.316 + 1.317 +#undef NPRGREG 1.318 +#undef REG_INDEX 1.319 +#if amd64 1.320 +#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG 1.321 +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg 1.322 + 1.323 + array = (*env)->NewLongArray(env, NPRGREG); 1.324 + CHECK_EXCEPTION_(0); 1.325 + regs = (*env)->GetLongArrayElements(env, array, &isCopy); 1.326 + 1.327 + regs[REG_INDEX(R15)] = gregs.r_r15; 1.328 + regs[REG_INDEX(R14)] = gregs.r_r14; 1.329 + regs[REG_INDEX(R13)] = gregs.r_r13; 1.330 + regs[REG_INDEX(R12)] = gregs.r_r12; 1.331 + regs[REG_INDEX(RBP)] = gregs.r_rbp; 1.332 + regs[REG_INDEX(RBX)] = gregs.r_rbx; 1.333 + regs[REG_INDEX(R11)] = gregs.r_r11; 1.334 + regs[REG_INDEX(R10)] = gregs.r_r10; 1.335 + regs[REG_INDEX(R9)] = gregs.r_r9; 1.336 + regs[REG_INDEX(R8)] = gregs.r_r8; 1.337 + regs[REG_INDEX(RAX)] = gregs.r_rax; 1.338 + regs[REG_INDEX(RCX)] = gregs.r_rcx; 1.339 + regs[REG_INDEX(RDX)] = gregs.r_rdx; 1.340 + regs[REG_INDEX(RSI)] = gregs.r_rsi; 1.341 + regs[REG_INDEX(RDI)] = gregs.r_rdi; 1.342 + regs[REG_INDEX(RIP)] = gregs.r_rip; 1.343 + regs[REG_INDEX(CS)] = gregs.r_cs; 1.344 + regs[REG_INDEX(RSP)] = gregs.r_rsp; 1.345 + regs[REG_INDEX(SS)] = gregs.r_ss; 1.346 + regs[REG_INDEX(FSBASE)] = 0; 1.347 + regs[REG_INDEX(GSBASE)] = 0; 1.348 + regs[REG_INDEX(DS)] = gregs.r_ds; 1.349 + regs[REG_INDEX(ES)] = gregs.r_es; 1.350 + regs[REG_INDEX(FS)] = gregs.r_fs; 1.351 + regs[REG_INDEX(GS)] = gregs.r_gs; 1.352 + regs[REG_INDEX(TRAPNO)] = gregs.r_trapno; 1.353 + regs[REG_INDEX(RFL)] = gregs.r_rflags; 1.354 + 1.355 +#endif /* amd64 */ 1.356 + (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); 1.357 + return array; 1.358 +} 1.359 1.360 /* 1.361 * Lookup the thread_t that corresponds to the given thread_id. 1.362 @@ -232,9 +468,7 @@ 1.363 */ 1.364 thread_t 1.365 lookupThreadFromThreadId(task_t task, jlong thread_id) { 1.366 - if (debug) { 1.367 - printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); 1.368 - } 1.369 + print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); 1.370 1.371 thread_array_t thread_list = NULL; 1.372 mach_msg_type_number_t thread_list_count = 0; 1.373 @@ -244,9 +478,7 @@ 1.374 // get the list of all the send rights 1.375 kern_return_t result = task_threads(task, &thread_list, &thread_list_count); 1.376 if (result != KERN_SUCCESS) { 1.377 - if (debug) { 1.378 - printf("task_threads returned 0x%x\n", result); 1.379 - } 1.380 + print_debug("task_threads returned 0x%x\n", result); 1.381 return 0; 1.382 } 1.383 1.384 @@ -257,9 +489,7 @@ 1.385 // get the THREAD_IDENTIFIER_INFO for the send right 1.386 result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); 1.387 if (result != KERN_SUCCESS) { 1.388 - if (debug) { 1.389 - printf("thread_info returned 0x%x\n", result); 1.390 - } 1.391 + print_debug("thread_info returned 0x%x\n", result); 1.392 break; 1.393 } 1.394 1.395 @@ -288,15 +518,17 @@ 1.396 JNIEnv *env, jobject this_obj, 1.397 jlong thread_id) 1.398 { 1.399 - if (debug) 1.400 - printf("getThreadRegisterSet0 called\n"); 1.401 + print_debug("getThreadRegisterSet0 called\n"); 1.402 + 1.403 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.404 + if (ph->core != NULL) { 1.405 + return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id); 1.406 + } 1.407 1.408 kern_return_t result; 1.409 thread_t tid; 1.410 mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT; 1.411 hsdb_thread_state_t state; 1.412 - unsigned int *r; 1.413 - int i; 1.414 jlongArray registerArray; 1.415 jlong *primitiveArray; 1.416 task_t gTask = getTask(env, this_obj); 1.417 @@ -306,97 +538,56 @@ 1.418 result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); 1.419 1.420 if (result != KERN_SUCCESS) { 1.421 - if (debug) 1.422 - printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result); 1.423 + print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result); 1.424 return NULL; 1.425 } 1.426 1.427 - // 40 32-bit registers on ppc, 16 on x86. 1.428 - // Output order is the same as the order in the ppc_thread_state/i386_thread_state struct. 1.429 -#if defined(__i386__) 1.430 - r = (unsigned int *)&state; 1.431 - registerArray = (*env)->NewLongArray(env, 8); 1.432 - primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); 1.433 - primitiveArray[0] = r[0]; // eax 1.434 - primitiveArray[1] = r[2]; // ecx 1.435 - primitiveArray[2] = r[3]; // edx 1.436 - primitiveArray[3] = r[1]; // ebx 1.437 - primitiveArray[4] = r[7]; // esp 1.438 - primitiveArray[5] = r[6]; // ebp 1.439 - primitiveArray[6] = r[5]; // esi 1.440 - primitiveArray[7] = r[4]; // edi 1.441 - (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); 1.442 -#elif defined(__x86_64__) 1.443 - /* From AMD64ThreadContext.java 1.444 - public static final int R15 = 0; 1.445 - public static final int R14 = 1; 1.446 - public static final int R13 = 2; 1.447 - public static final int R12 = 3; 1.448 - public static final int R11 = 4; 1.449 - public static final int R10 = 5; 1.450 - public static final int R9 = 6; 1.451 - public static final int R8 = 7; 1.452 - public static final int RDI = 8; 1.453 - public static final int RSI = 9; 1.454 - public static final int RBP = 10; 1.455 - public static final int RBX = 11; 1.456 - public static final int RDX = 12; 1.457 - public static final int RCX = 13; 1.458 - public static final int RAX = 14; 1.459 - public static final int TRAPNO = 15; 1.460 - public static final int ERR = 16; 1.461 - public static final int RIP = 17; 1.462 - public static final int CS = 18; 1.463 - public static final int RFL = 19; 1.464 - public static final int RSP = 20; 1.465 - public static final int SS = 21; 1.466 - public static final int FS = 22; 1.467 - public static final int GS = 23; 1.468 - public static final int ES = 24; 1.469 - public static final int DS = 25; 1.470 - public static final int FSBASE = 26; 1.471 - public static final int GSBASE = 27; 1.472 - */ 1.473 - // 64 bit 1.474 - if (debug) printf("Getting threads for a 64-bit process\n"); 1.475 - registerArray = (*env)->NewLongArray(env, 28); 1.476 - primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); 1.477 +#if amd64 1.478 +#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG 1.479 +#undef REG_INDEX 1.480 +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg 1.481 1.482 - primitiveArray[0] = state.__r15; 1.483 - primitiveArray[1] = state.__r14; 1.484 - primitiveArray[2] = state.__r13; 1.485 - primitiveArray[3] = state.__r12; 1.486 - primitiveArray[4] = state.__r11; 1.487 - primitiveArray[5] = state.__r10; 1.488 - primitiveArray[6] = state.__r9; 1.489 - primitiveArray[7] = state.__r8; 1.490 - primitiveArray[8] = state.__rdi; 1.491 - primitiveArray[9] = state.__rsi; 1.492 - primitiveArray[10] = state.__rbp; 1.493 - primitiveArray[11] = state.__rbx; 1.494 - primitiveArray[12] = state.__rdx; 1.495 - primitiveArray[13] = state.__rcx; 1.496 - primitiveArray[14] = state.__rax; 1.497 - primitiveArray[15] = 0; // trapno ? 1.498 - primitiveArray[16] = 0; // err ? 1.499 - primitiveArray[17] = state.__rip; 1.500 - primitiveArray[18] = state.__cs; 1.501 - primitiveArray[19] = state.__rflags; 1.502 - primitiveArray[20] = state.__rsp; 1.503 - primitiveArray[21] = 0; // We don't have SS 1.504 - primitiveArray[22] = state.__fs; 1.505 - primitiveArray[23] = state.__gs; 1.506 - primitiveArray[24] = 0; 1.507 - primitiveArray[25] = 0; 1.508 - primitiveArray[26] = 0; 1.509 - primitiveArray[27] = 0; 1.510 + // 64 bit 1.511 + print_debug("Getting threads for a 64-bit process\n"); 1.512 + registerArray = (*env)->NewLongArray(env, NPRGREG); 1.513 + CHECK_EXCEPTION_(0); 1.514 + primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); 1.515 1.516 - if (debug) printf("set registers\n"); 1.517 + primitiveArray[REG_INDEX(R15)] = state.__r15; 1.518 + primitiveArray[REG_INDEX(R14)] = state.__r14; 1.519 + primitiveArray[REG_INDEX(R13)] = state.__r13; 1.520 + primitiveArray[REG_INDEX(R12)] = state.__r12; 1.521 + primitiveArray[REG_INDEX(R11)] = state.__r11; 1.522 + primitiveArray[REG_INDEX(R10)] = state.__r10; 1.523 + primitiveArray[REG_INDEX(R9)] = state.__r9; 1.524 + primitiveArray[REG_INDEX(R8)] = state.__r8; 1.525 + primitiveArray[REG_INDEX(RDI)] = state.__rdi; 1.526 + primitiveArray[REG_INDEX(RSI)] = state.__rsi; 1.527 + primitiveArray[REG_INDEX(RBP)] = state.__rbp; 1.528 + primitiveArray[REG_INDEX(RBX)] = state.__rbx; 1.529 + primitiveArray[REG_INDEX(RDX)] = state.__rdx; 1.530 + primitiveArray[REG_INDEX(RCX)] = state.__rcx; 1.531 + primitiveArray[REG_INDEX(RAX)] = state.__rax; 1.532 + primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used 1.533 + primitiveArray[REG_INDEX(ERR)] = 0; // err, not used 1.534 + primitiveArray[REG_INDEX(RIP)] = state.__rip; 1.535 + primitiveArray[REG_INDEX(CS)] = state.__cs; 1.536 + primitiveArray[REG_INDEX(RFL)] = state.__rflags; 1.537 + primitiveArray[REG_INDEX(RSP)] = state.__rsp; 1.538 + primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS 1.539 + primitiveArray[REG_INDEX(FS)] = state.__fs; 1.540 + primitiveArray[REG_INDEX(GS)] = state.__gs; 1.541 + primitiveArray[REG_INDEX(ES)] = 0; 1.542 + primitiveArray[REG_INDEX(DS)] = 0; 1.543 + primitiveArray[REG_INDEX(FSBASE)] = 0; 1.544 + primitiveArray[REG_INDEX(GSBASE)] = 0; 1.545 + print_debug("set registers\n"); 1.546 1.547 - (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); 1.548 + (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); 1.549 + 1.550 #else 1.551 -#error Unsupported architecture 1.552 -#endif 1.553 +#error UNSUPPORTED_ARCH 1.554 +#endif /* amd64 */ 1.555 1.556 return registerArray; 1.557 } 1.558 @@ -410,8 +601,7 @@ 1.559 Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( 1.560 JNIEnv *env, jobject this_obj, jint tid) 1.561 { 1.562 - if (debug) 1.563 - printf("translateTID0 called on tid = 0x%x\n", (int)tid); 1.564 + print_debug("translateTID0 called on tid = 0x%x\n", (int)tid); 1.565 1.566 kern_return_t result; 1.567 thread_t foreign_tid, usable_tid; 1.568 @@ -426,8 +616,7 @@ 1.569 if (result != KERN_SUCCESS) 1.570 return -1; 1.571 1.572 - if (debug) 1.573 - printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); 1.574 + print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); 1.575 1.576 return (jint) usable_tid; 1.577 } 1.578 @@ -437,7 +626,7 @@ 1.579 // pass the signal to the process so we don't swallow it 1.580 int res; 1.581 if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) { 1.582 - fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); 1.583 + print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); 1.584 return false; 1.585 } 1.586 return true; 1.587 @@ -461,11 +650,11 @@ 1.588 return true; 1.589 } 1.590 if (!ptrace_continue(pid, WSTOPSIG(status))) { 1.591 - fprintf(stderr, "attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); 1.592 + print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); 1.593 return false; 1.594 } 1.595 } else { 1.596 - fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 1.597 + print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 1.598 return false; 1.599 } 1.600 } else { 1.601 @@ -474,13 +663,13 @@ 1.602 continue; 1.603 break; 1.604 case ECHILD: 1.605 - fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); 1.606 + print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); 1.607 break; 1.608 case EINVAL: 1.609 - fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n"); 1.610 + print_error("attach: waitpid() failed. Invalid options argument.\n"); 1.611 break; 1.612 default: 1.613 - fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno); 1.614 + print_error("attach: waitpid() failed. Unexpected error %d\n",errno); 1.615 break; 1.616 } 1.617 return false; 1.618 @@ -492,7 +681,7 @@ 1.619 static bool ptrace_attach(pid_t pid) { 1.620 int res; 1.621 if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { 1.622 - fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); 1.623 + print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); 1.624 return false; 1.625 } else { 1.626 return ptrace_waitpid(pid); 1.627 @@ -504,23 +693,19 @@ 1.628 * Method: attach0 1.629 * Signature: (I)V 1.630 */ 1.631 -JNIEXPORT void JNICALL 1.632 +JNIEXPORT void JNICALL 1.633 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( 1.634 - JNIEnv *env, jobject this_obj, jint jpid) 1.635 + JNIEnv *env, jobject this_obj, jint jpid) 1.636 { 1.637 + print_debug("attach0 called for jpid=%d\n", (int)jpid); 1.638 + 1.639 JNF_COCOA_ENTER(env); 1.640 - if (getenv("JAVA_SAPROC_DEBUG") != NULL) 1.641 - debug = JNI_TRUE; 1.642 - else 1.643 - debug = JNI_FALSE; 1.644 - if (debug) printf("attach0 called for jpid=%d\n", (int)jpid); 1.645 - 1.646 - // get the task from the pid 1.647 + 1.648 kern_return_t result; 1.649 task_t gTask = 0; 1.650 result = task_for_pid(mach_task_self(), jpid, &gTask); 1.651 if (result != KERN_SUCCESS) { 1.652 - fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); 1.653 + print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); 1.654 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); 1.655 } 1.656 putTask(env, this_obj, gTask); 1.657 @@ -550,18 +735,79 @@ 1.658 JNF_COCOA_EXIT(env); 1.659 } 1.660 1.661 +/** For core file, 1.662 + called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */ 1.663 +static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { 1.664 + int n = 0, i = 0; 1.665 + 1.666 + // add load objects 1.667 + n = get_num_libs(ph); 1.668 + for (i = 0; i < n; i++) { 1.669 + uintptr_t base; 1.670 + const char* name; 1.671 + jobject loadObject; 1.672 + jobject loadObjectList; 1.673 + 1.674 + base = get_lib_base(ph, i); 1.675 + name = get_lib_name(ph, i); 1.676 + loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, 1.677 + (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); 1.678 + CHECK_EXCEPTION; 1.679 + loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); 1.680 + CHECK_EXCEPTION; 1.681 + (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); 1.682 + CHECK_EXCEPTION; 1.683 + } 1.684 +} 1.685 + 1.686 +/* 1.687 + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 1.688 + * Method: attach0 1.689 + * Signature: (Ljava/lang/String;Ljava/lang/String;)V 1.690 + */ 1.691 +JNIEXPORT void JNICALL 1.692 +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2( 1.693 + JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) 1.694 +{ 1.695 + const char *execName_cstr; 1.696 + const char *coreName_cstr; 1.697 + jboolean isCopy; 1.698 + struct ps_prochandle* ph; 1.699 + 1.700 + execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); 1.701 + CHECK_EXCEPTION; 1.702 + coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); 1.703 + CHECK_EXCEPTION; 1.704 + 1.705 + print_debug("attach: %s %s\n", execName_cstr, coreName_cstr); 1.706 + 1.707 + if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { 1.708 + (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 1.709 + (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 1.710 + THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); 1.711 + } 1.712 + (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); 1.713 + (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 1.714 + (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 1.715 + fillLoadObjects(env, this_obj, ph); 1.716 +} 1.717 + 1.718 /* 1.719 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal 1.720 * Method: detach0 1.721 * Signature: ()V 1.722 */ 1.723 -JNIEXPORT void JNICALL 1.724 +JNIEXPORT void JNICALL 1.725 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( 1.726 - JNIEnv *env, jobject this_obj) 1.727 + JNIEnv *env, jobject this_obj) 1.728 { 1.729 + print_debug("detach0 called\n"); 1.730 + struct ps_prochandle* ph = get_proc_handle(env, this_obj); 1.731 + if (ph != NULL && ph->core != NULL) { 1.732 + Prelease(ph); 1.733 + return; 1.734 + } 1.735 JNF_COCOA_ENTER(env); 1.736 - if (debug) printf("detach0 called\n"); 1.737 - 1.738 task_t gTask = getTask(env, this_obj); 1.739 1.740 // detach from the ptraced process causing it to resume execution 1.741 @@ -569,15 +815,15 @@ 1.742 kern_return_t k_res; 1.743 k_res = pid_for_task(gTask, &pid); 1.744 if (k_res != KERN_SUCCESS) { 1.745 - fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res); 1.746 + print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); 1.747 } 1.748 else { 1.749 int res = ptrace(PT_DETACH, pid, 0, 0); 1.750 if (res < 0) { 1.751 - fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); 1.752 + print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); 1.753 } 1.754 } 1.755 - 1.756 + 1.757 mach_port_deallocate(mach_task_self(), gTask); 1.758 id symbolicator = getSymbolicator(env, this_obj); 1.759 if (symbolicator != nil) { 1.760 @@ -585,170 +831,3 @@ 1.761 } 1.762 JNF_COCOA_EXIT(env); 1.763 } 1.764 - 1.765 -/* 1.766 - * Class: sun_jvm_hotspot_asm_Disassembler 1.767 - * Method: load_library 1.768 - * Signature: (Ljava/lang/String;)L 1.769 - */ 1.770 -JNIEXPORT jlong JNICALL 1.771 -Java_sun_jvm_hotspot_asm_Disassembler_load_1library( 1.772 - JNIEnv * env, 1.773 - jclass disclass, 1.774 - jstring jrepath_s, 1.775 - jstring libname_s) 1.776 -{ 1.777 - uintptr_t func = 0; 1.778 - const char* error_message = NULL; 1.779 - const char* java_home; 1.780 - jboolean isCopy; 1.781 - uintptr_t *handle = NULL; 1.782 - 1.783 - const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ 1.784 - const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); 1.785 - char buffer[128]; 1.786 - 1.787 - /* Load the hsdis library */ 1.788 - void* hsdis_handle; 1.789 - hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL); 1.790 - if (hsdis_handle == NULL) { 1.791 - snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname); 1.792 - hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL); 1.793 - } 1.794 - if (hsdis_handle != NULL) { 1.795 - func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual"); 1.796 - } 1.797 - if (func == 0) { 1.798 - error_message = dlerror(); 1.799 - fprintf(stderr, "%s\n", error_message); 1.800 - } 1.801 - 1.802 - (*env)->ReleaseStringUTFChars(env, libname_s, libname); 1.803 - (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath); 1.804 - 1.805 - if (func == 0) { 1.806 - /* Couldn't find entry point. error_message should contain some 1.807 - * platform dependent error message. 1.808 - */ 1.809 - THROW_NEW_DEBUGGER_EXCEPTION_(error_message, (jlong)func); 1.810 - } 1.811 - return (jlong)func; 1.812 -} 1.813 - 1.814 -/* signature of decode_instructions_virtual from hsdis.h */ 1.815 -typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, 1.816 - unsigned char* start, uintptr_t length, 1.817 - void* (*event_callback)(void*, const char*, void*), 1.818 - void* event_stream, 1.819 - int (*printf_callback)(void*, const char*, ...), 1.820 - void* printf_stream, 1.821 - const char* options); 1.822 - 1.823 -/* container for call back state when decoding instructions */ 1.824 -typedef struct { 1.825 - JNIEnv* env; 1.826 - jobject dis; 1.827 - jobject visitor; 1.828 - jmethodID handle_event; 1.829 - jmethodID raw_print; 1.830 - char buffer[4096]; 1.831 -} decode_env; 1.832 - 1.833 - 1.834 -/* event callback binding to Disassembler.handleEvent */ 1.835 -static void* event_to_env(void* env_pv, const char* event, void* arg) { 1.836 - decode_env* denv = (decode_env*)env_pv; 1.837 - JNIEnv* env = denv->env; 1.838 - jstring event_string = (*env)->NewStringUTF(env, event); 1.839 - jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor, 1.840 - event_string, (jlong) (uintptr_t)arg); 1.841 - /* ignore exceptions for now */ 1.842 - CHECK_EXCEPTION_CLEAR_((void *)0); 1.843 - return (void*)(uintptr_t)result; 1.844 -} 1.845 - 1.846 -/* printing callback binding to Disassembler.rawPrint */ 1.847 -static int printf_to_env(void* env_pv, const char* format, ...) { 1.848 - jstring output; 1.849 - va_list ap; 1.850 - int cnt; 1.851 - decode_env* denv = (decode_env*)env_pv; 1.852 - JNIEnv* env = denv->env; 1.853 - size_t flen = strlen(format); 1.854 - const char* raw = NULL; 1.855 - 1.856 - if (flen == 0) return 0; 1.857 - if (flen < 2 || 1.858 - strchr(format, '%') == NULL) { 1.859 - raw = format; 1.860 - } else if (format[0] == '%' && format[1] == '%' && 1.861 - strchr(format+2, '%') == NULL) { 1.862 - // happens a lot on machines with names like %foo 1.863 - flen--; 1.864 - raw = format+1; 1.865 - } 1.866 - if (raw != NULL) { 1.867 - jstring output = (*env)->NewStringUTF(env, raw); 1.868 - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); 1.869 - CHECK_EXCEPTION_CLEAR; 1.870 - return (int) flen; 1.871 - } 1.872 - va_start(ap, format); 1.873 - cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap); 1.874 - va_end(ap); 1.875 - 1.876 - output = (*env)->NewStringUTF(env, denv->buffer); 1.877 - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); 1.878 - CHECK_EXCEPTION_CLEAR; 1.879 - return cnt; 1.880 -} 1.881 - 1.882 -/* 1.883 - * Class: sun_jvm_hotspot_asm_Disassembler 1.884 - * Method: decode 1.885 - * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V 1.886 - */ 1.887 -JNIEXPORT void JNICALL 1.888 -Java_sun_jvm_hotspot_asm_Disassembler_decode( 1.889 - JNIEnv * env, 1.890 - jobject dis, 1.891 - jobject visitor, 1.892 - jlong startPc, 1.893 - jbyteArray code, 1.894 - jstring options_s, 1.895 - jlong decode_instructions_virtual) 1.896 -{ 1.897 - jboolean isCopy; 1.898 - jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy); 1.899 - jbyte* end = start + (*env)->GetArrayLength(env, code); 1.900 - const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy); 1.901 - jclass disclass = (*env)->GetObjectClass(env, dis); 1.902 - 1.903 - decode_env denv; 1.904 - denv.env = env; 1.905 - denv.dis = dis; 1.906 - denv.visitor = visitor; 1.907 - 1.908 - /* find Disassembler.handleEvent callback */ 1.909 - denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent", 1.910 - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J"); 1.911 - CHECK_EXCEPTION_CLEAR_VOID 1.912 - 1.913 - /* find Disassembler.rawPrint callback */ 1.914 - denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint", 1.915 - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V"); 1.916 - CHECK_EXCEPTION_CLEAR_VOID 1.917 - 1.918 - /* decode the buffer */ 1.919 - (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc, 1.920 - startPc + end - start, 1.921 - (unsigned char*)start, 1.922 - end - start, 1.923 - &event_to_env, (void*) &denv, 1.924 - &printf_to_env, (void*) &denv, 1.925 - options); 1.926 - 1.927 - /* cleanup */ 1.928 - (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); 1.929 - (*env)->ReleaseStringUTFChars(env, options_s, options); 1.930 -}
2.1 --- a/agent/src/os/bsd/Makefile Fri Mar 15 11:44:33 2013 -0700 2.2 +++ b/agent/src/os/bsd/Makefile Sun Mar 17 08:57:56 2013 -0700 2.3 @@ -1,5 +1,5 @@ 2.4 # 2.5 -# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. 2.6 +# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 2.7 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 # 2.9 # This code is free software; you can redistribute it and/or modify it 2.10 @@ -22,34 +22,60 @@ 2.11 # 2.12 # 2.13 2.14 -ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) 2.15 +ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) 2.16 + 2.17 +OS := $(shell uname -s) 2.18 + 2.19 GCC = gcc 2.20 2.21 JAVAH = ${JAVA_HOME}/bin/javah 2.22 2.23 +ifneq ($(OS), Darwin) 2.24 SOURCES = salibelf.c \ 2.25 symtab.c \ 2.26 libproc_impl.c \ 2.27 ps_proc.c \ 2.28 ps_core.c \ 2.29 BsdDebuggerLocal.c 2.30 - 2.31 -INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") 2.32 - 2.33 -OBJS = $(SOURCES:.c=.o) 2.34 +OBJS = $(SOURCES:.c=.o) 2.35 +OBJSPLUS = $(OBJS) sadis.o 2.36 +LIBSA = $(ARCH)/libsaproc.so 2.37 2.38 LIBS = -lutil -lthread_db 2.39 2.40 -CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) 2.41 +else 2.42 2.43 -LIBSA = $(ARCH)/libsaproc.so 2.44 +SOURCES = symtab.c \ 2.45 + libproc_impl.c \ 2.46 + ps_core.c 2.47 +OBJS = $(SOURCES:.c=.o) 2.48 +OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS) 2.49 +EXTINCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers -I. 2.50 +EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation 2.51 +FOUNDATIONFLAGS = -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation 2.52 +LIBSA = $(ARCH)/libsaproc.dylib 2.53 +endif # Darwin 2.54 + 2.55 +INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") $(EXTINCLUDE) 2.56 + 2.57 + 2.58 + 2.59 +CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) $(EXTCFLAGS) 2.60 + 2.61 + 2.62 2.63 all: $(LIBSA) 2.64 2.65 -BsdDebuggerLocal.o: BsdDebuggerLocal.c 2.66 - $(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \ 2.67 +MacosxDebuggerLocal.o: MacosxDebuggerLocal.m 2.68 + echo "OS="$(OS) 2.69 + $(JAVAH) -jni -classpath ../../../build/classes \ 2.70 sun.jvm.hotspot.debugger.x86.X86ThreadContext \ 2.71 sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext 2.72 + $(GCC) $(CFLAGS) $(FOUNDATIONFLAGS) $< 2.73 + 2.74 +sadis.o: ../../share/native/sadis.c 2.75 + $(JAVAH) -jni -classpath ../../../build/classes \ 2.76 + sun.jvm.hotspot.asm.Disassembler 2.77 $(GCC) $(CFLAGS) $< 2.78 2.79 .c.obj: 2.80 @@ -59,9 +85,9 @@ 2.81 LFLAGS_LIBSA = -Xlinker --version-script=mapfile 2.82 endif 2.83 2.84 -$(LIBSA): $(OBJS) mapfile 2.85 +$(LIBSA): $(OBJSPLUS) mapfile 2.86 if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi 2.87 - $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS) 2.88 + $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(FOUNDATIONFLAGS) $(OBJSPLUS) $(LIBS) $(SALIBS) 2.89 2.90 test.o: $(LIBSA) test.c 2.91 $(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c 2.92 @@ -71,7 +97,6 @@ 2.93 2.94 clean: 2.95 rm -f $(LIBSA) 2.96 - rm -f $(OBJS) 2.97 + rm -f *.o 2.98 rm -f test.o 2.99 -rmdir $(ARCH) 2.100 -
3.1 --- a/agent/src/os/bsd/libproc.h Fri Mar 15 11:44:33 2013 -0700 3.2 +++ b/agent/src/os/bsd/libproc.h Sun Mar 17 08:57:56 2013 -0700 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -27,9 +27,38 @@ 3.11 3.12 #include <unistd.h> 3.13 #include <stdint.h> 3.14 +#include <stdarg.h> 3.15 +#include <stdio.h> 3.16 +#include <stdlib.h> 3.17 +#include <string.h> 3.18 +#include <fcntl.h> 3.19 + 3.20 +#ifdef __APPLE__ 3.21 +typedef enum ps_err_e { 3.22 + PS_OK, PS_ERR, PS_BADPID, PS_BADLID, 3.23 + PS_BADADDR, PS_NOSYM, PS_NOFREGS 3.24 +} ps_err_e; 3.25 + 3.26 +#ifndef psaddr_t 3.27 +#define psaddr_t uintptr_t 3.28 +#endif 3.29 + 3.30 +#ifndef bool 3.31 +typedef int bool; 3.32 +#define true 1 3.33 +#define false 0 3.34 +#endif // bool 3.35 + 3.36 +#ifndef lwpid_t 3.37 +#define lwpid_t uintptr_t 3.38 +#endif 3.39 + 3.40 +#include <mach/thread_status.h> 3.41 +#else // __APPLE__ 3.42 +#include <elf.h> 3.43 +#include <link.h> 3.44 #include <machine/reg.h> 3.45 #include <proc_service.h> 3.46 - 3.47 #if defined(sparc) || defined(sparcv9) 3.48 /* 3.49 If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64 3.50 @@ -44,6 +73,14 @@ 3.51 3.52 #endif //sparc or sparcv9 3.53 3.54 +// This C bool type must be int for compatibility with BSD calls and 3.55 +// it would be a mistake to equivalence it to C++ bool on many platforms 3.56 +typedef int bool; 3.57 +#define true 1 3.58 +#define false 0 3.59 + 3.60 +#endif // __APPLE__ 3.61 + 3.62 /************************************************************************************ 3.63 3.64 0. This is very minimal subset of Solaris libproc just enough for current application. 3.65 @@ -72,13 +109,7 @@ 3.66 3.67 *************************************************************************************/ 3.68 3.69 -// This C bool type must be int for compatibility with BSD calls and 3.70 -// it would be a mistake to equivalence it to C++ bool on many platforms 3.71 - 3.72 -typedef int bool; 3.73 -#define true 1 3.74 -#define false 0 3.75 - 3.76 +struct reg; 3.77 struct ps_prochandle; 3.78 3.79 // attach to a process
4.1 --- a/agent/src/os/bsd/libproc_impl.c Fri Mar 15 11:44:33 2013 -0700 4.2 +++ b/agent/src/os/bsd/libproc_impl.c Sun Mar 17 08:57:56 2013 -0700 4.3 @@ -21,12 +21,6 @@ 4.4 * questions. 4.5 * 4.6 */ 4.7 -#include <stdarg.h> 4.8 -#include <stdio.h> 4.9 -#include <stdlib.h> 4.10 -#include <string.h> 4.11 -#include <fcntl.h> 4.12 -#include <thread_db.h> 4.13 #include "libproc_impl.h" 4.14 4.15 static const char* alt_root = NULL; 4.16 @@ -34,61 +28,65 @@ 4.17 4.18 #define SA_ALTROOT "SA_ALTROOT" 4.19 4.20 +off_t ltell(int fd) { 4.21 + return lseek(fd, 0, SEEK_CUR); 4.22 +} 4.23 + 4.24 static void init_alt_root() { 4.25 - if (alt_root_len == -1) { 4.26 - alt_root = getenv(SA_ALTROOT); 4.27 - if (alt_root) { 4.28 - alt_root_len = strlen(alt_root); 4.29 - } else { 4.30 - alt_root_len = 0; 4.31 - } 4.32 - } 4.33 + if (alt_root_len == -1) { 4.34 + alt_root = getenv(SA_ALTROOT); 4.35 + if (alt_root) { 4.36 + alt_root_len = strlen(alt_root); 4.37 + } else { 4.38 + alt_root_len = 0; 4.39 + } 4.40 + } 4.41 } 4.42 4.43 int pathmap_open(const char* name) { 4.44 - int fd; 4.45 - char alt_path[PATH_MAX + 1]; 4.46 + int fd; 4.47 + char alt_path[PATH_MAX + 1]; 4.48 4.49 - init_alt_root(); 4.50 - fd = open(name, O_RDONLY); 4.51 - if (fd >= 0) { 4.52 + init_alt_root(); 4.53 + 4.54 + if (alt_root_len > 0) { 4.55 + strcpy(alt_path, alt_root); 4.56 + strcat(alt_path, name); 4.57 + fd = open(alt_path, O_RDONLY); 4.58 + if (fd >= 0) { 4.59 + print_debug("path %s substituted for %s\n", alt_path, name); 4.60 return fd; 4.61 - } 4.62 + } 4.63 4.64 - if (alt_root_len > 0) { 4.65 + if (strrchr(name, '/')) { 4.66 strcpy(alt_path, alt_root); 4.67 - strcat(alt_path, name); 4.68 + strcat(alt_path, strrchr(name, '/')); 4.69 fd = open(alt_path, O_RDONLY); 4.70 if (fd >= 0) { 4.71 - print_debug("path %s substituted for %s\n", alt_path, name); 4.72 - return fd; 4.73 + print_debug("path %s substituted for %s\n", alt_path, name); 4.74 + return fd; 4.75 } 4.76 - 4.77 - if (strrchr(name, '/')) { 4.78 - strcpy(alt_path, alt_root); 4.79 - strcat(alt_path, strrchr(name, '/')); 4.80 - fd = open(alt_path, O_RDONLY); 4.81 - if (fd >= 0) { 4.82 - print_debug("path %s substituted for %s\n", alt_path, name); 4.83 - return fd; 4.84 - } 4.85 - } 4.86 - } 4.87 - 4.88 - return -1; 4.89 + } 4.90 + } else { 4.91 + fd = open(name, O_RDONLY); 4.92 + if (fd >= 0) { 4.93 + return fd; 4.94 + } 4.95 + } 4.96 + return -1; 4.97 } 4.98 4.99 static bool _libsaproc_debug; 4.100 4.101 void print_debug(const char* format,...) { 4.102 - if (_libsaproc_debug) { 4.103 - va_list alist; 4.104 + if (_libsaproc_debug) { 4.105 + va_list alist; 4.106 4.107 - va_start(alist, format); 4.108 - fputs("libsaproc DEBUG: ", stderr); 4.109 - vfprintf(stderr, format, alist); 4.110 - va_end(alist); 4.111 - } 4.112 + va_start(alist, format); 4.113 + fputs("libsaproc DEBUG: ", stderr); 4.114 + vfprintf(stderr, format, alist); 4.115 + va_end(alist); 4.116 + } 4.117 } 4.118 4.119 void print_error(const char* format,...) { 4.120 @@ -100,172 +98,235 @@ 4.121 } 4.122 4.123 bool is_debug() { 4.124 - return _libsaproc_debug; 4.125 + return _libsaproc_debug; 4.126 } 4.127 4.128 +#ifdef __APPLE__ 4.129 +// get arch offset in file 4.130 +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) { 4.131 + struct fat_header fatheader; 4.132 + struct fat_arch fatarch; 4.133 + off_t img_start = 0; 4.134 + 4.135 + off_t pos = ltell(fd); 4.136 + if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) { 4.137 + return false; 4.138 + } 4.139 + if (fatheader.magic == FAT_CIGAM) { 4.140 + int i; 4.141 + for (i = 0; i < ntohl(fatheader.nfat_arch); i++) { 4.142 + if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) { 4.143 + return false; 4.144 + } 4.145 + if (ntohl(fatarch.cputype) == cputype) { 4.146 + print_debug("fat offset=%x\n", ntohl(fatarch.offset)); 4.147 + img_start = ntohl(fatarch.offset); 4.148 + break; 4.149 + } 4.150 + } 4.151 + if (img_start == 0) { 4.152 + return false; 4.153 + } 4.154 + } 4.155 + lseek(fd, pos, SEEK_SET); 4.156 + *offset = img_start; 4.157 + return true; 4.158 +} 4.159 + 4.160 +bool is_macho_file(int fd) { 4.161 + mach_header_64 fhdr; 4.162 + off_t x86_64_off; 4.163 + 4.164 + if (fd < 0) { 4.165 + print_debug("Invalid file handle passed to is_macho_file\n"); 4.166 + return false; 4.167 + } 4.168 + 4.169 + off_t pos = ltell(fd); 4.170 + // check fat header 4.171 + if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) { 4.172 + print_debug("failed to get fat header\n"); 4.173 + return false; 4.174 + } 4.175 + lseek(fd, x86_64_off, SEEK_SET); 4.176 + if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 4.177 + return false; 4.178 + } 4.179 + lseek(fd, pos, SEEK_SET); // restore 4.180 + print_debug("fhdr.magic %x\n", fhdr.magic); 4.181 + return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64); 4.182 +} 4.183 + 4.184 +#endif //__APPLE__ 4.185 + 4.186 // initialize libproc 4.187 bool init_libproc(bool debug) { 4.188 - // init debug mode 4.189 _libsaproc_debug = debug; 4.190 - 4.191 +#ifndef __APPLE__ 4.192 // initialize the thread_db library 4.193 if (td_init() != TD_OK) { 4.194 print_debug("libthread_db's td_init failed\n"); 4.195 return false; 4.196 } 4.197 - 4.198 +#endif // __APPLE__ 4.199 return true; 4.200 } 4.201 4.202 -static void destroy_lib_info(struct ps_prochandle* ph) { 4.203 - lib_info* lib = ph->libs; 4.204 - while (lib) { 4.205 - lib_info *next = lib->next; 4.206 - if (lib->symtab) { 4.207 - destroy_symtab(lib->symtab); 4.208 - } 4.209 - free(lib); 4.210 - lib = next; 4.211 - } 4.212 +void destroy_lib_info(struct ps_prochandle* ph) { 4.213 + lib_info* lib = ph->libs; 4.214 + while (lib) { 4.215 + lib_info* next = lib->next; 4.216 + if (lib->symtab) { 4.217 + destroy_symtab(lib->symtab); 4.218 + } 4.219 + free(lib); 4.220 + lib = next; 4.221 + } 4.222 } 4.223 4.224 -static void destroy_thread_info(struct ps_prochandle* ph) { 4.225 - thread_info* thr = ph->threads; 4.226 - while (thr) { 4.227 - thread_info *next = thr->next; 4.228 - free(thr); 4.229 - thr = next; 4.230 - } 4.231 +void destroy_thread_info(struct ps_prochandle* ph) { 4.232 + sa_thread_info* thr = ph->threads; 4.233 + while (thr) { 4.234 + sa_thread_info* n = thr->next; 4.235 + free(thr); 4.236 + thr = n; 4.237 + } 4.238 } 4.239 4.240 // ps_prochandle cleanup 4.241 - 4.242 -// ps_prochandle cleanup 4.243 void Prelease(struct ps_prochandle* ph) { 4.244 - // do the "derived class" clean-up first 4.245 - ph->ops->release(ph); 4.246 - destroy_lib_info(ph); 4.247 - destroy_thread_info(ph); 4.248 - free(ph); 4.249 + // do the "derived class" clean-up first 4.250 + ph->ops->release(ph); 4.251 + destroy_lib_info(ph); 4.252 + destroy_thread_info(ph); 4.253 + free(ph); 4.254 } 4.255 4.256 lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { 4.257 - return add_lib_info_fd(ph, libname, -1, base); 4.258 + return add_lib_info_fd(ph, libname, -1, base); 4.259 } 4.260 4.261 lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { 4.262 lib_info* newlib; 4.263 + print_debug("add_lib_info_fd %s\n", libname); 4.264 4.265 - if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 4.266 - print_debug("can't allocate memory for lib_info\n"); 4.267 - return NULL; 4.268 - } 4.269 + if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 4.270 + print_debug("can't allocate memory for lib_info\n"); 4.271 + return NULL; 4.272 + } 4.273 4.274 - strncpy(newlib->name, libname, sizeof(newlib->name)); 4.275 - newlib->base = base; 4.276 + strncpy(newlib->name, libname, sizeof(newlib->name)); 4.277 + newlib->base = base; 4.278 4.279 - if (fd == -1) { 4.280 - if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 4.281 - print_debug("can't open shared object %s\n", newlib->name); 4.282 - free(newlib); 4.283 - return NULL; 4.284 - } 4.285 - } else { 4.286 - newlib->fd = fd; 4.287 - } 4.288 - 4.289 - // check whether we have got an ELF file. /proc/<pid>/map 4.290 - // gives out all file mappings and not just shared objects 4.291 - if (is_elf_file(newlib->fd) == false) { 4.292 - close(newlib->fd); 4.293 + if (fd == -1) { 4.294 + if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 4.295 + print_debug("can't open shared object %s\n", newlib->name); 4.296 free(newlib); 4.297 return NULL; 4.298 - } 4.299 + } 4.300 + } else { 4.301 + newlib->fd = fd; 4.302 + } 4.303 4.304 - newlib->symtab = build_symtab(newlib->fd); 4.305 - if (newlib->symtab == NULL) { 4.306 - print_debug("symbol table build failed for %s\n", newlib->name); 4.307 - } 4.308 - else { 4.309 - print_debug("built symbol table for %s\n", newlib->name); 4.310 - } 4.311 +#ifdef __APPLE__ 4.312 + // check whether we have got an Macho file. 4.313 + if (is_macho_file(newlib->fd) == false) { 4.314 + close(newlib->fd); 4.315 + free(newlib); 4.316 + print_debug("not a mach-o file\n"); 4.317 + return NULL; 4.318 + } 4.319 +#else 4.320 + // check whether we have got an ELF file. /proc/<pid>/map 4.321 + // gives out all file mappings and not just shared objects 4.322 + if (is_elf_file(newlib->fd) == false) { 4.323 + close(newlib->fd); 4.324 + free(newlib); 4.325 + return NULL; 4.326 + } 4.327 +#endif // __APPLE__ 4.328 4.329 - // even if symbol table building fails, we add the lib_info. 4.330 - // This is because we may need to read from the ELF file for core file 4.331 - // address read functionality. lookup_symbol checks for NULL symtab. 4.332 - if (ph->libs) { 4.333 - ph->lib_tail->next = newlib; 4.334 - ph->lib_tail = newlib; 4.335 - } else { 4.336 - ph->libs = ph->lib_tail = newlib; 4.337 - } 4.338 - ph->num_libs++; 4.339 + newlib->symtab = build_symtab(newlib->fd); 4.340 + if (newlib->symtab == NULL) { 4.341 + print_debug("symbol table build failed for %s\n", newlib->name); 4.342 + } else { 4.343 + print_debug("built symbol table for %s\n", newlib->name); 4.344 + } 4.345 4.346 - return newlib; 4.347 + // even if symbol table building fails, we add the lib_info. 4.348 + // This is because we may need to read from the ELF file or MachO file for core file 4.349 + // address read functionality. lookup_symbol checks for NULL symtab. 4.350 + if (ph->libs) { 4.351 + ph->lib_tail->next = newlib; 4.352 + ph->lib_tail = newlib; 4.353 + } else { 4.354 + ph->libs = ph->lib_tail = newlib; 4.355 + } 4.356 + ph->num_libs++; 4.357 + return newlib; 4.358 } 4.359 4.360 // lookup for a specific symbol 4.361 uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, 4.362 const char* sym_name) { 4.363 - // ignore object_name. search in all libraries 4.364 - // FIXME: what should we do with object_name?? The library names are obtained 4.365 - // by parsing /proc/<pid>/maps, which may not be the same as object_name. 4.366 - // What we need is a utility to map object_name to real file name, something 4.367 - // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For 4.368 - // now, we just ignore object_name and do a global search for the symbol. 4.369 + // ignore object_name. search in all libraries 4.370 + // FIXME: what should we do with object_name?? The library names are obtained 4.371 + // by parsing /proc/<pid>/maps, which may not be the same as object_name. 4.372 + // What we need is a utility to map object_name to real file name, something 4.373 + // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For 4.374 + // now, we just ignore object_name and do a global search for the symbol. 4.375 4.376 - lib_info* lib = ph->libs; 4.377 - while (lib) { 4.378 - if (lib->symtab) { 4.379 - uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 4.380 - if (res) return res; 4.381 - } 4.382 - lib = lib->next; 4.383 - } 4.384 + lib_info* lib = ph->libs; 4.385 + while (lib) { 4.386 + if (lib->symtab) { 4.387 + uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 4.388 + if (res) return res; 4.389 + } 4.390 + lib = lib->next; 4.391 + } 4.392 4.393 - print_debug("lookup failed for symbol '%s' in obj '%s'\n", 4.394 + print_debug("lookup failed for symbol '%s' in obj '%s'\n", 4.395 sym_name, object_name); 4.396 - return (uintptr_t) NULL; 4.397 + return (uintptr_t) NULL; 4.398 } 4.399 4.400 - 4.401 const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { 4.402 - const char* res = NULL; 4.403 - lib_info* lib = ph->libs; 4.404 - while (lib) { 4.405 - if (lib->symtab && addr >= lib->base) { 4.406 - res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 4.407 - if (res) return res; 4.408 - } 4.409 - lib = lib->next; 4.410 - } 4.411 - return NULL; 4.412 + const char* res = NULL; 4.413 + lib_info* lib = ph->libs; 4.414 + while (lib) { 4.415 + if (lib->symtab && addr >= lib->base) { 4.416 + res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 4.417 + if (res) return res; 4.418 + } 4.419 + lib = lib->next; 4.420 + } 4.421 + return NULL; 4.422 } 4.423 4.424 // add a thread to ps_prochandle 4.425 -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 4.426 - thread_info* newthr; 4.427 - if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { 4.428 - print_debug("can't allocate memory for thread_info\n"); 4.429 - return NULL; 4.430 - } 4.431 +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 4.432 + sa_thread_info* newthr; 4.433 + if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { 4.434 + print_debug("can't allocate memory for thread_info\n"); 4.435 + return NULL; 4.436 + } 4.437 4.438 - // initialize thread info 4.439 - newthr->pthread_id = pthread_id; 4.440 - newthr->lwp_id = lwp_id; 4.441 + // initialize thread info 4.442 + newthr->pthread_id = pthread_id; 4.443 + newthr->lwp_id = lwp_id; 4.444 4.445 - // add new thread to the list 4.446 - newthr->next = ph->threads; 4.447 - ph->threads = newthr; 4.448 - ph->num_threads++; 4.449 - return newthr; 4.450 + // add new thread to the list 4.451 + newthr->next = ph->threads; 4.452 + ph->threads = newthr; 4.453 + ph->num_threads++; 4.454 + return newthr; 4.455 } 4.456 4.457 - 4.458 +#ifndef __APPLE__ 4.459 // struct used for client data from thread_db callback 4.460 struct thread_db_client_data { 4.461 - struct ps_prochandle* ph; 4.462 - thread_info_callback callback; 4.463 + struct ps_prochandle* ph; 4.464 + thread_info_callback callback; 4.465 }; 4.466 4.467 // callback function for libthread_db 4.468 @@ -314,6 +375,7 @@ 4.469 return true; 4.470 } 4.471 4.472 +#endif // __APPLE__ 4.473 4.474 // get number of threads 4.475 int get_num_threads(struct ps_prochandle* ph) { 4.476 @@ -322,18 +384,54 @@ 4.477 4.478 // get lwp_id of n'th thread 4.479 lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { 4.480 - int count = 0; 4.481 - thread_info* thr = ph->threads; 4.482 - while (thr) { 4.483 - if (count == index) { 4.484 - return thr->lwp_id; 4.485 - } 4.486 - count++; 4.487 - thr = thr->next; 4.488 - } 4.489 - return -1; 4.490 + int count = 0; 4.491 + sa_thread_info* thr = ph->threads; 4.492 + while (thr) { 4.493 + if (count == index) { 4.494 + return thr->lwp_id; 4.495 + } 4.496 + count++; 4.497 + thr = thr->next; 4.498 + } 4.499 + return 0; 4.500 } 4.501 4.502 +#ifdef __APPLE__ 4.503 +// set lwp_id of n'th thread 4.504 +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) { 4.505 + int count = 0; 4.506 + sa_thread_info* thr = ph->threads; 4.507 + while (thr) { 4.508 + if (count == index) { 4.509 + thr->lwp_id = lwpid; 4.510 + return true; 4.511 + } 4.512 + count++; 4.513 + thr = thr->next; 4.514 + } 4.515 + return false; 4.516 +} 4.517 + 4.518 +// get regs of n-th thread, only used in fillThreads the first time called 4.519 +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) { 4.520 + int count = 0; 4.521 + sa_thread_info* thr = ph->threads; 4.522 + while (thr) { 4.523 + if (count == index) { 4.524 + break; 4.525 + } 4.526 + count++; 4.527 + thr = thr->next; 4.528 + } 4.529 + if (thr != NULL) { 4.530 + memcpy(regs, &thr->regs, sizeof(struct reg)); 4.531 + return true; 4.532 + } 4.533 + return false; 4.534 +} 4.535 + 4.536 +#endif // __APPLE__ 4.537 + 4.538 // get regs for a given lwp 4.539 bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { 4.540 return ph->ops->get_lwp_regs(ph, lwp_id, regs); 4.541 @@ -341,35 +439,35 @@ 4.542 4.543 // get number of shared objects 4.544 int get_num_libs(struct ps_prochandle* ph) { 4.545 - return ph->num_libs; 4.546 + return ph->num_libs; 4.547 } 4.548 4.549 // get name of n'th solib 4.550 const char* get_lib_name(struct ps_prochandle* ph, int index) { 4.551 - int count = 0; 4.552 - lib_info* lib = ph->libs; 4.553 - while (lib) { 4.554 - if (count == index) { 4.555 - return lib->name; 4.556 - } 4.557 - count++; 4.558 - lib = lib->next; 4.559 - } 4.560 - return NULL; 4.561 + int count = 0; 4.562 + lib_info* lib = ph->libs; 4.563 + while (lib) { 4.564 + if (count == index) { 4.565 + return lib->name; 4.566 + } 4.567 + count++; 4.568 + lib = lib->next; 4.569 + } 4.570 + return NULL; 4.571 } 4.572 4.573 // get base address of a lib 4.574 uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { 4.575 - int count = 0; 4.576 - lib_info* lib = ph->libs; 4.577 - while (lib) { 4.578 - if (count == index) { 4.579 - return lib->base; 4.580 - } 4.581 - count++; 4.582 - lib = lib->next; 4.583 - } 4.584 - return (uintptr_t)NULL; 4.585 + int count = 0; 4.586 + lib_info* lib = ph->libs; 4.587 + while (lib) { 4.588 + if (count == index) { 4.589 + return lib->base; 4.590 + } 4.591 + count++; 4.592 + lib = lib->next; 4.593 + } 4.594 + return (uintptr_t)NULL; 4.595 } 4.596 4.597 bool find_lib(struct ps_prochandle* ph, const char *lib_name) { 4.598 @@ -425,6 +523,7 @@ 4.599 va_end(alist); 4.600 } 4.601 4.602 +#ifndef __APPLE__ 4.603 // ------------------------------------------------------------------------ 4.604 // Functions below this point are not yet implemented. They are here only 4.605 // to make the linker happy. 4.606 @@ -458,3 +557,4 @@ 4.607 print_debug("ps_pcontinue not implemented\n"); 4.608 return PS_OK; 4.609 } 4.610 +#endif // __APPLE__
5.1 --- a/agent/src/os/bsd/libproc_impl.h Fri Mar 15 11:44:33 2013 -0700 5.2 +++ b/agent/src/os/bsd/libproc_impl.h Sun Mar 17 08:57:56 2013 -0700 5.3 @@ -30,6 +30,60 @@ 5.4 #include "libproc.h" 5.5 #include "symtab.h" 5.6 5.7 +#ifdef __APPLE__ 5.8 +#include <inttypes.h> // for PRIx64, 32, ... 5.9 +#include <pthread.h> 5.10 +#include <mach-o/loader.h> 5.11 +#include <mach-o/nlist.h> 5.12 +#include <mach-o/fat.h> 5.13 + 5.14 +#ifndef register_t 5.15 +#define register_t uint64_t 5.16 +#endif 5.17 + 5.18 +/*** registers copied from bsd/amd64 */ 5.19 +typedef struct reg { 5.20 + register_t r_r15; 5.21 + register_t r_r14; 5.22 + register_t r_r13; 5.23 + register_t r_r12; 5.24 + register_t r_r11; 5.25 + register_t r_r10; 5.26 + register_t r_r9; 5.27 + register_t r_r8; 5.28 + register_t r_rdi; 5.29 + register_t r_rsi; 5.30 + register_t r_rbp; 5.31 + register_t r_rbx; 5.32 + register_t r_rdx; 5.33 + register_t r_rcx; 5.34 + register_t r_rax; 5.35 + uint32_t r_trapno; // not used 5.36 + uint16_t r_fs; 5.37 + uint16_t r_gs; 5.38 + uint32_t r_err; // not used 5.39 + uint16_t r_es; // not used 5.40 + uint16_t r_ds; // not used 5.41 + register_t r_rip; 5.42 + register_t r_cs; 5.43 + register_t r_rflags; 5.44 + register_t r_rsp; 5.45 + register_t r_ss; // not used 5.46 +} reg; 5.47 + 5.48 +// convenient defs 5.49 +typedef struct mach_header_64 mach_header_64; 5.50 +typedef struct load_command load_command; 5.51 +typedef struct segment_command_64 segment_command_64; 5.52 +typedef struct thread_command thread_command; 5.53 +typedef struct dylib_command dylib_command; 5.54 +typedef struct symtab_command symtab_command; 5.55 +typedef struct nlist_64 nlist_64; 5.56 +#else 5.57 +#include <thread_db.h> 5.58 +#include "salibelf.h" 5.59 +#endif // __APPLE__ 5.60 + 5.61 // data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h 5.62 5.63 #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) 5.64 @@ -44,12 +98,12 @@ 5.65 } lib_info; 5.66 5.67 // list of threads 5.68 -typedef struct thread_info { 5.69 - lwpid_t lwp_id; 5.70 - pthread_t pthread_id; // not used cores, always -1 5.71 +typedef struct sa_thread_info { 5.72 + lwpid_t lwp_id; // same as pthread_t 5.73 + pthread_t pthread_id; // 5.74 struct reg regs; // not for process, core uses for caching regset 5.75 - struct thread_info* next; 5.76 -} thread_info; 5.77 + struct sa_thread_info* next; 5.78 +} sa_thread_info; 5.79 5.80 // list of virtual memory maps 5.81 typedef struct map_info { 5.82 @@ -91,6 +145,7 @@ 5.83 // part of the class sharing workaround 5.84 map_info* class_share_maps;// class share maps in a linked list 5.85 map_info** map_array; // sorted (by vaddr) array of map_info pointers 5.86 + char exec_path[4096]; // file name java 5.87 }; 5.88 5.89 struct ps_prochandle { 5.90 @@ -100,12 +155,11 @@ 5.91 lib_info* libs; // head of lib list 5.92 lib_info* lib_tail; // tail of lib list - to append at the end 5.93 int num_threads; 5.94 - thread_info* threads; // head of thread list 5.95 + sa_thread_info* threads; // head of thread list 5.96 struct core_data* core; // data only used for core dumps, NULL for process 5.97 }; 5.98 5.99 int pathmap_open(const char* name); 5.100 - 5.101 void print_debug(const char* format,...); 5.102 void print_error(const char* format,...); 5.103 bool is_debug(); 5.104 @@ -122,10 +176,45 @@ 5.105 lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, 5.106 uintptr_t base); 5.107 5.108 -// adds a new thread to threads list, returns NULL on failure 5.109 -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); 5.110 +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); 5.111 +// a test for ELF signature without using libelf 5.112 5.113 -// a test for ELF signature without using libelf 5.114 +#ifdef __APPLE__ 5.115 +// a test for Mach-O signature 5.116 +bool is_macho_file(int fd); 5.117 +// skip fat head to get image start offset of cpu_type_t 5.118 +// return false if any error happens, else value in offset. 5.119 +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset); 5.120 +#else 5.121 bool is_elf_file(int fd); 5.122 +#endif // __APPLE__ 5.123 5.124 +lwpid_t get_lwp_id(struct ps_prochandle* ph, int index); 5.125 +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid); 5.126 +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs); 5.127 + 5.128 +// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table 5.129 +// of the load object object_name in the target process identified by ph. 5.130 +// It returns the symbol's value as an address in the target process in 5.131 +// *sym_addr. 5.132 + 5.133 +ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, 5.134 + const char *sym_name, psaddr_t *sym_addr); 5.135 + 5.136 +// read "size" bytes info "buf" from address "addr" 5.137 +ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr, 5.138 + void *buf, size_t size); 5.139 + 5.140 +// write "size" bytes of data to debuggee at address "addr" 5.141 +ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, 5.142 + const void *buf, size_t size); 5.143 + 5.144 +// fill in ptrace_lwpinfo for lid 5.145 +ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo); 5.146 + 5.147 +// needed for when libthread_db is compiled with TD_DEBUG defined 5.148 +void ps_plog (const char *format, ...); 5.149 + 5.150 +// untility, tells the position in file 5.151 +off_t ltell(int fd); 5.152 #endif //_LIBPROC_IMPL_H_
6.1 --- a/agent/src/os/bsd/ps_core.c Fri Mar 15 11:44:33 2013 -0700 6.2 +++ b/agent/src/os/bsd/ps_core.c Sun Mar 17 08:57:56 2013 -0700 6.3 @@ -1,5 +1,5 @@ 6.4 /* 6.5 - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 6.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 6.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.8 * 6.9 * This code is free software; you can redistribute it and/or modify it 6.10 @@ -28,10 +28,11 @@ 6.11 #include <string.h> 6.12 #include <stdlib.h> 6.13 #include <stddef.h> 6.14 -#include <elf.h> 6.15 -#include <link.h> 6.16 #include "libproc_impl.h" 6.17 -#include "salibelf.h" 6.18 + 6.19 +#ifdef __APPLE__ 6.20 +#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" 6.21 +#endif 6.22 6.23 // This file has the libproc implementation to read core files. 6.24 // For live processes, refer to ps_proc.c. Portions of this is adapted 6.25 @@ -41,156 +42,158 @@ 6.26 // ps_prochandle cleanup helper functions 6.27 6.28 // close all file descriptors 6.29 -static void close_elf_files(struct ps_prochandle* ph) { 6.30 - lib_info* lib = NULL; 6.31 +static void close_files(struct ps_prochandle* ph) { 6.32 + lib_info* lib = NULL; 6.33 + // close core file descriptor 6.34 + if (ph->core->core_fd >= 0) 6.35 + close(ph->core->core_fd); 6.36 6.37 - // close core file descriptor 6.38 - if (ph->core->core_fd >= 0) 6.39 - close(ph->core->core_fd); 6.40 + // close exec file descriptor 6.41 + if (ph->core->exec_fd >= 0) 6.42 + close(ph->core->exec_fd); 6.43 6.44 - // close exec file descriptor 6.45 - if (ph->core->exec_fd >= 0) 6.46 - close(ph->core->exec_fd); 6.47 + // close interp file descriptor 6.48 + if (ph->core->interp_fd >= 0) 6.49 + close(ph->core->interp_fd); 6.50 6.51 - // close interp file descriptor 6.52 - if (ph->core->interp_fd >= 0) 6.53 - close(ph->core->interp_fd); 6.54 + // close class share archive file 6.55 + if (ph->core->classes_jsa_fd >= 0) 6.56 + close(ph->core->classes_jsa_fd); 6.57 6.58 - // close class share archive file 6.59 - if (ph->core->classes_jsa_fd >= 0) 6.60 - close(ph->core->classes_jsa_fd); 6.61 - 6.62 - // close all library file descriptors 6.63 - lib = ph->libs; 6.64 - while (lib) { 6.65 - int fd = lib->fd; 6.66 - if (fd >= 0 && fd != ph->core->exec_fd) close(fd); 6.67 - lib = lib->next; 6.68 - } 6.69 + // close all library file descriptors 6.70 + lib = ph->libs; 6.71 + while (lib) { 6.72 + int fd = lib->fd; 6.73 + if (fd >= 0 && fd != ph->core->exec_fd) { 6.74 + close(fd); 6.75 + } 6.76 + lib = lib->next; 6.77 + } 6.78 } 6.79 6.80 // clean all map_info stuff 6.81 static void destroy_map_info(struct ps_prochandle* ph) { 6.82 map_info* map = ph->core->maps; 6.83 while (map) { 6.84 - map_info* next = map->next; 6.85 - free(map); 6.86 - map = next; 6.87 + map_info* next = map->next; 6.88 + free(map); 6.89 + map = next; 6.90 } 6.91 6.92 if (ph->core->map_array) { 6.93 - free(ph->core->map_array); 6.94 + free(ph->core->map_array); 6.95 } 6.96 6.97 // Part of the class sharing workaround 6.98 map = ph->core->class_share_maps; 6.99 while (map) { 6.100 - map_info* next = map->next; 6.101 - free(map); 6.102 - map = next; 6.103 + map_info* next = map->next; 6.104 + free(map); 6.105 + map = next; 6.106 } 6.107 } 6.108 6.109 // ps_prochandle operations 6.110 static void core_release(struct ps_prochandle* ph) { 6.111 - if (ph->core) { 6.112 - close_elf_files(ph); 6.113 - destroy_map_info(ph); 6.114 - free(ph->core); 6.115 - } 6.116 + if (ph->core) { 6.117 + close_files(ph); 6.118 + destroy_map_info(ph); 6.119 + free(ph->core); 6.120 + } 6.121 } 6.122 6.123 static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) { 6.124 - map_info* map; 6.125 - if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { 6.126 - print_debug("can't allocate memory for map_info\n"); 6.127 - return NULL; 6.128 - } 6.129 + map_info* map; 6.130 + if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { 6.131 + print_debug("can't allocate memory for map_info\n"); 6.132 + return NULL; 6.133 + } 6.134 6.135 - // initialize map 6.136 - map->fd = fd; 6.137 - map->offset = offset; 6.138 - map->vaddr = vaddr; 6.139 - map->memsz = memsz; 6.140 - return map; 6.141 + // initialize map 6.142 + map->fd = fd; 6.143 + map->offset = offset; 6.144 + map->vaddr = vaddr; 6.145 + map->memsz = memsz; 6.146 + return map; 6.147 } 6.148 6.149 // add map info with given fd, offset, vaddr and memsz 6.150 static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, 6.151 uintptr_t vaddr, size_t memsz) { 6.152 - map_info* map; 6.153 - if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { 6.154 - return NULL; 6.155 - } 6.156 + map_info* map; 6.157 + if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { 6.158 + return NULL; 6.159 + } 6.160 6.161 - // add this to map list 6.162 - map->next = ph->core->maps; 6.163 - ph->core->maps = map; 6.164 - ph->core->num_maps++; 6.165 + // add this to map list 6.166 + map->next = ph->core->maps; 6.167 + ph->core->maps = map; 6.168 + ph->core->num_maps++; 6.169 6.170 - return map; 6.171 + return map; 6.172 } 6.173 6.174 // Part of the class sharing workaround 6.175 static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, 6.176 uintptr_t vaddr, size_t memsz) { 6.177 - map_info* map; 6.178 - if ((map = allocate_init_map(ph->core->classes_jsa_fd, 6.179 - offset, vaddr, memsz)) == NULL) { 6.180 - return NULL; 6.181 - } 6.182 + map_info* map; 6.183 + if ((map = allocate_init_map(ph->core->classes_jsa_fd, 6.184 + offset, vaddr, memsz)) == NULL) { 6.185 + return NULL; 6.186 + } 6.187 6.188 - map->next = ph->core->class_share_maps; 6.189 - ph->core->class_share_maps = map; 6.190 - return map; 6.191 + map->next = ph->core->class_share_maps; 6.192 + ph->core->class_share_maps = map; 6.193 + return map; 6.194 } 6.195 6.196 // Return the map_info for the given virtual address. We keep a sorted 6.197 // array of pointers in ph->map_array, so we can binary search. 6.198 static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) 6.199 { 6.200 - int mid, lo = 0, hi = ph->core->num_maps - 1; 6.201 - map_info *mp; 6.202 + int mid, lo = 0, hi = ph->core->num_maps - 1; 6.203 + map_info *mp; 6.204 6.205 - while (hi - lo > 1) { 6.206 - mid = (lo + hi) / 2; 6.207 - if (addr >= ph->core->map_array[mid]->vaddr) 6.208 - lo = mid; 6.209 - else 6.210 - hi = mid; 6.211 - } 6.212 + while (hi - lo > 1) { 6.213 + mid = (lo + hi) / 2; 6.214 + if (addr >= ph->core->map_array[mid]->vaddr) { 6.215 + lo = mid; 6.216 + } else { 6.217 + hi = mid; 6.218 + } 6.219 + } 6.220 6.221 - if (addr < ph->core->map_array[hi]->vaddr) 6.222 - mp = ph->core->map_array[lo]; 6.223 - else 6.224 - mp = ph->core->map_array[hi]; 6.225 + if (addr < ph->core->map_array[hi]->vaddr) { 6.226 + mp = ph->core->map_array[lo]; 6.227 + } else { 6.228 + mp = ph->core->map_array[hi]; 6.229 + } 6.230 6.231 - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) 6.232 + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { 6.233 + return (mp); 6.234 + } 6.235 + 6.236 + 6.237 + // Part of the class sharing workaround 6.238 + // Unfortunately, we have no way of detecting -Xshare state. 6.239 + // Check out the share maps atlast, if we don't find anywhere. 6.240 + // This is done this way so to avoid reading share pages 6.241 + // ahead of other normal maps. For eg. with -Xshare:off we don't 6.242 + // want to prefer class sharing data to data from core. 6.243 + mp = ph->core->class_share_maps; 6.244 + if (mp) { 6.245 + print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); 6.246 + } 6.247 + while (mp) { 6.248 + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { 6.249 + print_debug("located map_info at 0x%lx from class share maps\n", addr); 6.250 return (mp); 6.251 + } 6.252 + mp = mp->next; 6.253 + } 6.254 6.255 - 6.256 - // Part of the class sharing workaround 6.257 - // Unfortunately, we have no way of detecting -Xshare state. 6.258 - // Check out the share maps atlast, if we don't find anywhere. 6.259 - // This is done this way so to avoid reading share pages 6.260 - // ahead of other normal maps. For eg. with -Xshare:off we don't 6.261 - // want to prefer class sharing data to data from core. 6.262 - mp = ph->core->class_share_maps; 6.263 - if (mp) { 6.264 - print_debug("can't locate map_info at 0x%lx, trying class share maps\n", 6.265 - addr); 6.266 - } 6.267 - while (mp) { 6.268 - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { 6.269 - print_debug("located map_info at 0x%lx from class share maps\n", 6.270 - addr); 6.271 - return (mp); 6.272 - } 6.273 - mp = mp->next; 6.274 - } 6.275 - 6.276 - print_debug("can't locate map_info at 0x%lx\n", addr); 6.277 - return (NULL); 6.278 + print_debug("can't locate map_info at 0x%lx\n", addr); 6.279 + return (NULL); 6.280 } 6.281 6.282 //--------------------------------------------------------------- 6.283 @@ -239,157 +242,171 @@ 6.284 }; 6.285 6.286 static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { 6.287 - jboolean i; 6.288 - if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { 6.289 - *pvalue = i; 6.290 - return true; 6.291 - } else { 6.292 - return false; 6.293 - } 6.294 + jboolean i; 6.295 + if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { 6.296 + *pvalue = i; 6.297 + return true; 6.298 + } else { 6.299 + return false; 6.300 + } 6.301 } 6.302 6.303 static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { 6.304 - uintptr_t uip; 6.305 - if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) { 6.306 - *pvalue = uip; 6.307 - return true; 6.308 - } else { 6.309 - return false; 6.310 - } 6.311 + uintptr_t uip; 6.312 + if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { 6.313 + *pvalue = uip; 6.314 + return true; 6.315 + } else { 6.316 + return false; 6.317 + } 6.318 } 6.319 6.320 // used to read strings from debuggee 6.321 static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { 6.322 - size_t i = 0; 6.323 - char c = ' '; 6.324 + size_t i = 0; 6.325 + char c = ' '; 6.326 6.327 - while (c != '\0') { 6.328 - if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) 6.329 - return false; 6.330 - if (i < size - 1) 6.331 - buf[i] = c; 6.332 - else // smaller buffer 6.333 - return false; 6.334 - i++; addr++; 6.335 - } 6.336 - 6.337 - buf[i] = '\0'; 6.338 - return true; 6.339 + while (c != '\0') { 6.340 + if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { 6.341 + return false; 6.342 + } 6.343 + if (i < size - 1) { 6.344 + buf[i] = c; 6.345 + } else { 6.346 + // smaller buffer 6.347 + return false; 6.348 + } 6.349 + i++; addr++; 6.350 + } 6.351 + buf[i] = '\0'; 6.352 + return true; 6.353 } 6.354 6.355 +#ifdef __APPLE__ 6.356 +#define USE_SHARED_SPACES_SYM "_UseSharedSpaces" 6.357 +// mangled name of Arguments::SharedArchivePath 6.358 +#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" 6.359 +#else 6.360 #define USE_SHARED_SPACES_SYM "UseSharedSpaces" 6.361 // mangled name of Arguments::SharedArchivePath 6.362 -#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" 6.363 +#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" 6.364 +#endif // __APPLE_ 6.365 6.366 static bool init_classsharing_workaround(struct ps_prochandle* ph) { 6.367 - lib_info* lib = ph->libs; 6.368 - while (lib != NULL) { 6.369 - // we are iterating over shared objects from the core dump. look for 6.370 - // libjvm[_g].so. 6.371 - const char *jvm_name = 0; 6.372 - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || 6.373 - (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) { 6.374 - char classes_jsa[PATH_MAX]; 6.375 - struct FileMapHeader header; 6.376 - size_t n = 0; 6.377 - int fd = -1, m = 0; 6.378 - uintptr_t base = 0, useSharedSpacesAddr = 0; 6.379 - uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; 6.380 - jboolean useSharedSpaces = 0; 6.381 + int m; 6.382 + size_t n; 6.383 + lib_info* lib = ph->libs; 6.384 + while (lib != NULL) { 6.385 + // we are iterating over shared objects from the core dump. look for 6.386 + // libjvm[_g].so. 6.387 + const char *jvm_name = 0; 6.388 +#ifdef __APPLE__ 6.389 + if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 || 6.390 + (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0) 6.391 +#else 6.392 + if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || 6.393 + (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) 6.394 +#endif // __APPLE__ 6.395 + { 6.396 + char classes_jsa[PATH_MAX]; 6.397 + struct FileMapHeader header; 6.398 + int fd = -1; 6.399 + uintptr_t base = 0, useSharedSpacesAddr = 0; 6.400 + uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; 6.401 + jboolean useSharedSpaces = 0; 6.402 6.403 - memset(classes_jsa, 0, sizeof(classes_jsa)); 6.404 - jvm_name = lib->name; 6.405 - useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); 6.406 - if (useSharedSpacesAddr == 0) { 6.407 - print_debug("can't lookup 'UseSharedSpaces' flag\n"); 6.408 - return false; 6.409 - } 6.410 + memset(classes_jsa, 0, sizeof(classes_jsa)); 6.411 + jvm_name = lib->name; 6.412 + useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); 6.413 + if (useSharedSpacesAddr == 0) { 6.414 + print_debug("can't lookup 'UseSharedSpaces' flag\n"); 6.415 + return false; 6.416 + } 6.417 6.418 - // Hotspot vm types are not exported to build this library. So 6.419 - // using equivalent type jboolean to read the value of 6.420 - // UseSharedSpaces which is same as hotspot type "bool". 6.421 - if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { 6.422 - print_debug("can't read the value of 'UseSharedSpaces' flag\n"); 6.423 - return false; 6.424 - } 6.425 + // Hotspot vm types are not exported to build this library. So 6.426 + // using equivalent type jboolean to read the value of 6.427 + // UseSharedSpaces which is same as hotspot type "bool". 6.428 + if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { 6.429 + print_debug("can't read the value of 'UseSharedSpaces' flag\n"); 6.430 + return false; 6.431 + } 6.432 6.433 - if ((int)useSharedSpaces == 0) { 6.434 - print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); 6.435 - return true; 6.436 - } 6.437 + if ((int)useSharedSpaces == 0) { 6.438 + print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); 6.439 + return true; 6.440 + } 6.441 6.442 - sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); 6.443 - if (sharedArchivePathAddrAddr == 0) { 6.444 - print_debug("can't lookup shared archive path symbol\n"); 6.445 - return false; 6.446 - } 6.447 + sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); 6.448 + if (sharedArchivePathAddrAddr == 0) { 6.449 + print_debug("can't lookup shared archive path symbol\n"); 6.450 + return false; 6.451 + } 6.452 6.453 - if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { 6.454 - print_debug("can't read shared archive path pointer\n"); 6.455 - return false; 6.456 - } 6.457 + if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { 6.458 + print_debug("can't read shared archive path pointer\n"); 6.459 + return false; 6.460 + } 6.461 6.462 - if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { 6.463 - print_debug("can't read shared archive path value\n"); 6.464 - return false; 6.465 - } 6.466 + if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { 6.467 + print_debug("can't read shared archive path value\n"); 6.468 + return false; 6.469 + } 6.470 6.471 - print_debug("looking for %s\n", classes_jsa); 6.472 - // open the class sharing archive file 6.473 - fd = pathmap_open(classes_jsa); 6.474 - if (fd < 0) { 6.475 - print_debug("can't open %s!\n", classes_jsa); 6.476 - ph->core->classes_jsa_fd = -1; 6.477 - return false; 6.478 - } else { 6.479 - print_debug("opened %s\n", classes_jsa); 6.480 - } 6.481 + print_debug("looking for %s\n", classes_jsa); 6.482 + // open the class sharing archive file 6.483 + fd = pathmap_open(classes_jsa); 6.484 + if (fd < 0) { 6.485 + print_debug("can't open %s!\n", classes_jsa); 6.486 + ph->core->classes_jsa_fd = -1; 6.487 + return false; 6.488 + } else { 6.489 + print_debug("opened %s\n", classes_jsa); 6.490 + } 6.491 6.492 - // read FileMapHeader from the file 6.493 - memset(&header, 0, sizeof(struct FileMapHeader)); 6.494 - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) 6.495 - != sizeof(struct FileMapHeader)) { 6.496 - print_debug("can't read shared archive file map header from %s\n", classes_jsa); 6.497 - close(fd); 6.498 - return false; 6.499 - } 6.500 + // read FileMapHeader from the file 6.501 + memset(&header, 0, sizeof(struct FileMapHeader)); 6.502 + if ((n = read(fd, &header, sizeof(struct FileMapHeader))) 6.503 + != sizeof(struct FileMapHeader)) { 6.504 + print_debug("can't read shared archive file map header from %s\n", classes_jsa); 6.505 + close(fd); 6.506 + return false; 6.507 + } 6.508 6.509 - // check file magic 6.510 - if (header._magic != 0xf00baba2) { 6.511 - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", 6.512 - classes_jsa, header._magic); 6.513 - close(fd); 6.514 - return false; 6.515 - } 6.516 + // check file magic 6.517 + if (header._magic != 0xf00baba2) { 6.518 + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", 6.519 + classes_jsa, header._magic); 6.520 + close(fd); 6.521 + return false; 6.522 + } 6.523 6.524 - // check version 6.525 - if (header._version != CURRENT_ARCHIVE_VERSION) { 6.526 - print_debug("%s has wrong shared archive file version %d, expecting %d\n", 6.527 - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); 6.528 - close(fd); 6.529 - return false; 6.530 - } 6.531 + // check version 6.532 + if (header._version != CURRENT_ARCHIVE_VERSION) { 6.533 + print_debug("%s has wrong shared archive file version %d, expecting %d\n", 6.534 + classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); 6.535 + close(fd); 6.536 + return false; 6.537 + } 6.538 6.539 - ph->core->classes_jsa_fd = fd; 6.540 - // add read-only maps from classes[_g].jsa to the list of maps 6.541 - for (m = 0; m < NUM_SHARED_MAPS; m++) { 6.542 - if (header._space[m]._read_only) { 6.543 - base = (uintptr_t) header._space[m]._base; 6.544 - // no need to worry about the fractional pages at-the-end. 6.545 - // possible fractional pages are handled by core_read_data. 6.546 - add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, 6.547 - base, (size_t) header._space[m]._used); 6.548 - print_debug("added a share archive map at 0x%lx\n", base); 6.549 - } 6.550 - } 6.551 - return true; 6.552 + ph->core->classes_jsa_fd = fd; 6.553 + // add read-only maps from classes[_g].jsa to the list of maps 6.554 + for (m = 0; m < NUM_SHARED_MAPS; m++) { 6.555 + if (header._space[m]._read_only) { 6.556 + base = (uintptr_t) header._space[m]._base; 6.557 + // no need to worry about the fractional pages at-the-end. 6.558 + // possible fractional pages are handled by core_read_data. 6.559 + add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, 6.560 + base, (size_t) header._space[m]._used); 6.561 + print_debug("added a share archive map at 0x%lx\n", base); 6.562 + } 6.563 } 6.564 - lib = lib->next; 6.565 - } 6.566 - return true; 6.567 + return true; 6.568 + } 6.569 + lib = lib->next; 6.570 + } 6.571 + return true; 6.572 } 6.573 6.574 - 6.575 //--------------------------------------------------------------------------- 6.576 // functions to handle map_info 6.577 6.578 @@ -397,54 +414,57 @@ 6.579 // callback for sorting the array of map_info pointers. 6.580 static int core_cmp_mapping(const void *lhsp, const void *rhsp) 6.581 { 6.582 - const map_info *lhs = *((const map_info **)lhsp); 6.583 - const map_info *rhs = *((const map_info **)rhsp); 6.584 + const map_info *lhs = *((const map_info **)lhsp); 6.585 + const map_info *rhs = *((const map_info **)rhsp); 6.586 6.587 - if (lhs->vaddr == rhs->vaddr) 6.588 - return (0); 6.589 + if (lhs->vaddr == rhs->vaddr) { 6.590 + return (0); 6.591 + } 6.592 6.593 - return (lhs->vaddr < rhs->vaddr ? -1 : 1); 6.594 + return (lhs->vaddr < rhs->vaddr ? -1 : 1); 6.595 } 6.596 6.597 // we sort map_info by starting virtual address so that we can do 6.598 // binary search to read from an address. 6.599 static bool sort_map_array(struct ps_prochandle* ph) { 6.600 - size_t num_maps = ph->core->num_maps; 6.601 - map_info* map = ph->core->maps; 6.602 - int i = 0; 6.603 + size_t num_maps = ph->core->num_maps; 6.604 + map_info* map = ph->core->maps; 6.605 + int i = 0; 6.606 6.607 - // allocate map_array 6.608 - map_info** array; 6.609 - if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { 6.610 - print_debug("can't allocate memory for map array\n"); 6.611 - return false; 6.612 - } 6.613 + // allocate map_array 6.614 + map_info** array; 6.615 + if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { 6.616 + print_debug("can't allocate memory for map array\n"); 6.617 + return false; 6.618 + } 6.619 6.620 - // add maps to array 6.621 - while (map) { 6.622 - array[i] = map; 6.623 - i++; 6.624 - map = map->next; 6.625 - } 6.626 + // add maps to array 6.627 + while (map) { 6.628 + array[i] = map; 6.629 + i++; 6.630 + map = map->next; 6.631 + } 6.632 6.633 - // sort is called twice. If this is second time, clear map array 6.634 - if (ph->core->map_array) free(ph->core->map_array); 6.635 - ph->core->map_array = array; 6.636 - // sort the map_info array by base virtual address. 6.637 - qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), 6.638 - core_cmp_mapping); 6.639 + // sort is called twice. If this is second time, clear map array 6.640 + if (ph->core->map_array) { 6.641 + free(ph->core->map_array); 6.642 + } 6.643 + ph->core->map_array = array; 6.644 + // sort the map_info array by base virtual address. 6.645 + qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), 6.646 + core_cmp_mapping); 6.647 6.648 - // print map 6.649 - if (is_debug()) { 6.650 - int j = 0; 6.651 - print_debug("---- sorted virtual address map ----\n"); 6.652 - for (j = 0; j < ph->core->num_maps; j++) { 6.653 - print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, 6.654 - ph->core->map_array[j]->memsz); 6.655 - } 6.656 - } 6.657 + // print map 6.658 + if (is_debug()) { 6.659 + int j = 0; 6.660 + print_debug("---- sorted virtual address map ----\n"); 6.661 + for (j = 0; j < ph->core->num_maps; j++) { 6.662 + print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, 6.663 + ph->core->map_array[j]->memsz); 6.664 + } 6.665 + } 6.666 6.667 - return true; 6.668 + return true; 6.669 } 6.670 6.671 #ifndef MIN 6.672 @@ -461,16 +481,18 @@ 6.673 off_t off; 6.674 int fd; 6.675 6.676 - if (mp == NULL) 6.677 + if (mp == NULL) { 6.678 break; /* No mapping for this address */ 6.679 + } 6.680 6.681 fd = mp->fd; 6.682 mapoff = addr - mp->vaddr; 6.683 len = MIN(resid, mp->memsz - mapoff); 6.684 off = mp->offset + mapoff; 6.685 6.686 - if ((len = pread(fd, buf, len, off)) <= 0) 6.687 + if ((len = pread(fd, buf, len, off)) <= 0) { 6.688 break; 6.689 + } 6.690 6.691 resid -= len; 6.692 addr += len; 6.693 @@ -507,8 +529,8 @@ 6.694 6.695 static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, 6.696 struct reg* regs) { 6.697 - // for core we have cached the lwp regs from NOTE section 6.698 - thread_info* thr = ph->threads; 6.699 + // for core we have cached the lwp regs after segment parsed 6.700 + sa_thread_info* thr = ph->threads; 6.701 while (thr) { 6.702 if (thr->lwp_id == lwp_id) { 6.703 memcpy(regs, &thr->regs, sizeof(struct reg)); 6.704 @@ -519,7 +541,7 @@ 6.705 return false; 6.706 } 6.707 6.708 -static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { 6.709 +static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t id, void *info) { 6.710 print_debug("core_get_lwp_info not implemented\n"); 6.711 return false; 6.712 } 6.713 @@ -532,12 +554,451 @@ 6.714 .get_lwp_info= core_get_lwp_info 6.715 }; 6.716 6.717 -// read regs and create thread from NT_PRSTATUS entries from core file 6.718 +// from this point, mainly two blocks divided by def __APPLE__ 6.719 +// one for Macosx, the other for regular Bsd 6.720 + 6.721 +#ifdef __APPLE__ 6.722 + 6.723 +void print_thread(sa_thread_info *threadinfo) { 6.724 + print_debug("thread added: %d\n", threadinfo->lwp_id); 6.725 + print_debug("registers:\n"); 6.726 + print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15); 6.727 + print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14); 6.728 + print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13); 6.729 + print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12); 6.730 + print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11); 6.731 + print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10); 6.732 + print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9); 6.733 + print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8); 6.734 + print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi); 6.735 + print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi); 6.736 + print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp); 6.737 + print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx); 6.738 + print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx); 6.739 + print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx); 6.740 + print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax); 6.741 + print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs); 6.742 + print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs); 6.743 + print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip); 6.744 + print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs); 6.745 + print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp); 6.746 + print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags); 6.747 +} 6.748 + 6.749 +// read all segments64 commands from core file 6.750 +// read all thread commands from core file 6.751 +static bool read_core_segments(struct ps_prochandle* ph) { 6.752 + int i = 0; 6.753 + int num_threads = 0; 6.754 + int fd = ph->core->core_fd; 6.755 + off_t offset = 0; 6.756 + mach_header_64 fhead; 6.757 + load_command lcmd; 6.758 + segment_command_64 segcmd; 6.759 + // thread_command thrcmd; 6.760 + 6.761 + lseek(fd, offset, SEEK_SET); 6.762 + if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 6.763 + goto err; 6.764 + } 6.765 + print_debug("total commands: %d\n", fhead.ncmds); 6.766 + offset += sizeof(mach_header_64); 6.767 + for (i = 0; i < fhead.ncmds; i++) { 6.768 + lseek(fd, offset, SEEK_SET); 6.769 + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { 6.770 + goto err; 6.771 + } 6.772 + offset += lcmd.cmdsize; // next command position 6.773 + if (lcmd.cmd == LC_SEGMENT_64) { 6.774 + lseek(fd, -sizeof(load_command), SEEK_CUR); 6.775 + if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { 6.776 + print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i); 6.777 + goto err; 6.778 + } 6.779 + if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) { 6.780 + print_debug("Failed to add map_info at i = %d\n", i); 6.781 + goto err; 6.782 + } 6.783 + print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n", 6.784 + segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize); 6.785 + } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) { 6.786 + typedef struct thread_fc { 6.787 + uint32_t flavor; 6.788 + uint32_t count; 6.789 + } thread_fc; 6.790 + thread_fc fc; 6.791 + uint32_t size = sizeof(load_command); 6.792 + while (size < lcmd.cmdsize) { 6.793 + if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) { 6.794 + printf("Reading flavor, count failed.\n"); 6.795 + goto err; 6.796 + } 6.797 + size += sizeof(thread_fc); 6.798 + if (fc.flavor == x86_THREAD_STATE) { 6.799 + x86_thread_state_t thrstate; 6.800 + if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) { 6.801 + printf("Reading flavor, count failed.\n"); 6.802 + goto err; 6.803 + } 6.804 + size += sizeof(x86_thread_state_t); 6.805 + // create thread info list, update lwp_id later 6.806 + sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); 6.807 + if (newthr == NULL) { 6.808 + printf("create thread_info failed\n"); 6.809 + goto err; 6.810 + } 6.811 + 6.812 + // note __DARWIN_UNIX03 depengs on other definitions 6.813 +#if __DARWIN_UNIX03 6.814 +#define get_register_v(regst, regname) \ 6.815 + regst.uts.ts64.__##regname 6.816 +#else 6.817 +#define get_register_v(regst, regname) \ 6.818 + regst.uts.ts64.##regname 6.819 +#endif // __DARWIN_UNIX03 6.820 + newthr->regs.r_rax = get_register_v(thrstate, rax); 6.821 + newthr->regs.r_rbx = get_register_v(thrstate, rbx); 6.822 + newthr->regs.r_rcx = get_register_v(thrstate, rcx); 6.823 + newthr->regs.r_rdx = get_register_v(thrstate, rdx); 6.824 + newthr->regs.r_rdi = get_register_v(thrstate, rdi); 6.825 + newthr->regs.r_rsi = get_register_v(thrstate, rsi); 6.826 + newthr->regs.r_rbp = get_register_v(thrstate, rbp); 6.827 + newthr->regs.r_rsp = get_register_v(thrstate, rsp); 6.828 + newthr->regs.r_r8 = get_register_v(thrstate, r8); 6.829 + newthr->regs.r_r9 = get_register_v(thrstate, r9); 6.830 + newthr->regs.r_r10 = get_register_v(thrstate, r10); 6.831 + newthr->regs.r_r11 = get_register_v(thrstate, r11); 6.832 + newthr->regs.r_r12 = get_register_v(thrstate, r12); 6.833 + newthr->regs.r_r13 = get_register_v(thrstate, r13); 6.834 + newthr->regs.r_r14 = get_register_v(thrstate, r14); 6.835 + newthr->regs.r_r15 = get_register_v(thrstate, r15); 6.836 + newthr->regs.r_rip = get_register_v(thrstate, rip); 6.837 + newthr->regs.r_rflags = get_register_v(thrstate, rflags); 6.838 + newthr->regs.r_cs = get_register_v(thrstate, cs); 6.839 + newthr->regs.r_fs = get_register_v(thrstate, fs); 6.840 + newthr->regs.r_gs = get_register_v(thrstate, gs); 6.841 + print_thread(newthr); 6.842 + } else if (fc.flavor == x86_FLOAT_STATE) { 6.843 + x86_float_state_t flstate; 6.844 + if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) { 6.845 + print_debug("Reading flavor, count failed.\n"); 6.846 + goto err; 6.847 + } 6.848 + size += sizeof(x86_float_state_t); 6.849 + } else if (fc.flavor == x86_EXCEPTION_STATE) { 6.850 + x86_exception_state_t excpstate; 6.851 + if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) { 6.852 + printf("Reading flavor, count failed.\n"); 6.853 + goto err; 6.854 + } 6.855 + size += sizeof(x86_exception_state_t); 6.856 + } 6.857 + } 6.858 + } 6.859 + } 6.860 + return true; 6.861 +err: 6.862 + return false; 6.863 +} 6.864 + 6.865 +/**local function **/ 6.866 +bool exists(const char *fname) 6.867 +{ 6.868 + int fd; 6.869 + if ((fd = open(fname, O_RDONLY)) > 0) { 6.870 + close(fd); 6.871 + return true; 6.872 + } 6.873 + return false; 6.874 +} 6.875 + 6.876 +// we check: 1. lib 6.877 +// 2. lib/server 6.878 +// 3. jre/lib 6.879 +// 4. jre/lib/server 6.880 +// from: 1. exe path 6.881 +// 2. JAVA_HOME 6.882 +// 3. DYLD_LIBRARY_PATH 6.883 +static bool get_real_path(struct ps_prochandle* ph, char *rpath) { 6.884 + /** check if they exist in JAVA ***/ 6.885 + char* execname = ph->core->exec_path; 6.886 + char filepath[4096]; 6.887 + char* filename = strrchr(rpath, '/'); // like /libjvm.dylib 6.888 + if (filename == NULL) { 6.889 + return false; 6.890 + } 6.891 + 6.892 + char* posbin = strstr(execname, "/bin/java"); 6.893 + if (posbin != NULL) { 6.894 + memcpy(filepath, execname, posbin - execname); // not include trailing '/' 6.895 + filepath[posbin - execname] = '\0'; 6.896 + } else { 6.897 + char* java_home = getenv("JAVA_HOME"); 6.898 + if (java_home != NULL) { 6.899 + strcpy(filepath, java_home); 6.900 + } else { 6.901 + char* dyldpath = getenv("DYLD_LIBRARY_PATH"); 6.902 + char* dypath = strtok(dyldpath, ":"); 6.903 + while (dypath != NULL) { 6.904 + strcpy(filepath, dypath); 6.905 + strcat(filepath, filename); 6.906 + if (exists(filepath)) { 6.907 + strcpy(rpath, filepath); 6.908 + return true; 6.909 + } 6.910 + dypath = strtok(dyldpath, ":"); 6.911 + } 6.912 + // not found 6.913 + return false; 6.914 + } 6.915 + } 6.916 + // for exec and java_home, jdkpath now is filepath 6.917 + size_t filepath_base_size = strlen(filepath); 6.918 + 6.919 + // first try /lib/ and /lib/server 6.920 + strcat(filepath, "/lib"); 6.921 + strcat(filepath, filename); 6.922 + if (exists(filepath)) { 6.923 + strcpy(rpath, filepath); 6.924 + return true; 6.925 + } 6.926 + char* pos = strstr(filepath, filename); // like /libjvm.dylib 6.927 + *pos = '\0'; 6.928 + strcat(filepath, "/server"); 6.929 + strcat(filepath, filename); 6.930 + if (exists(filepath)) { 6.931 + strcpy(rpath, filepath); 6.932 + return true; 6.933 + } 6.934 + 6.935 + // then try /jre/lib/ and /jre/lib/server 6.936 + filepath[filepath_base_size] = '\0'; 6.937 + strcat(filepath, "/jre/lib"); 6.938 + strcat(filepath, filename); 6.939 + if (exists(filepath)) { 6.940 + strcpy(rpath, filepath); 6.941 + return true; 6.942 + } 6.943 + pos = strstr(filepath, filename); 6.944 + *pos = '\0'; 6.945 + strcat(filepath, "/server"); 6.946 + strcat(filepath, filename); 6.947 + if (exists(filepath)) { 6.948 + strcpy(rpath, filepath); 6.949 + return true; 6.950 + } 6.951 + 6.952 + return false; 6.953 +} 6.954 + 6.955 +static bool read_shared_lib_info(struct ps_prochandle* ph) { 6.956 + static int pagesize = 0; 6.957 + int fd = ph->core->core_fd; 6.958 + int i = 0, j; 6.959 + uint32_t v; 6.960 + mach_header_64 header; // used to check if a file header in segment 6.961 + load_command lcmd; 6.962 + dylib_command dylibcmd; 6.963 + 6.964 + char name[BUF_SIZE]; // use to store name 6.965 + 6.966 + if (pagesize == 0) { 6.967 + pagesize = getpagesize(); 6.968 + print_debug("page size is %d\n", pagesize); 6.969 + } 6.970 + for (j = 0; j < ph->core->num_maps; j++) { 6.971 + map_info *iter = ph->core->map_array[j]; // head 6.972 + off_t fpos = iter->offset; 6.973 + if (iter->fd != fd) { 6.974 + // only search core file! 6.975 + continue; 6.976 + } 6.977 + print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n", 6.978 + j, iter->vaddr, iter->offset, iter->memsz); 6.979 + lseek(fd, fpos, SEEK_SET); 6.980 + // we assume .dylib loaded at segment address --- which is true for JVM libraries 6.981 + // multiple files may be loaded in one segment. 6.982 + // if first word is not a magic word, means this segment does not contain lib file. 6.983 + if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) { 6.984 + if (v != MH_MAGIC_64) { 6.985 + continue; 6.986 + } 6.987 + } else { 6.988 + // may be encountered last map, which is not readable 6.989 + continue; 6.990 + } 6.991 + while (ltell(fd) - iter->offset < iter->memsz) { 6.992 + lseek(fd, fpos, SEEK_SET); 6.993 + if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) { 6.994 + break; 6.995 + } 6.996 + if (v != MH_MAGIC_64) { 6.997 + fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize; 6.998 + continue; 6.999 + } 6.1000 + lseek(fd, -sizeof(uint32_t), SEEK_CUR); 6.1001 + // this is the file begining to core file. 6.1002 + if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 6.1003 + goto err; 6.1004 + } 6.1005 + fpos = ltell(fd); 6.1006 + 6.1007 + // found a mach-o file in this segment 6.1008 + for (i = 0; i < header.ncmds; i++) { 6.1009 + // read commands in this "file" 6.1010 + // LC_ID_DYLIB is the file itself for a .dylib 6.1011 + lseek(fd, fpos, SEEK_SET); 6.1012 + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { 6.1013 + return false; // error 6.1014 + } 6.1015 + fpos += lcmd.cmdsize; // next command position 6.1016 + // make sure still within seg size. 6.1017 + if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) { 6.1018 + print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset); 6.1019 + break; // no need to iterate all commands 6.1020 + } 6.1021 + if (lcmd.cmd == LC_ID_DYLIB) { 6.1022 + lseek(fd, -sizeof(load_command), SEEK_CUR); 6.1023 + if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) { 6.1024 + return false; 6.1025 + } 6.1026 + /**** name stored at dylib_command.dylib.name.offset, is a C string */ 6.1027 + lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR); 6.1028 + int j = 0; 6.1029 + while (j < BUF_SIZE) { 6.1030 + read(fd, (void *)(name + j), sizeof(char)); 6.1031 + if (name[j] == '\0') break; 6.1032 + j++; 6.1033 + } 6.1034 + print_debug("%s\n", name); 6.1035 + // changed name from @rpath/xxxx.dylib to real path 6.1036 + if (strrchr(name, '@')) { 6.1037 + get_real_path(ph, name); 6.1038 + print_debug("get_real_path returned: %s\n", name); 6.1039 + } 6.1040 + add_lib_info(ph, name, iter->vaddr); 6.1041 + break; 6.1042 + } 6.1043 + } 6.1044 + // done with the file, advanced to next page to search more files 6.1045 + fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize; 6.1046 + } 6.1047 + } 6.1048 + return true; 6.1049 +err: 6.1050 + return false; 6.1051 +} 6.1052 + 6.1053 +bool read_macho64_header(int fd, mach_header_64* core_header) { 6.1054 + bool is_macho = false; 6.1055 + if (fd < 0) return false; 6.1056 + off_t pos = ltell(fd); 6.1057 + lseek(fd, 0, SEEK_SET); 6.1058 + if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 6.1059 + is_macho = false; 6.1060 + } else { 6.1061 + is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64); 6.1062 + } 6.1063 + lseek(fd, pos, SEEK_SET); 6.1064 + return is_macho; 6.1065 +} 6.1066 + 6.1067 +// the one and only one exposed stuff from this file 6.1068 +struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { 6.1069 + mach_header_64 core_header; 6.1070 + mach_header_64 exec_header; 6.1071 + 6.1072 + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); 6.1073 + if (ph == NULL) { 6.1074 + print_debug("cant allocate ps_prochandle\n"); 6.1075 + return NULL; 6.1076 + } 6.1077 + 6.1078 + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { 6.1079 + free(ph); 6.1080 + print_debug("can't allocate ps_prochandle\n"); 6.1081 + return NULL; 6.1082 + } 6.1083 + 6.1084 + // initialize ph 6.1085 + ph->ops = &core_ops; 6.1086 + ph->core->core_fd = -1; 6.1087 + ph->core->exec_fd = -1; 6.1088 + ph->core->interp_fd = -1; 6.1089 + 6.1090 + print_debug("exec: %s core: %s", exec_file, core_file); 6.1091 + 6.1092 + strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path)); 6.1093 + 6.1094 + // open the core file 6.1095 + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { 6.1096 + print_error("can't open core file\n"); 6.1097 + goto err; 6.1098 + } 6.1099 + 6.1100 + // read core file header 6.1101 + if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) { 6.1102 + print_debug("core file is not a valid Mach-O file\n"); 6.1103 + goto err; 6.1104 + } 6.1105 + 6.1106 + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { 6.1107 + print_error("can't open executable file\n"); 6.1108 + goto err; 6.1109 + } 6.1110 + 6.1111 + if (read_macho64_header(ph->core->exec_fd, &exec_header) != true || 6.1112 + exec_header.filetype != MH_EXECUTE) { 6.1113 + print_error("executable file is not a valid Mach-O file\n"); 6.1114 + goto err; 6.1115 + } 6.1116 + 6.1117 + // process core file segments 6.1118 + if (read_core_segments(ph) != true) { 6.1119 + print_error("failed to read core segments\n"); 6.1120 + goto err; 6.1121 + } 6.1122 + 6.1123 + // allocate and sort maps into map_array, we need to do this 6.1124 + // here because read_shared_lib_info needs to read from debuggee 6.1125 + // address space 6.1126 + if (sort_map_array(ph) != true) { 6.1127 + print_error("failed to sort segment map array\n"); 6.1128 + goto err; 6.1129 + } 6.1130 + 6.1131 + if (read_shared_lib_info(ph) != true) { 6.1132 + print_error("failed to read libraries\n"); 6.1133 + goto err; 6.1134 + } 6.1135 + 6.1136 + // sort again because we have added more mappings from shared objects 6.1137 + if (sort_map_array(ph) != true) { 6.1138 + print_error("failed to sort segment map array\n"); 6.1139 + goto err; 6.1140 + } 6.1141 + 6.1142 + if (init_classsharing_workaround(ph) != true) { 6.1143 + print_error("failed to workaround classshareing\n"); 6.1144 + goto err; 6.1145 + } 6.1146 + 6.1147 + print_debug("Leave Pgrab_core\n"); 6.1148 + return ph; 6.1149 + 6.1150 +err: 6.1151 + Prelease(ph); 6.1152 + return NULL; 6.1153 +} 6.1154 + 6.1155 +#else // __APPLE__ (none macosx) 6.1156 + 6.1157 +// read regs and create thread from core file 6.1158 static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) { 6.1159 // we have to read prstatus_t from buf 6.1160 // assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t"); 6.1161 prstatus_t* prstat = (prstatus_t*) buf; 6.1162 - thread_info* newthr; 6.1163 + sa_thread_info* newthr; 6.1164 print_debug("got integer regset for lwp %d\n", prstat->pr_pid); 6.1165 // we set pthread_t to -1 for core dump 6.1166 if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL) 6.1167 @@ -632,8 +1093,9 @@ 6.1168 notep->n_type, notep->n_descsz); 6.1169 6.1170 if (notep->n_type == NT_PRSTATUS) { 6.1171 - if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) 6.1172 + if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { 6.1173 return false; 6.1174 + } 6.1175 } 6.1176 p = descdata + ROUNDUP(notep->n_descsz, 4); 6.1177 } 6.1178 @@ -681,7 +1143,9 @@ 6.1179 for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) { 6.1180 switch (core_php->p_type) { 6.1181 case PT_NOTE: 6.1182 - if (core_handle_note(ph, core_php) != true) goto err; 6.1183 + if (core_handle_note(ph, core_php) != true) { 6.1184 + goto err; 6.1185 + } 6.1186 break; 6.1187 6.1188 case PT_LOAD: { 6.1189 @@ -800,7 +1264,6 @@ 6.1190 return false; 6.1191 } 6.1192 6.1193 - 6.1194 #define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map) 6.1195 #define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase) 6.1196 #define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr) 6.1197 @@ -810,213 +1273,218 @@ 6.1198 // read shared library info from runtime linker's data structures. 6.1199 // This work is done by librtlb_db in Solaris 6.1200 static bool read_shared_lib_info(struct ps_prochandle* ph) { 6.1201 - uintptr_t addr = ph->core->dynamic_addr; 6.1202 - uintptr_t debug_base; 6.1203 - uintptr_t first_link_map_addr; 6.1204 - uintptr_t ld_base_addr; 6.1205 - uintptr_t link_map_addr; 6.1206 - uintptr_t lib_base_diff; 6.1207 - uintptr_t lib_base; 6.1208 - uintptr_t lib_name_addr; 6.1209 - char lib_name[BUF_SIZE]; 6.1210 - ELF_DYN dyn; 6.1211 - ELF_EHDR elf_ehdr; 6.1212 - int lib_fd; 6.1213 + uintptr_t addr = ph->core->dynamic_addr; 6.1214 + uintptr_t debug_base; 6.1215 + uintptr_t first_link_map_addr; 6.1216 + uintptr_t ld_base_addr; 6.1217 + uintptr_t link_map_addr; 6.1218 + uintptr_t lib_base_diff; 6.1219 + uintptr_t lib_base; 6.1220 + uintptr_t lib_name_addr; 6.1221 + char lib_name[BUF_SIZE]; 6.1222 + ELF_DYN dyn; 6.1223 + ELF_EHDR elf_ehdr; 6.1224 + int lib_fd; 6.1225 6.1226 - // _DYNAMIC has information of the form 6.1227 - // [tag] [data] [tag] [data] ..... 6.1228 - // Both tag and data are pointer sized. 6.1229 - // We look for dynamic info with DT_DEBUG. This has shared object info. 6.1230 - // refer to struct r_debug in link.h 6.1231 + // _DYNAMIC has information of the form 6.1232 + // [tag] [data] [tag] [data] ..... 6.1233 + // Both tag and data are pointer sized. 6.1234 + // We look for dynamic info with DT_DEBUG. This has shared object info. 6.1235 + // refer to struct r_debug in link.h 6.1236 6.1237 - dyn.d_tag = DT_NULL; 6.1238 - while (dyn.d_tag != DT_DEBUG) { 6.1239 - if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { 6.1240 - print_debug("can't read debug info from _DYNAMIC\n"); 6.1241 - return false; 6.1242 + dyn.d_tag = DT_NULL; 6.1243 + while (dyn.d_tag != DT_DEBUG) { 6.1244 + if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { 6.1245 + print_debug("can't read debug info from _DYNAMIC\n"); 6.1246 + return false; 6.1247 + } 6.1248 + addr += sizeof(ELF_DYN); 6.1249 + } 6.1250 + 6.1251 + // we have got Dyn entry with DT_DEBUG 6.1252 + debug_base = dyn.d_un.d_ptr; 6.1253 + // at debug_base we have struct r_debug. This has first link map in r_map field 6.1254 + if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, 6.1255 + &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { 6.1256 + print_debug("can't read first link map address\n"); 6.1257 + return false; 6.1258 + } 6.1259 + 6.1260 + // read ld_base address from struct r_debug 6.1261 + // XXX: There is no r_ldbase member on BSD 6.1262 + /* 6.1263 + if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, 6.1264 + sizeof(uintptr_t)) != PS_OK) { 6.1265 + print_debug("can't read ld base address\n"); 6.1266 + return false; 6.1267 + } 6.1268 + ph->core->ld_base_addr = ld_base_addr; 6.1269 + */ 6.1270 + ph->core->ld_base_addr = 0; 6.1271 + 6.1272 + print_debug("interpreter base address is 0x%lx\n", ld_base_addr); 6.1273 + 6.1274 + // now read segments from interp (i.e ld-elf.so.1) 6.1275 + if (read_interp_segments(ph) != true) 6.1276 + return false; 6.1277 + 6.1278 + // after adding interpreter (ld.so) mappings sort again 6.1279 + if (sort_map_array(ph) != true) 6.1280 + return false; 6.1281 + 6.1282 + print_debug("first link map is at 0x%lx\n", first_link_map_addr); 6.1283 + 6.1284 + link_map_addr = first_link_map_addr; 6.1285 + while (link_map_addr != 0) { 6.1286 + // read library base address of the .so. Note that even though <sys/link.h> calls 6.1287 + // link_map->l_addr as "base address", this is * not * really base virtual 6.1288 + // address of the shared object. This is actually the difference b/w the virtual 6.1289 + // address mentioned in shared object and the actual virtual base where runtime 6.1290 + // linker loaded it. We use "base diff" in read_lib_segments call below. 6.1291 + 6.1292 + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, 6.1293 + &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { 6.1294 + print_debug("can't read shared object base address diff\n"); 6.1295 + return false; 6.1296 + } 6.1297 + 6.1298 + // read address of the name 6.1299 + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, 6.1300 + &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { 6.1301 + print_debug("can't read address of shared object name\n"); 6.1302 + return false; 6.1303 + } 6.1304 + 6.1305 + // read name of the shared object 6.1306 + if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { 6.1307 + print_debug("can't read shared object name\n"); 6.1308 + return false; 6.1309 + } 6.1310 + 6.1311 + if (lib_name[0] != '\0') { 6.1312 + // ignore empty lib names 6.1313 + lib_fd = pathmap_open(lib_name); 6.1314 + 6.1315 + if (lib_fd < 0) { 6.1316 + print_debug("can't open shared object %s\n", lib_name); 6.1317 + // continue with other libraries... 6.1318 + } else { 6.1319 + if (read_elf_header(lib_fd, &elf_ehdr)) { 6.1320 + lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); 6.1321 + print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", 6.1322 + lib_name, lib_base, lib_base_diff); 6.1323 + // while adding library mappings we need to use "base difference". 6.1324 + if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { 6.1325 + print_debug("can't read shared object's segments\n"); 6.1326 + close(lib_fd); 6.1327 + return false; 6.1328 + } 6.1329 + add_lib_info_fd(ph, lib_name, lib_fd, lib_base); 6.1330 + // Map info is added for the library (lib_name) so 6.1331 + // we need to re-sort it before calling the p_pdread. 6.1332 + if (sort_map_array(ph) != true) 6.1333 + return false; 6.1334 + } else { 6.1335 + print_debug("can't read ELF header for shared object %s\n", lib_name); 6.1336 + close(lib_fd); 6.1337 + // continue with other libraries... 6.1338 + } 6.1339 } 6.1340 - addr += sizeof(ELF_DYN); 6.1341 - } 6.1342 + } 6.1343 6.1344 - // we have got Dyn entry with DT_DEBUG 6.1345 - debug_base = dyn.d_un.d_ptr; 6.1346 - // at debug_base we have struct r_debug. This has first link map in r_map field 6.1347 - if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, 6.1348 - &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { 6.1349 - print_debug("can't read first link map address\n"); 6.1350 + // read next link_map address 6.1351 + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, 6.1352 + &link_map_addr, sizeof(uintptr_t)) != PS_OK) { 6.1353 + print_debug("can't read next link in link_map\n"); 6.1354 return false; 6.1355 - } 6.1356 + } 6.1357 + } 6.1358 6.1359 - // read ld_base address from struct r_debug 6.1360 - // XXX: There is no r_ldbase member on BSD 6.1361 -/* 6.1362 - if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, 6.1363 - sizeof(uintptr_t)) != PS_OK) { 6.1364 - print_debug("can't read ld base address\n"); 6.1365 - return false; 6.1366 - } 6.1367 - ph->core->ld_base_addr = ld_base_addr; 6.1368 -*/ 6.1369 - ph->core->ld_base_addr = 0; 6.1370 - 6.1371 - print_debug("interpreter base address is 0x%lx\n", ld_base_addr); 6.1372 - 6.1373 - // now read segments from interp (i.e ld-elf.so.1) 6.1374 - if (read_interp_segments(ph) != true) 6.1375 - return false; 6.1376 - 6.1377 - // after adding interpreter (ld.so) mappings sort again 6.1378 - if (sort_map_array(ph) != true) 6.1379 - return false; 6.1380 - 6.1381 - print_debug("first link map is at 0x%lx\n", first_link_map_addr); 6.1382 - 6.1383 - link_map_addr = first_link_map_addr; 6.1384 - while (link_map_addr != 0) { 6.1385 - // read library base address of the .so. Note that even though <sys/link.h> calls 6.1386 - // link_map->l_addr as "base address", this is * not * really base virtual 6.1387 - // address of the shared object. This is actually the difference b/w the virtual 6.1388 - // address mentioned in shared object and the actual virtual base where runtime 6.1389 - // linker loaded it. We use "base diff" in read_lib_segments call below. 6.1390 - 6.1391 - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, 6.1392 - &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { 6.1393 - print_debug("can't read shared object base address diff\n"); 6.1394 - return false; 6.1395 - } 6.1396 - 6.1397 - // read address of the name 6.1398 - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, 6.1399 - &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { 6.1400 - print_debug("can't read address of shared object name\n"); 6.1401 - return false; 6.1402 - } 6.1403 - 6.1404 - // read name of the shared object 6.1405 - if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { 6.1406 - print_debug("can't read shared object name\n"); 6.1407 - return false; 6.1408 - } 6.1409 - 6.1410 - if (lib_name[0] != '\0') { 6.1411 - // ignore empty lib names 6.1412 - lib_fd = pathmap_open(lib_name); 6.1413 - 6.1414 - if (lib_fd < 0) { 6.1415 - print_debug("can't open shared object %s\n", lib_name); 6.1416 - // continue with other libraries... 6.1417 - } else { 6.1418 - if (read_elf_header(lib_fd, &elf_ehdr)) { 6.1419 - lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); 6.1420 - print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", 6.1421 - lib_name, lib_base, lib_base_diff); 6.1422 - // while adding library mappings we need to use "base difference". 6.1423 - if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { 6.1424 - print_debug("can't read shared object's segments\n"); 6.1425 - close(lib_fd); 6.1426 - return false; 6.1427 - } 6.1428 - add_lib_info_fd(ph, lib_name, lib_fd, lib_base); 6.1429 - // Map info is added for the library (lib_name) so 6.1430 - // we need to re-sort it before calling the p_pdread. 6.1431 - if (sort_map_array(ph) != true) 6.1432 - return false; 6.1433 - } else { 6.1434 - print_debug("can't read ELF header for shared object %s\n", lib_name); 6.1435 - close(lib_fd); 6.1436 - // continue with other libraries... 6.1437 - } 6.1438 - } 6.1439 - } 6.1440 - 6.1441 - // read next link_map address 6.1442 - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, 6.1443 - &link_map_addr, sizeof(uintptr_t)) != PS_OK) { 6.1444 - print_debug("can't read next link in link_map\n"); 6.1445 - return false; 6.1446 - } 6.1447 - } 6.1448 - 6.1449 - return true; 6.1450 + return true; 6.1451 } 6.1452 6.1453 // the one and only one exposed stuff from this file 6.1454 struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { 6.1455 - ELF_EHDR core_ehdr; 6.1456 - ELF_EHDR exec_ehdr; 6.1457 + ELF_EHDR core_ehdr; 6.1458 + ELF_EHDR exec_ehdr; 6.1459 6.1460 - struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); 6.1461 - if (ph == NULL) { 6.1462 - print_debug("can't allocate ps_prochandle\n"); 6.1463 - return NULL; 6.1464 - } 6.1465 + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); 6.1466 + if (ph == NULL) { 6.1467 + print_debug("cant allocate ps_prochandle\n"); 6.1468 + return NULL; 6.1469 + } 6.1470 6.1471 - if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { 6.1472 - free(ph); 6.1473 - print_debug("can't allocate ps_prochandle\n"); 6.1474 - return NULL; 6.1475 - } 6.1476 + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { 6.1477 + free(ph); 6.1478 + print_debug("can't allocate ps_prochandle\n"); 6.1479 + return NULL; 6.1480 + } 6.1481 6.1482 - // initialize ph 6.1483 - ph->ops = &core_ops; 6.1484 - ph->core->core_fd = -1; 6.1485 - ph->core->exec_fd = -1; 6.1486 - ph->core->interp_fd = -1; 6.1487 + // initialize ph 6.1488 + ph->ops = &core_ops; 6.1489 + ph->core->core_fd = -1; 6.1490 + ph->core->exec_fd = -1; 6.1491 + ph->core->interp_fd = -1; 6.1492 6.1493 - // open the core file 6.1494 - if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { 6.1495 - print_debug("can't open core file\n"); 6.1496 - goto err; 6.1497 - } 6.1498 + print_debug("exec: %s core: %s", exec_file, core_file); 6.1499 6.1500 - // read core file ELF header 6.1501 - if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { 6.1502 - print_debug("core file is not a valid ELF ET_CORE file\n"); 6.1503 - goto err; 6.1504 - } 6.1505 + // open the core file 6.1506 + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { 6.1507 + print_debug("can't open core file\n"); 6.1508 + goto err; 6.1509 + } 6.1510 6.1511 - if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { 6.1512 - print_debug("can't open executable file\n"); 6.1513 - goto err; 6.1514 - } 6.1515 + // read core file ELF header 6.1516 + if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { 6.1517 + print_debug("core file is not a valid ELF ET_CORE file\n"); 6.1518 + goto err; 6.1519 + } 6.1520 6.1521 - if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { 6.1522 - print_debug("executable file is not a valid ELF ET_EXEC file\n"); 6.1523 - goto err; 6.1524 - } 6.1525 + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { 6.1526 + print_debug("can't open executable file\n"); 6.1527 + goto err; 6.1528 + } 6.1529 6.1530 - // process core file segments 6.1531 - if (read_core_segments(ph, &core_ehdr) != true) 6.1532 - goto err; 6.1533 + if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { 6.1534 + print_debug("executable file is not a valid ELF ET_EXEC file\n"); 6.1535 + goto err; 6.1536 + } 6.1537 6.1538 - // process exec file segments 6.1539 - if (read_exec_segments(ph, &exec_ehdr) != true) 6.1540 - goto err; 6.1541 + // process core file segments 6.1542 + if (read_core_segments(ph, &core_ehdr) != true) 6.1543 + goto err; 6.1544 6.1545 - // exec file is also treated like a shared object for symbol search 6.1546 - if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, 6.1547 - (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) 6.1548 - goto err; 6.1549 + // process exec file segments 6.1550 + if (read_exec_segments(ph, &exec_ehdr) != true) 6.1551 + goto err; 6.1552 6.1553 - // allocate and sort maps into map_array, we need to do this 6.1554 - // here because read_shared_lib_info needs to read from debuggee 6.1555 - // address space 6.1556 - if (sort_map_array(ph) != true) 6.1557 - goto err; 6.1558 + // exec file is also treated like a shared object for symbol search 6.1559 + if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, 6.1560 + (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) 6.1561 + goto err; 6.1562 6.1563 - if (read_shared_lib_info(ph) != true) 6.1564 - goto err; 6.1565 + // allocate and sort maps into map_array, we need to do this 6.1566 + // here because read_shared_lib_info needs to read from debuggee 6.1567 + // address space 6.1568 + if (sort_map_array(ph) != true) 6.1569 + goto err; 6.1570 6.1571 - // sort again because we have added more mappings from shared objects 6.1572 - if (sort_map_array(ph) != true) 6.1573 - goto err; 6.1574 + if (read_shared_lib_info(ph) != true) 6.1575 + goto err; 6.1576 6.1577 - if (init_classsharing_workaround(ph) != true) 6.1578 - goto err; 6.1579 + // sort again because we have added more mappings from shared objects 6.1580 + if (sort_map_array(ph) != true) 6.1581 + goto err; 6.1582 6.1583 - return ph; 6.1584 + if (init_classsharing_workaround(ph) != true) 6.1585 + goto err; 6.1586 + 6.1587 + print_debug("Leave Pgrab_core\n"); 6.1588 + return ph; 6.1589 6.1590 err: 6.1591 - Prelease(ph); 6.1592 - return NULL; 6.1593 + Prelease(ph); 6.1594 + return NULL; 6.1595 } 6.1596 + 6.1597 +#endif // __APPLE__
7.1 --- a/agent/src/os/bsd/symtab.c Fri Mar 15 11:44:33 2013 -0700 7.2 +++ b/agent/src/os/bsd/symtab.c Sun Mar 17 08:57:56 2013 -0700 7.3 @@ -1,5 +1,5 @@ 7.4 /* 7.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 7.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 7.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.8 * 7.9 * This code is free software; you can redistribute it and/or modify it 7.10 @@ -28,32 +28,182 @@ 7.11 #include <string.h> 7.12 #include <db.h> 7.13 #include <fcntl.h> 7.14 + 7.15 +#include "libproc_impl.h" 7.16 #include "symtab.h" 7.17 +#ifndef __APPLE__ 7.18 #include "salibelf.h" 7.19 +#endif // __APPLE__ 7.20 7.21 7.22 // ---------------------------------------------------- 7.23 // functions for symbol lookups 7.24 // ---------------------------------------------------- 7.25 7.26 +typedef struct symtab_symbol { 7.27 + char *name; // name like __ZThread_... 7.28 + uintptr_t offset; // to loaded address 7.29 + uintptr_t size; // size strlen 7.30 +} symtab_symbol; 7.31 + 7.32 +typedef struct symtab { 7.33 + char *strs; // all symbols "__symbol1__'\0'__symbol2__...." 7.34 + size_t num_symbols; 7.35 + DB* hash_table; 7.36 + symtab_symbol* symbols; 7.37 +} symtab_t; 7.38 + 7.39 +#ifdef __APPLE__ 7.40 + 7.41 +void build_search_table(symtab_t *symtab) { 7.42 + int i; 7.43 + for (i = 0; i < symtab->num_symbols; i++) { 7.44 + DBT key, value; 7.45 + key.data = symtab->symbols[i].name; 7.46 + key.size = strlen(key.data) + 1; 7.47 + value.data = &(symtab->symbols[i]); 7.48 + value.size = sizeof(symtab_symbol); 7.49 + (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); 7.50 + 7.51 + // check result 7.52 + if (is_debug()) { 7.53 + DBT rkey, rvalue; 7.54 + char* tmp = (char *)malloc(strlen(symtab->symbols[i].name) + 1); 7.55 + strcpy(tmp, symtab->symbols[i].name); 7.56 + rkey.data = tmp; 7.57 + rkey.size = strlen(tmp) + 1; 7.58 + (*symtab->hash_table->get)(symtab->hash_table, &rkey, &rvalue, 0); 7.59 + // we may get a copy back so compare contents 7.60 + symtab_symbol *res = (symtab_symbol *)rvalue.data; 7.61 + if (strcmp(res->name, symtab->symbols[i].name) || 7.62 + res->offset != symtab->symbols[i].offset || 7.63 + res->size != symtab->symbols[i].size) { 7.64 + print_debug("error to get hash_table value!\n"); 7.65 + } 7.66 + free(tmp); 7.67 + } 7.68 + } 7.69 +} 7.70 + 7.71 +// read symbol table from given fd. 7.72 +struct symtab* build_symtab(int fd) { 7.73 + symtab_t* symtab = NULL; 7.74 + int i; 7.75 + mach_header_64 header; 7.76 + off_t image_start; 7.77 + 7.78 + if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) { 7.79 + print_debug("failed in get fat header\n"); 7.80 + return NULL; 7.81 + } 7.82 + lseek(fd, image_start, SEEK_SET); 7.83 + if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 7.84 + print_debug("reading header failed!\n"); 7.85 + return NULL; 7.86 + } 7.87 + // header 7.88 + if (header.magic != MH_MAGIC_64) { 7.89 + print_debug("not a valid .dylib file\n"); 7.90 + return NULL; 7.91 + } 7.92 + 7.93 + load_command lcmd; 7.94 + symtab_command symtabcmd; 7.95 + nlist_64 lentry; 7.96 + 7.97 + bool lcsymtab_exist = false; 7.98 + 7.99 + long filepos = ltell(fd); 7.100 + for (i = 0; i < header.ncmds; i++) { 7.101 + lseek(fd, filepos, SEEK_SET); 7.102 + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { 7.103 + print_debug("read load_command failed for file\n"); 7.104 + return NULL; 7.105 + } 7.106 + filepos += lcmd.cmdsize; // next command position 7.107 + if (lcmd.cmd == LC_SYMTAB) { 7.108 + lseek(fd, -sizeof(load_command), SEEK_CUR); 7.109 + lcsymtab_exist = true; 7.110 + break; 7.111 + } 7.112 + } 7.113 + if (!lcsymtab_exist) { 7.114 + print_debug("No symtab command found!\n"); 7.115 + return NULL; 7.116 + } 7.117 + if (read(fd, (void *)&symtabcmd, sizeof(symtab_command)) != sizeof(symtab_command)) { 7.118 + print_debug("read symtab_command failed for file"); 7.119 + return NULL; 7.120 + } 7.121 + symtab = (symtab_t *)malloc(sizeof(symtab_t)); 7.122 + if (symtab == NULL) { 7.123 + print_debug("out of memory: allocating symtab\n"); 7.124 + return NULL; 7.125 + } 7.126 + 7.127 + // create hash table, we use berkeley db to 7.128 + // manipulate the hash table. 7.129 + symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL); 7.130 + if (symtab->hash_table == NULL) 7.131 + goto quit; 7.132 + 7.133 + symtab->num_symbols = symtabcmd.nsyms; 7.134 + symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols); 7.135 + symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize); 7.136 + if (symtab->symbols == NULL || symtab->strs == NULL) { 7.137 + print_debug("out of memory: allocating symtab.symbol or symtab.strs\n"); 7.138 + goto quit; 7.139 + } 7.140 + lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); 7.141 + for (i = 0; i < symtab->num_symbols; i++) { 7.142 + if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { 7.143 + print_debug("read nlist_64 failed at %i\n", i); 7.144 + goto quit; 7.145 + } 7.146 + symtab->symbols[i].offset = lentry.n_value; 7.147 + symtab->symbols[i].size = lentry.n_un.n_strx; // index 7.148 + } 7.149 + 7.150 + // string table 7.151 + lseek(fd, image_start + symtabcmd.stroff, SEEK_SET); 7.152 + int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char)); 7.153 + if (size != symtabcmd.strsize * sizeof(char)) { 7.154 + print_debug("reading string table failed\n"); 7.155 + goto quit; 7.156 + } 7.157 + 7.158 + for (i = 0; i < symtab->num_symbols; i++) { 7.159 + symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size; 7.160 + if (i > 0) { 7.161 + // fix size 7.162 + symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size; 7.163 + print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size); 7.164 + 7.165 + } 7.166 + 7.167 + if (i == symtab->num_symbols - 1) { 7.168 + // last index 7.169 + symtab->symbols[i].size = 7.170 + symtabcmd.strsize - symtab->symbols[i].size; 7.171 + print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size); 7.172 + } 7.173 + } 7.174 + 7.175 + // build a hashtable for fast query 7.176 + build_search_table(symtab); 7.177 + return symtab; 7.178 +quit: 7.179 + if (symtab) destroy_symtab(symtab); 7.180 + return NULL; 7.181 +} 7.182 + 7.183 +#else // __APPLE__ 7.184 + 7.185 struct elf_section { 7.186 ELF_SHDR *c_shdr; 7.187 void *c_data; 7.188 }; 7.189 7.190 -struct elf_symbol { 7.191 - char *name; 7.192 - uintptr_t offset; 7.193 - uintptr_t size; 7.194 -}; 7.195 - 7.196 -typedef struct symtab { 7.197 - char *strs; 7.198 - size_t num_symbols; 7.199 - struct elf_symbol *symbols; 7.200 - DB* hash_table; 7.201 -} symtab_t; 7.202 - 7.203 // read symbol table from given fd. 7.204 struct symtab* build_symtab(int fd) { 7.205 ELF_EHDR ehdr; 7.206 @@ -176,7 +326,7 @@ 7.207 key.data = sym_name; 7.208 key.size = strlen(sym_name) + 1; 7.209 value.data = &(symtab->symbols[j]); 7.210 - value.size = sizeof(void *); 7.211 + value.size = sizeof(symtab_symbol); 7.212 (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); 7.213 } 7.214 } 7.215 @@ -201,30 +351,29 @@ 7.216 return symtab; 7.217 } 7.218 7.219 -void destroy_symtab(struct symtab* symtab) { 7.220 +#endif // __APPLE__ 7.221 + 7.222 +void destroy_symtab(symtab_t* symtab) { 7.223 if (!symtab) return; 7.224 - if (symtab->strs) free(symtab->strs); 7.225 - if (symtab->symbols) free(symtab->symbols); 7.226 - if (symtab->hash_table) { 7.227 - (*symtab->hash_table->close)(symtab->hash_table); 7.228 - } 7.229 + free(symtab->strs); 7.230 + free(symtab->symbols); 7.231 free(symtab); 7.232 } 7.233 7.234 -uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, 7.235 - const char *sym_name, int *sym_size) { 7.236 +uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_name, int *sym_size) { 7.237 DBT key, value; 7.238 int ret; 7.239 7.240 // library does not have symbol table 7.241 - if (!symtab || !symtab->hash_table) 7.242 + if (!symtab || !symtab->hash_table) { 7.243 return 0; 7.244 + } 7.245 7.246 key.data = (char*)(uintptr_t)sym_name; 7.247 key.size = strlen(sym_name) + 1; 7.248 ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0); 7.249 if (ret == 0) { 7.250 - struct elf_symbol *sym = value.data; 7.251 + symtab_symbol *sym = value.data; 7.252 uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset); 7.253 if (sym_size) *sym_size = sym->size; 7.254 return rslt; 7.255 @@ -238,7 +387,7 @@ 7.256 int n = 0; 7.257 if (!symtab) return NULL; 7.258 for (; n < symtab->num_symbols; n++) { 7.259 - struct elf_symbol* sym = &(symtab->symbols[n]); 7.260 + symtab_symbol* sym = &(symtab->symbols[n]); 7.261 if (sym->name != NULL && 7.262 offset >= sym->offset && offset < sym->offset + sym->size) { 7.263 if (poffset) *poffset = (offset - sym->offset);
8.1 --- a/agent/src/os/bsd/symtab.h Fri Mar 15 11:44:33 2013 -0700 8.2 +++ b/agent/src/os/bsd/symtab.h Sun Mar 17 08:57:56 2013 -0700 8.3 @@ -1,5 +1,5 @@ 8.4 /* 8.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 8.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 8.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.8 * 8.9 * This code is free software; you can redistribute it and/or modify it 8.10 @@ -27,11 +27,11 @@ 8.11 8.12 #include <stdint.h> 8.13 8.14 -// interface to manage ELF symbol tables 8.15 +// interface to manage ELF or MachO symbol tables 8.16 8.17 struct symtab; 8.18 8.19 -// build symbol table for a given ELF file descriptor 8.20 +// build symbol table for a given ELF or MachO file escriptor 8.21 struct symtab* build_symtab(int fd); 8.22 8.23 // destroy the symbol table
9.1 --- a/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Fri Mar 15 11:44:33 2013 -0700 9.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Sun Mar 17 08:57:56 2013 -0700 9.3 @@ -1,5 +1,5 @@ 9.4 /* 9.5 - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. 9.6 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 9.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.8 * 9.9 * This code is free software; you can redistribute it and/or modify it 9.10 @@ -34,11 +34,18 @@ 9.11 public BsdVtblAccess(SymbolLookup symbolLookup, 9.12 String[] dllNames) { 9.13 super(symbolLookup, dllNames); 9.14 - 9.15 - if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null || 9.16 - symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) { 9.17 + boolean oldVT = false; 9.18 + boolean isDarwin = dllNames[0].lastIndexOf(".dylib") != -1; 9.19 + String vtJavaThread = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; 9.20 + for (String dllName : dllNames) { 9.21 + if (symbolLookup.lookup(dllName, vtJavaThread) != null) { 9.22 + oldVT = true; 9.23 + break; 9.24 + } 9.25 + } 9.26 + if (oldVT) { 9.27 // old C++ ABI 9.28 - vt = "__vt_"; 9.29 + vt = isDarwin ? "_vt_" : "__vt_"; 9.30 } else { 9.31 // new C++ ABI 9.32 vt = "_ZTV";
10.1 --- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Fri Mar 15 11:44:33 2013 -0700 10.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Sun Mar 17 08:57:56 2013 -0700 10.3 @@ -1517,7 +1517,7 @@ 10.4 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 10.5 thread.printThreadIDOn(new PrintStream(bos)); 10.6 if (all || bos.toString().equals(name)) { 10.7 - out.println(bos.toString() + " = " + thread.getAddress()); 10.8 + out.println("Thread " + bos.toString() + " Address: " + thread.getAddress()); 10.9 HTMLGenerator gen = new HTMLGenerator(false); 10.10 try { 10.11 out.println(gen.genHTMLForJavaStackTrace(thread)); 10.12 @@ -1546,7 +1546,7 @@ 10.13 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 10.14 thread.printThreadIDOn(new PrintStream(bos)); 10.15 if (all || bos.toString().equals(name)) { 10.16 - out.println(bos.toString() + " = " + thread.getAddress()); 10.17 + out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); 10.18 if (!all) return; 10.19 } 10.20 }
11.1 --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Fri Mar 15 11:44:33 2013 -0700 11.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Sun Mar 17 08:57:56 2013 -0700 11.3 @@ -1,5 +1,5 @@ 11.4 /* 11.5 - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 11.6 + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 11.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.8 * 11.9 * This code is free software; you can redistribute it and/or modify it 11.10 @@ -311,6 +311,8 @@ 11.11 setupDebuggerLinux(); 11.12 } else if (os.equals("bsd")) { 11.13 setupDebuggerBsd(); 11.14 + } else if (os.equals("darwin")) { 11.15 + setupDebuggerDarwin(); 11.16 } else { 11.17 // Add support for more operating systems here 11.18 throw new DebuggerException("Operating system " + os + " not yet supported"); 11.19 @@ -370,6 +372,10 @@ 11.20 db = new HotSpotTypeDataBase(machDesc, 11.21 new BsdVtblAccess(debugger, jvmLibNames), 11.22 debugger, jvmLibNames); 11.23 + } else if (os.equals("darwin")) { 11.24 + db = new HotSpotTypeDataBase(machDesc, 11.25 + new BsdVtblAccess(debugger, jvmLibNames), 11.26 + debugger, jvmLibNames); 11.27 } else { 11.28 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)"); 11.29 } 11.30 @@ -459,6 +465,8 @@ 11.31 setupJVMLibNamesLinux(); 11.32 } else if (os.equals("bsd")) { 11.33 setupJVMLibNamesBsd(); 11.34 + } else if (os.equals("darwin")) { 11.35 + setupJVMLibNamesDarwin(); 11.36 } else { 11.37 throw new RuntimeException("Unknown OS type"); 11.38 } 11.39 @@ -567,6 +575,29 @@ 11.40 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; 11.41 } 11.42 11.43 + // 11.44 + // Darwin 11.45 + // 11.46 + 11.47 + private void setupDebuggerDarwin() { 11.48 + setupJVMLibNamesDarwin(); 11.49 + 11.50 + if (cpu.equals("amd64") || cpu.equals("x86_64")) { 11.51 + machDesc = new MachineDescriptionAMD64(); 11.52 + } else { 11.53 + throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu); 11.54 + } 11.55 + 11.56 + BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer); 11.57 + debugger = dbg; 11.58 + 11.59 + attachDebugger(); 11.60 + } 11.61 + 11.62 + private void setupJVMLibNamesDarwin() { 11.63 + jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" }; 11.64 + } 11.65 + 11.66 /** Convenience routine which should be called by per-platform 11.67 debugger setup. Should not be called when startupMode is 11.68 REMOTE_MODE. */
12.1 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Fri Mar 15 11:44:33 2013 -0700 12.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Sun Mar 17 08:57:56 2013 -0700 12.3 @@ -1,5 +1,5 @@ 12.4 /* 12.5 - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. 12.6 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 12.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.8 * 12.9 * This code is free software; you can redistribute it and/or modify it 12.10 @@ -31,6 +31,9 @@ 12.11 import sun.jvm.hotspot.debugger.x86.*; 12.12 import sun.jvm.hotspot.debugger.cdbg.*; 12.13 import sun.jvm.hotspot.utilities.*; 12.14 +import sun.jvm.hotspot.runtime.VM; 12.15 +import sun.jvm.hotspot.runtime.Threads; 12.16 +import sun.jvm.hotspot.runtime.JavaThread; 12.17 import java.lang.reflect.*; 12.18 12.19 /** <P> An implementation of the JVMDebugger interface. The basic debug 12.20 @@ -51,10 +54,11 @@ 12.21 public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { 12.22 private boolean useGCC32ABI; 12.23 private boolean attached; 12.24 - private long p_ps_prochandle; // native debugger handle 12.25 - private long symbolicator; // macosx symbolicator handle 12.26 - private long task; // macosx task handle 12.27 + private long p_ps_prochandle; // native debugger handle 12.28 + private long symbolicator; // macosx symbolicator handle 12.29 + private long task; // macosx task handle 12.30 private boolean isCore; 12.31 + private boolean isDarwin; // variant for bsd 12.32 12.33 // CDebugger support 12.34 private BsdCDebugger cdbg; 12.35 @@ -208,6 +212,7 @@ 12.36 } 12.37 } 12.38 12.39 + isDarwin = getOS().equals("darwin"); 12.40 workerThread = new BsdDebuggerLocalWorkerThread(this); 12.41 workerThread.start(); 12.42 } 12.43 @@ -240,8 +245,11 @@ 12.44 12.45 /* called from attach methods */ 12.46 private void findABIVersion() throws DebuggerException { 12.47 - if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 || 12.48 - lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) { 12.49 + String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so"; 12.50 + String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so"; 12.51 + String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; 12.52 + if (lookupByName0(libjvmName, javaThreadVt) != 0 || 12.53 + lookupByName0(libjvm_gName, javaThreadVt) != 0) { 12.54 // old C++ ABI 12.55 useGCC32ABI = false; 12.56 } else { 12.57 @@ -360,7 +368,8 @@ 12.58 } 12.59 12.60 if (isCore) { 12.61 - long addr = lookupByName0(objectName, symbol); 12.62 + // MacOSX symbol with "_" as leading 12.63 + long addr = lookupByName0(objectName, isDarwin ? "_" + symbol : symbol); 12.64 return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol)); 12.65 } else { 12.66 class LookupByNameTask implements WorkerThreadTask { 12.67 @@ -403,12 +412,12 @@ 12.68 public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) { 12.69 return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr); 12.70 } 12.71 + 12.72 @Override 12.73 public ThreadProxy getThreadForIdentifierAddress(Address addr) { 12.74 throw new RuntimeException("unimplemented"); 12.75 } 12.76 12.77 - 12.78 /** From the ThreadAccess interface via Debugger and JVMDebugger */ 12.79 public ThreadProxy getThreadForThreadId(long id) { 12.80 return new BsdThread(this, id); 12.81 @@ -601,6 +610,33 @@ 12.82 throw new DebuggerException("Unimplemented"); 12.83 } 12.84 12.85 + /** this functions used for core file reading and called from native attach0, 12.86 + it returns an array of long integers as 12.87 + [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for 12.88 + all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ 12.89 + public long[] getJavaThreadsInfo() { 12.90 + requireAttach(); 12.91 + Threads threads = VM.getVM().getThreads(); 12.92 + int len = threads.getNumberOfThreads(); 12.93 + long[] result = new long[len * 3]; // triple 12.94 + JavaThread t = threads.first(); 12.95 + long beg, end; 12.96 + int i = 0; 12.97 + while (t != null) { 12.98 + end = t.getStackBaseValue(); 12.99 + beg = end - t.getStackSize(); 12.100 + BsdThread bsdt = (BsdThread)t.getThreadProxy(); 12.101 + long uid = bsdt.getUniqueThreadId(); 12.102 + if (threadList != null) threadList.add(bsdt); 12.103 + result[i] = uid; 12.104 + result[i + 1] = beg; 12.105 + result[i + 2] = end; 12.106 + t = t.next(); 12.107 + i += 3; 12.108 + } 12.109 + return result; 12.110 + } 12.111 + 12.112 static { 12.113 System.loadLibrary("saproc"); 12.114 init0();
13.1 --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Fri Mar 15 11:44:33 2013 -0700 13.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Sun Mar 17 08:57:56 2013 -0700 13.3 @@ -1,5 +1,5 @@ 13.4 /* 13.5 - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. 13.6 + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 13.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.8 * 13.9 * This code is free software; you can redistribute it and/or modify it 13.10 @@ -44,7 +44,8 @@ 13.11 13.12 BsdThread(BsdDebugger debugger, long id) { 13.13 this.debugger = debugger; 13.14 - this.thread_id = (int) id; 13.15 + // use unique_thread_id to identify thread 13.16 + this.unique_thread_id = id; 13.17 } 13.18 13.19 public boolean equals(Object obj) { 13.20 @@ -52,7 +53,7 @@ 13.21 return false; 13.22 } 13.23 13.24 - return (((BsdThread) obj).thread_id == thread_id); 13.25 + return (((BsdThread) obj).unique_thread_id == unique_thread_id); 13.26 } 13.27 13.28 public int hashCode() { 13.29 @@ -80,4 +81,9 @@ 13.30 throws IllegalThreadStateException, DebuggerException { 13.31 throw new DebuggerException("Unimplemented"); 13.32 } 13.33 + 13.34 + /** this is not interface function, used in core file to get unique thread id on Macosx*/ 13.35 + public long getUniqueThreadId() { 13.36 + return unique_thread_id; 13.37 + } 13.38 }
14.1 --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Fri Mar 15 11:44:33 2013 -0700 14.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Sun Mar 17 08:57:56 2013 -0700 14.3 @@ -1,5 +1,5 @@ 14.4 /* 14.5 - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 14.6 + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 14.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.8 * 14.9 * This code is free software; you can redistribute it and/or modify it 14.10 @@ -320,6 +320,10 @@ 14.11 return stackBaseField.getValue(addr); 14.12 } 14.13 14.14 + public long getStackBaseValue() { 14.15 + return VM.getVM().getAddressValue(getStackBase()); 14.16 + } 14.17 + 14.18 public long getStackSize() { 14.19 return stackSizeField.getValue(addr); 14.20 }
15.1 --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Fri Mar 15 11:44:33 2013 -0700 15.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Sun Mar 17 08:57:56 2013 -0700 15.3 @@ -1,5 +1,5 @@ 15.4 /* 15.5 - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 15.6 + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 15.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 15.8 * 15.9 * This code is free software; you can redistribute it and/or modify it 15.10 @@ -42,6 +42,7 @@ 15.11 public class Threads { 15.12 private static JavaThreadFactory threadFactory; 15.13 private static AddressField threadListField; 15.14 + private static CIntegerField numOfThreadsField; 15.15 private static VirtualConstructor virtualConstructor; 15.16 private static JavaThreadPDAccess access; 15.17 15.18 @@ -57,6 +58,7 @@ 15.19 Type type = db.lookupType("Threads"); 15.20 15.21 threadListField = type.getAddressField("_thread_list"); 15.22 + numOfThreadsField = type.getCIntegerField("_number_of_threads"); 15.23 15.24 // Instantiate appropriate platform-specific JavaThreadFactory 15.25 String os = VM.getVM().getOS(); 15.26 @@ -102,6 +104,10 @@ 15.27 } else if (cpu.equals("amd64") || cpu.equals("x86_64")) { 15.28 access = new BsdAMD64JavaThreadPDAccess(); 15.29 } 15.30 + } else if (os.equals("darwin")) { 15.31 + if (cpu.equals("amd64") || cpu.equals("x86_64")) { 15.32 + access = new BsdAMD64JavaThreadPDAccess(); 15.33 + } 15.34 } 15.35 15.36 if (access == null) { 15.37 @@ -144,6 +150,10 @@ 15.38 return createJavaThreadWrapper(threadAddr); 15.39 } 15.40 15.41 + public int getNumberOfThreads() { 15.42 + return (int) numOfThreadsField.getValue(); 15.43 + } 15.44 + 15.45 /** Routine for instantiating appropriately-typed wrapper for a 15.46 JavaThread. Currently needs to be public for OopUtilities to 15.47 access it. */
16.1 --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Fri Mar 15 11:44:33 2013 -0700 16.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Sun Mar 17 08:57:56 2013 -0700 16.3 @@ -1,5 +1,5 @@ 16.4 /* 16.5 - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 16.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 16.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 16.8 * 16.9 * This code is free software; you can redistribute it and/or modify it 16.10 @@ -32,6 +32,7 @@ 16.11 import sun.jvm.hotspot.debugger.cdbg.*; 16.12 import sun.jvm.hotspot.oops.*; 16.13 import sun.jvm.hotspot.runtime.*; 16.14 +import sun.jvm.hotspot.utilities.PlatformInfo; 16.15 16.16 public class PStack extends Tool { 16.17 // in non-verbose mode, Method*s are not printed in java frames 16.18 @@ -54,6 +55,11 @@ 16.19 } 16.20 16.21 public void run(PrintStream out, Debugger dbg) { 16.22 + if (PlatformInfo.getOS().equals("darwin")) { 16.23 + out.println("Not available on Darwin"); 16.24 + return; 16.25 + } 16.26 + 16.27 CDebugger cdbg = dbg.getCDebugger(); 16.28 if (cdbg != null) { 16.29 ConcurrentLocksPrinter concLocksPrinter = null;
17.1 --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Fri Mar 15 11:44:33 2013 -0700 17.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Sun Mar 17 08:57:56 2013 -0700 17.3 @@ -1,5 +1,5 @@ 17.4 /* 17.5 - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. 17.6 + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 17.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 17.8 * 17.9 * This code is free software; you can redistribute it and/or modify it 17.10 @@ -43,8 +43,8 @@ 17.11 return "bsd"; 17.12 } else if (os.equals("OpenBSD")) { 17.13 return "bsd"; 17.14 - } else if (os.equals("Darwin") || os.contains("OS X")) { 17.15 - return "bsd"; 17.16 + } else if (os.contains("Darwin") || os.contains("OS X")) { 17.17 + return "darwin"; 17.18 } else if (os.startsWith("Windows")) { 17.19 return "win32"; 17.20 } else {
18.1 --- a/agent/src/share/native/sadis.c Fri Mar 15 11:44:33 2013 -0700 18.2 +++ b/agent/src/share/native/sadis.c Sun Mar 17 08:57:56 2013 -0700 18.3 @@ -1,5 +1,5 @@ 18.4 /* 18.5 - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 18.6 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 18.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.8 * 18.9 * This code is free software; you can redistribute it and/or modify it 18.10 @@ -48,7 +48,10 @@ 18.11 18.12 #include <string.h> 18.13 #include <dlfcn.h> 18.14 + 18.15 +#ifndef __APPLE__ 18.16 #include <link.h> 18.17 +#endif 18.18 18.19 #endif 18.20 18.21 @@ -109,9 +112,7 @@ 18.22 jstring libname_s) { 18.23 uintptr_t func = 0; 18.24 const char* error_message = NULL; 18.25 - const char* java_home; 18.26 jboolean isCopy; 18.27 - uintptr_t *handle = NULL; 18.28 18.29 const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ 18.30 const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); 18.31 @@ -167,7 +168,8 @@ 18.32 void* event_stream, 18.33 int (*printf_callback)(void*, const char*, ...), 18.34 void* printf_stream, 18.35 - const char* options); 18.36 + const char* options, 18.37 + int newline); 18.38 18.39 /* container for call back state when decoding instructions */ 18.40 typedef struct { 18.41 @@ -281,7 +283,7 @@ 18.42 end - start, 18.43 &event_to_env, (void*) &denv, 18.44 &printf_to_env, (void*) &denv, 18.45 - options); 18.46 + options, 0 /* newline */); 18.47 18.48 /* cleanup */ 18.49 (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
19.1 --- a/make/bsd/makefiles/saproc.make Fri Mar 15 11:44:33 2013 -0700 19.2 +++ b/make/bsd/makefiles/saproc.make Sun Mar 17 08:57:56 2013 -0700 19.3 @@ -1,5 +1,5 @@ 19.4 # 19.5 -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 19.6 +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 19.7 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.8 # 19.9 # This code is free software; you can redistribute it and/or modify it 19.10 @@ -24,7 +24,7 @@ 19.11 19.12 # Rules to build serviceability agent library, used by vm.make 19.13 19.14 -# libsaproc.so: serviceability agent 19.15 +# libsaproc.so(dylib): serviceability agent 19.16 SAPROC = saproc 19.17 19.18 ifeq ($(OS_VENDOR), Darwin) 19.19 @@ -37,7 +37,7 @@ 19.20 19.21 SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) 19.22 19.23 -NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ 19.24 +BSD_NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ 19.25 $(SASRCDIR)/symtab.c \ 19.26 $(SASRCDIR)/libproc_impl.c \ 19.27 $(SASRCDIR)/ps_proc.c \ 19.28 @@ -45,13 +45,19 @@ 19.29 $(SASRCDIR)/BsdDebuggerLocal.c \ 19.30 $(AGENT_DIR)/src/share/native/sadis.c 19.31 19.32 +DARWIN_NON_STUB_SASRCFILES = $(SASRCDIR)/symtab.c \ 19.33 + $(SASRCDIR)/libproc_impl.c \ 19.34 + $(SASRCDIR)/ps_core.c \ 19.35 + $(SASRCDIR)/MacosxDebuggerLocal.m \ 19.36 + $(AGENT_DIR)/src/share/native/sadis.c 19.37 + 19.38 ifeq ($(OS_VENDOR), FreeBSD) 19.39 - SASRCFILES = $(NON_STUB_SASRCFILES) 19.40 + SASRCFILES = $(BSD_NON_STUB_SASRCFILES) 19.41 SALIBS = -lutil -lthread_db 19.42 SAARCH = $(ARCHFLAG) 19.43 else 19.44 ifeq ($(OS_VENDOR), Darwin) 19.45 - SASRCFILES = $(SASRCDIR)/MacosxDebuggerLocal.m 19.46 + SASRCFILES = $(DARWIN_NON_STUB_SASRCFILES) 19.47 SALIBS = -g -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation 19.48 #objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles? 19.49 SAARCH = $(subst -march=i586,,$(ARCHFLAG)) 19.50 @@ -102,7 +108,7 @@ 19.51 fi 19.52 @echo Making SA debugger back-end... 19.53 $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ 19.54 - $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ 19.55 + $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ 19.56 -I$(SASRCDIR) \ 19.57 -I$(GENERATED) \ 19.58 $(BOOT_JAVA_INCLUDES) \
20.1 --- a/src/share/vm/classfile/classLoaderData.cpp Fri Mar 15 11:44:33 2013 -0700 20.2 +++ b/src/share/vm/classfile/classLoaderData.cpp Sun Mar 17 08:57:56 2013 -0700 20.3 @@ -105,6 +105,7 @@ 20.4 void ClassLoaderData::classes_do(KlassClosure* klass_closure) { 20.5 for (Klass* k = _klasses; k != NULL; k = k->next_link()) { 20.6 klass_closure->do_klass(k); 20.7 + assert(k != k->next_link(), "no loops!"); 20.8 } 20.9 } 20.10 20.11 @@ -113,6 +114,7 @@ 20.12 if (k->oop_is_instance()) { 20.13 f(InstanceKlass::cast(k)); 20.14 } 20.15 + assert(k != k->next_link(), "no loops!"); 20.16 } 20.17 } 20.18 20.19 @@ -258,6 +260,7 @@ 20.20 return; 20.21 } 20.22 prev = k; 20.23 + assert(k != k->next_link(), "no loops!"); 20.24 } 20.25 ShouldNotReachHere(); // should have found this class!! 20.26 } 20.27 @@ -439,6 +442,7 @@ 20.28 while (k != NULL) { 20.29 out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(), 20.30 k->has_modified_oops(), k->has_accumulated_modified_oops()); 20.31 + assert(k != k->next_link(), "no loops!"); 20.32 k = k->next_link(); 20.33 } 20.34 } 20.35 @@ -465,6 +469,7 @@ 20.36 for (Klass* k = _klasses; k != NULL; k = k->next_link()) { 20.37 guarantee(k->class_loader_data() == this, "Must be the same"); 20.38 k->verify(); 20.39 + assert(k != k->next_link(), "no loops!"); 20.40 } 20.41 } 20.42
21.1 --- a/src/share/vm/classfile/systemDictionary.cpp Fri Mar 15 11:44:33 2013 -0700 21.2 +++ b/src/share/vm/classfile/systemDictionary.cpp Sun Mar 17 08:57:56 2013 -0700 21.3 @@ -804,6 +804,32 @@ 21.4 } 21.5 } // load_instance_class loop 21.6 21.7 + if (HAS_PENDING_EXCEPTION) { 21.8 + // An exception, such as OOM could have happened at various places inside 21.9 + // load_instance_class. We might have partially initialized a shared class 21.10 + // and need to clean it up. 21.11 + if (class_loader.is_null()) { 21.12 + // In some cases k may be null. Let's find the shared class again. 21.13 + instanceKlassHandle ik(THREAD, find_shared_class(name)); 21.14 + if (ik.not_null()) { 21.15 + if (ik->class_loader_data() == NULL) { 21.16 + // We didn't go as far as Klass::restore_unshareable_info(), 21.17 + // so nothing to clean up. 21.18 + } else { 21.19 + MutexLocker mu(SystemDictionary_lock, THREAD); 21.20 + Klass* kk = find_class(name, ik->class_loader_data()); 21.21 + if (kk != NULL) { 21.22 + // No clean up is needed if the shared class has been entered 21.23 + // into system dictionary, as load_shared_class() won't be called 21.24 + // again. 21.25 + } else { 21.26 + clean_up_shared_class(ik, class_loader, THREAD); 21.27 + } 21.28 + } 21.29 + } 21.30 + } 21.31 + } 21.32 + 21.33 if (load_instance_added == true) { 21.34 // clean up placeholder entries for LOAD_INSTANCE success or error 21.35 // This brackets the SystemDictionary updates for both defining 21.36 @@ -1140,11 +1166,6 @@ 21.37 return load_shared_class(ik, class_loader, THREAD); 21.38 } 21.39 21.40 -// Note well! Changes to this method may affect oop access order 21.41 -// in the shared archive. Please take care to not make changes that 21.42 -// adversely affect cold start time by changing the oop access order 21.43 -// that is specified in dump.cpp MarkAndMoveOrderedReadOnly and 21.44 -// MarkAndMoveOrderedReadWrite closures. 21.45 instanceKlassHandle SystemDictionary::load_shared_class( 21.46 instanceKlassHandle ik, Handle class_loader, TRAPS) { 21.47 assert(class_loader.is_null(), "non-null classloader for shared class?"); 21.48 @@ -1205,6 +1226,19 @@ 21.49 return ik; 21.50 } 21.51 21.52 +void SystemDictionary::clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS) { 21.53 + // Updating methods must be done under a lock so multiple 21.54 + // threads don't update these in parallel 21.55 + // Shared classes are all currently loaded by the bootstrap 21.56 + // classloader, so this will never cause a deadlock on 21.57 + // a custom class loader lock. 21.58 + { 21.59 + Handle lockObject = compute_loader_lock_object(class_loader, THREAD); 21.60 + check_loader_lock_contention(lockObject, THREAD); 21.61 + ObjectLocker ol(lockObject, THREAD, true); 21.62 + ik->remove_unshareable_info(); 21.63 + } 21.64 +} 21.65 21.66 instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { 21.67 instanceKlassHandle nh = instanceKlassHandle(); // null Handle
22.1 --- a/src/share/vm/classfile/systemDictionary.hpp Fri Mar 15 11:44:33 2013 -0700 22.2 +++ b/src/share/vm/classfile/systemDictionary.hpp Sun Mar 17 08:57:56 2013 -0700 22.3 @@ -621,6 +621,7 @@ 22.4 Handle class_loader, TRAPS); 22.5 static instanceKlassHandle load_shared_class(instanceKlassHandle ik, 22.6 Handle class_loader, TRAPS); 22.7 + static void clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS); 22.8 static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS); 22.9 static Handle compute_loader_lock_object(Handle class_loader, TRAPS); 22.10 static void check_loader_lock_contention(Handle loader_lock, TRAPS);
23.1 --- a/src/share/vm/memory/metaspace.cpp Fri Mar 15 11:44:33 2013 -0700 23.2 +++ b/src/share/vm/memory/metaspace.cpp Sun Mar 17 08:57:56 2013 -0700 23.3 @@ -334,6 +334,9 @@ 23.4 23.5 // byte_size is the size of the associated virtualspace. 23.6 VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) { 23.7 + // align up to vm allocation granularity 23.8 + byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); 23.9 + 23.10 // This allocates memory with mmap. For DumpSharedspaces, allocate the 23.11 // space at low memory so that other shared images don't conflict. 23.12 // This is the same address as memory needed for UseCompressedOops but
24.1 --- a/src/share/vm/oops/klass.cpp Fri Mar 15 11:44:33 2013 -0700 24.2 +++ b/src/share/vm/oops/klass.cpp Sun Mar 17 08:57:56 2013 -0700 24.3 @@ -486,6 +486,12 @@ 24.4 } 24.5 24.6 void Klass::remove_unshareable_info() { 24.7 + if (!DumpSharedSpaces) { 24.8 + // Clean up after OOM during class loading 24.9 + if (class_loader_data() != NULL) { 24.10 + class_loader_data()->remove_class(this); 24.11 + } 24.12 + } 24.13 set_subklass(NULL); 24.14 set_next_sibling(NULL); 24.15 // Clear the java mirror
25.1 --- a/src/share/vm/oops/method.cpp Fri Mar 15 11:44:33 2013 -0700 25.2 +++ b/src/share/vm/oops/method.cpp Sun Mar 17 08:57:56 2013 -0700 25.3 @@ -798,7 +798,15 @@ 25.4 backedge_counter()->reset(); 25.5 _adapter = NULL; 25.6 _from_compiled_entry = NULL; 25.7 - assert(_method_data == NULL, "unexpected method data?"); 25.8 + 25.9 + // In case of DumpSharedSpaces, _method_data should always be NULL. 25.10 + // 25.11 + // During runtime (!DumpSharedSpaces), when we are cleaning a 25.12 + // shared class that failed to load, this->link_method() may 25.13 + // have already been called (before an exception happened), so 25.14 + // this->_method_data may not be NULL. 25.15 + assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); 25.16 + 25.17 set_method_data(NULL); 25.18 set_interpreter_throwout_count(0); 25.19 set_interpreter_invocation_count(0);