/* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: init0 * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_init0 (JNIEnv *env, jclass cls) { jclass listClass; if (init_libproc(getenv("LIBSAPROC_DEBUG")) != true) { THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc"); } // fields we use p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); CHECK_EXCEPTION; threadList_ID = (*env)->GetFieldID(env, cls, "threadList", "Ljava/util/List;"); CHECK_EXCEPTION; loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); CHECK_EXCEPTION; // methods we use createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); CHECK_EXCEPTION; createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); CHECK_EXCEPTION; getThreadForThreadId_ID = (*env)->GetMethodID(env, cls, "getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;"); CHECK_EXCEPTION; // java.util.List method we call listClass = (*env)->FindClass(env, "java/util/List"); CHECK_EXCEPTION; listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); CHECK_EXCEPTION; }
/* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: attach0 * Signature: (I)V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I (JNIEnv *env, jobject this_obj, jint jpid) { struct ps_prochandle* ph; if ( (ph = Pgrab(jpid)) == NULL) { THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); } (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph); }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: writeBytesToProcess0 * Signature: (JJ[B)V * Description: write bytes into debugger process */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0 (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) { jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID); jboolean isCopy; jbyte* ptr = env->GetByteArrayElements(data, &isCopy); CHECK_EXCEPTION; if (ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes) != PS_OK) { env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); THROW_NEW_DEBUGGER_EXCEPTION("Process write failed!"); } env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: initIDs * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs (JNIEnv *env, jclass clazz) { void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL); if (libproc_handle == 0) THROW_NEW_DEBUGGER_EXCEPTION("Can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!"); ps_prochandle_ptr_ID = env->GetFieldID(clazz, "ps_prochandle_ptr", "J"); CHECK_EXCEPTION; tdb_handle_ID = env->GetFieldID(clazz, "tdb_handle", "J"); CHECK_EXCEPTION; p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J"); CHECK_EXCEPTION; p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J"); CHECK_EXCEPTION; p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J"); CHECK_EXCEPTION; p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J"); CHECK_EXCEPTION; p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J"); CHECK_EXCEPTION; p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J"); CHECK_EXCEPTION; setThreadIntegerRegisterSet_ID = env->GetMethodID(clazz, "setThreadIntegerRegisterSet", "(I[J)V"); CHECK_EXCEPTION; // Part of workaround for 4705086. // libjvm file descriptor libjvm_fd_ID = env->GetFieldID(clazz, "libjvm_fd", "I"); CHECK_EXCEPTION; // libjvm start virtual address libjvm_text_start_ID = env->GetFieldID(clazz, "libjvm_text_start", "J"); CHECK_EXCEPTION; // size of text in libjvm[_g].so. libjvm_text_size_ID = env->GetFieldID(clazz, "libjvm_text_size", "J"); CHECK_EXCEPTION; }
/* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: attach0 * Signature: (Ljava/lang/String;Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 (JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) { const char *execName_cstr; const char *coreName_cstr; jboolean isCopy; struct ps_prochandle* ph; execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); CHECK_EXCEPTION; coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); CHECK_EXCEPTION; if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); } (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); fillThreadsAndLoadObjects(env, this_obj, ph); }
static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) { jboolean isCopy; int gcode; const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy); CHECK_EXCEPTION; // some older versions of libproc.so crash when trying to attach 32 bit // debugger to 64 bit core file. check and throw error. #ifndef _LP64 atoi(cmdLine_cstr); if (errno) { // core file int core_fd; if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) { Elf32_Ehdr e32; if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) && memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 && e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) { close(core_fd); THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger"); } close(core_fd); } // all other conditions are handled by libproc.so. } #endif // connect to process/core ps_prochandle_t* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode, NULL); env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr); if (! ph) { if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]); THROW_NEW_DEBUGGER_EXCEPTION(errMsg); } else { if (_libsaproc_debug && gcode == G_STRANGE) { perror("libsaproc DEBUG: "); } if (isProcess) { THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!"); } else { THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!"); } } } // even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't // support such cross-bit-debugging. check for that combination and throw error. #ifdef _LP64 int data_model; if (ps_pdmodel(ph, &data_model) != PS_OK) { Prelease(ph, PRELEASE_CLEAR); THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)"); } if (data_model == PR_MODEL_ILP32) { Prelease(ph, PRELEASE_CLEAR); THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger"); } #endif env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph); Debugger dbg; dbg.env = env; dbg.this_obj = this_obj; jthrowable exception = 0; if (! isProcess) { /* * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ. * These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped * in Solaris core.To read shared heap pages, we have to read classes.jsa file. */ Pobject_iter(ph, init_classsharing_workaround, &dbg); exception = env->ExceptionOccurred(); if (exception) { env->ExceptionClear(); detach_internal(env, this_obj); env->Throw(exception); return; } } /* * Iterate over the process mappings looking * for libthread and then dlopen the appropriate * libthread_db and get function pointers. */ Pobject_iter(ph, init_libthread_db_ptrs, &dbg); exception = env->ExceptionOccurred(); if (exception) { env->ExceptionClear(); if (!sa_ignore_threaddb) { detach_internal(env, this_obj); env->Throw(exception); } return; } // init libthread_db and create thread_db agent p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID); if (p_td_init == 0) { if (!sa_ignore_threaddb) { detach_internal(env, this_obj); } HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!"); } if (p_td_init() != TD_OK) { if (!sa_ignore_threaddb) { detach_internal(env, this_obj); } HANDLE_THREADDB_FAILURE("Can't initialize thread_db!"); } p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID); td_thragent_t *p_td_thragent_t = 0; if (p_td_ta_new(ph, &p_td_thragent_t) != TD_OK) { if (!sa_ignore_threaddb) { detach_internal(env, this_obj); } HANDLE_THREADDB_FAILURE("Can't create thread_db agent!"); } env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t); }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: initIDs * Signature: ()V * Description: get JNI ids for fields and methods of ProcDebuggerLocal class */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs (JNIEnv *env, jclass clazz) { _libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL; if (_libsaproc_debug) { // propagate debug mode to libproc.so static const char* var = "LIBPROC_DEBUG=1"; putenv((char*)var); } void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL); if (libproc_handle == 0) THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!"); p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J"); CHECK_EXCEPTION; libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J"); CHECK_EXCEPTION; p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J"); CHECK_EXCEPTION; p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J"); CHECK_EXCEPTION; p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J"); CHECK_EXCEPTION; p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J"); CHECK_EXCEPTION; p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J"); CHECK_EXCEPTION; p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J"); CHECK_EXCEPTION; p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J"); CHECK_EXCEPTION; p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J"); CHECK_EXCEPTION; getThreadForThreadId_ID = env->GetMethodID(clazz, "getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;"); CHECK_EXCEPTION; pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I"); CHECK_EXCEPTION; fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I"); CHECK_EXCEPTION; createSenderFrame_ID = env->GetMethodID(clazz, "createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;"); CHECK_EXCEPTION; createLoadObject_ID = env->GetMethodID(clazz, "createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); CHECK_EXCEPTION; createClosestSymbol_ID = env->GetMethodID(clazz, "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); CHECK_EXCEPTION; jclass list_clazz = env->FindClass("java/util/List"); CHECK_EXCEPTION; listAdd_ID = env->GetMethodID(list_clazz, "add", "(Ljava/lang/Object;)Z"); CHECK_EXCEPTION; // part of the class sharing workaround classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I"); CHECK_EXCEPTION; p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J"); CHECK_EXCEPTION; }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: attach0 * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0 (JNIEnv *env, jobject this_obj, jstring cmdLine) { jboolean isCopy; int gcode; const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy); CHECK_EXCEPTION; struct ps_prochandle* Pr = proc_arg_grab(cmdLine_cstr, PR_ARG_ANY, PGRAB_FORCE, &gcode); env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr); if(! Pr) THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process/core file!"); env->SetLongField(this_obj, ps_prochandle_ptr_ID, (jlong) Pr); // initialize libthread_db pointers /* * Iterate over the process mappings looking * for libthread and then dlopen the appropriate * libthread_db and get pointers to functions. */ Debugger dbg; dbg.env = env; dbg.obj = this_obj; (void) Pobject_iter(Pr, object_iter, &dbg); CHECK_EXCEPTION; // get the user level threads info td_thragent_t *Tap = 0; p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID); if (p_td_init == 0) return; p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID); if (p_td_init() != TD_OK) THROW_NEW_DEBUGGER_EXCEPTION("Can't initialize thread_db!"); if (p_td_ta_new(Pr, &Tap) != TD_OK) THROW_NEW_DEBUGGER_EXCEPTION("Can't create thread_db agent!"); /* * Iterate over all threads, calling: * thr_stack(td_thrhandle_t *Thp, NULL); * for each one to generate the list of threads. */ p_td_ta_thr_iter_t p_td_ta_thr_iter = (p_td_ta_thr_iter_t) env->GetLongField(this_obj, p_td_ta_thr_iter_ID); (void) p_td_ta_thr_iter(Tap, thr_stack, &dbg, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); CHECK_EXCEPTION; p_td_ta_delete_t p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID); (void) p_td_ta_delete(Tap); // Part of workaround for 4705086. /* * iterate over maps of the process/core to get first * libjvm[_g].so mapping. */ Pmapping_iter(Pr, iterate_map, &dbg); CHECK_EXCEPTION; /* * Get libjvm[_g].so text size. First location after the end of text segment * is marked by the global reserved symbol '_etext' in any ELF file. * Please refer to page 53 of "Linkers and Libraries Guide - 816-0559". */ psaddr_t etext_addr; if (ps_pglobal_lookup(Pr, "libjvm.so", "_etext", &etext_addr) != PS_OK) { // try the debug version if (ps_pglobal_lookup(Pr, "libjvm_g.so", "_etext", &etext_addr) != PS_OK) THROW_NEW_DEBUGGER_EXCEPTION("Can't get end of text address of libjvm!"); } // now calculate and set libjvm text size. jlong libjvm_text_start = env->GetLongField(this_obj, libjvm_text_start_ID); env->SetLongField(this_obj, libjvm_text_size_ID, (jlong) (etext_addr - libjvm_text_start)); }