/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: lookupByName0 * Signature: (Ljava/lang/String;Ljava/lang/String;)J * Description: symbol lookup by name */ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName0 (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { jlong p_ps_prochandle; p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID); jboolean isCopy; const char* objectName_cstr = NULL; if (objectName != NULL) { objectName_cstr = env->GetStringUTFChars(objectName, &isCopy); CHECK_EXCEPTION_(0); } else { objectName_cstr = PR_OBJ_EVERY; } const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy); CHECK_EXCEPTION_(0); psaddr_t symbol_addr = (psaddr_t) 0; ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle, objectName_cstr, symbolName_cstr, &symbol_addr); if (symbol_addr == 0) { print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr); } if (objectName_cstr != PR_OBJ_EVERY) { env->ReleaseStringUTFChars(objectName, objectName_cstr); } env->ReleaseStringUTFChars(symbolName, symbolName_cstr); return (jlong) (uintptr_t) symbol_addr; }
ps_err_e td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) { ps_err_e result; assert (idx >= 0 && idx < SYM_NUM_MESSAGES); result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], sym_addr); #ifdef HAVE_ASM_GLOBAL_DOT_NAME /* For PowerPC, 64-bit uses dot symbols but 32-bit does not. We could be a 64-bit libthread_db debugging a 32-bit libpthread. */ if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.') result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1], sym_addr); #endif return result; }
ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *mod, int idx, psaddr_t *sym_addr) { ps_err_e result; assert (idx >= 0 && idx < SYM_NUM_MESSAGES); result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr); return result; }
static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { psaddr_t sym_addr; int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); if (err == PS_OK) { err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); return err; } *valuep = -1; return -1; }
static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { psaddr_t sym_addr; int err; err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); if (err != PS_OK) goto fail; *valuep = sym_addr; return PS_OK; fail: return err; }
static int parse_vmstructs(jvm_agent_t* J) { VMStructEntry vmVar; VMStructEntry* vmp = &vmVar; uint64_t gHotSpotVMStructs; psaddr_t sym_addr; uint64_t base; int err; /* Clear *vmp now in case we jump to fail: */ memset(vmp, 0, sizeof(VMStructEntry)); err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); CHECK_FAIL(err); err = read_pointer(J, sym_addr, &gHotSpotVMStructs); CHECK_FAIL(err); base = gHotSpotVMStructs; err = PS_OK; while (err == PS_OK) { memset(vmp, 0, sizeof(VMStructEntry)); err = parse_vmstruct_entry(J, base, vmp); if (err != PS_OK || vmp->typeName == NULL) { break; } if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { /* Read _heaps field of type GrowableArray<CodeHeaps*>* */ if (strcmp("_heaps", vmp->fieldName) == 0) { err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address); } } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { J->Universe_narrow_oop_base_address = vmp->address; } if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { J->Universe_narrow_oop_shift_address = vmp->address; } } CHECK_FAIL(err); base += SIZE_VMStructEntry; if (vmp->typeName != NULL) free((void*)vmp->typeName); if (vmp->fieldName != NULL) free((void*)vmp->fieldName); } return PS_OK; fail: if (vmp->typeName != NULL) free((void*)vmp->typeName); if (vmp->fieldName != NULL) free((void*)vmp->fieldName); return -1; }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: lookup0 * Signature: (Ljava/lang/String;Ljava/lang/String;)J */ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookup0 (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { jlong ps_prochandle_ptr; ps_prochandle_ptr = env->GetLongField(this_obj, ps_prochandle_ptr_ID); jboolean isCopy; const char* objectName_cstr = env->GetStringUTFChars(objectName, &isCopy); CHECK_EXCEPTION_(0); const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy); CHECK_EXCEPTION_(0); psaddr_t symbol_addr = (psaddr_t) 0; ps_pglobal_lookup((struct ps_prochandle*) ps_prochandle_ptr, objectName_cstr, symbolName_cstr, &symbol_addr); env->ReleaseStringUTFChars(objectName, objectName_cstr); env->ReleaseStringUTFChars(symbolName, symbolName_cstr); return (jlong) symbol_addr; }
td_err_e td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out) { int32_t err; /* * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up * the symbol from it's cache, which is populated at start time with the * symbols returned from td_symbol_list via calls back to the host. */ switch (event) { case TD_CREATE: err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr); if (err) { return TD_NOEVENT; } return TD_OK; } return TD_NOEVENT; }
td_err_e td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event) { td_err_e err; void * bkpt_addr; err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr); if (err) { return err; } err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0); if (err != 0x42) { return TD_NOMSG; } event->event = TD_CREATE; event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way! return TD_OK; }
static int init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) { Debugger* dbg = (Debugger*) cd; JNIEnv* env = dbg->env; jobject this_obj = dbg->this_obj; const char* jvm_name = 0; if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) { jvm_name = obj_name; } else { return 0; } struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID); // initialize classes.jsa file descriptor field. dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1); // check whether class sharing is on by reading variable "UseSharedSpaces" psaddr_t useSharedSpacesAddr = 0; ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr); if (useSharedSpacesAddr == 0) { THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1); } // read the value of the flag "UseSharedSpaces" // Since hotspot types are not available to build this library. So // equivalent type "jboolean" is used to read the value of "UseSharedSpaces" // which is same as hotspot type "bool". jboolean value = 0; if (read_jboolean(ph, useSharedSpacesAddr, &value) != true) { THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1); } else if ((int)value == 0) { print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); return 1; } char classes_jsa[PATH_MAX]; psaddr_t sharedArchivePathAddrAddr = 0; ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr); if (sharedArchivePathAddrAddr == 0) { print_debug("can't find symbol 'Arguments::SharedArchivePath'\n"); THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1); } uintptr_t sharedArchivePathAddr = 0; if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n"); THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1); } if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { print_debug("can't find read 'Arguments::SharedArchivePath' value\n"); THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1); } print_debug("looking for %s\n", classes_jsa); // open the classes.jsa int fd = libsaproc_open(classes_jsa, O_RDONLY); if (fd < 0) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "can't open shared archive file %s", classes_jsa); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } else { print_debug("opened shared archive file %s\n", classes_jsa); } // parse classes.jsa struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader)); if (pheader == NULL) { close(fd); THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1); } memset(pheader, 0, sizeof(struct FileMapHeader)); // read FileMapHeader size_t n = read(fd, pheader, sizeof(struct FileMapHeader)); if (n != sizeof(struct FileMapHeader)) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa); close(fd); free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check file magic if (pheader->_magic != 0xf00baba2) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2", classes_jsa, pheader->_magic); close(fd); free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } // check version if (pheader->_version != CURRENT_ARCHIVE_VERSION) { char errMsg[ERR_MSG_SIZE]; sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d", classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION); close(fd); free(pheader); THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1); } if (_libsaproc_debug) { for (int m = 0; m < NUM_SHARED_MAPS; m++) { print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n", pheader->_space[m]._file_offset, pheader->_space[m]._base, pheader->_space[m]._used, pheader->_space[m]._read_only); } } // FIXME: For now, omitting other checks such as VM version etc. // store class archive file fd and map header in debugger object fields dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd); dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader); return 1; }
int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) { assert (idx >= 0 && idx < NUM_MESSAGES); return ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], sym_addr); }
/* * 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)); }