/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: fillLoadObjectList0 * Signature: (Ljava/util/List;)V * Description: fills shared objects of the debuggee process/core */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillLoadObjectList0 (JNIEnv *env, jobject this_obj, jobject list) { DebuggerWithObject dbgo; dbgo.env = env; dbgo.this_obj = this_obj; dbgo.obj = list; jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID); Pobject_iter((struct ps_prochandle*) p_ps_prochandle, fill_load_object_list, &dbgo); }
lx_handle_dlsym_t lx_call_init(void) { struct ps_prochandle *ph; lookup_cb_arg_t lca; extern int __libc_threaded; int err; lx_debug("lx_call_init(): looking up Linux dlsym"); /* * The handle is really the address of the Linux "dlsym" function. * Once we have this address we can call into the Linux "dlsym" * function to lookup other functions. It's the initial lookup * of "dlsym" that's difficult. To do this we'll leverage the * brand support that we added to librtld_db. We're going * to fire up a seperate native solaris process that will * attach to us via libproc/librtld_db and lookup the symbol * for us. */ /* Make sure we're single threaded. */ if (__libc_threaded) { lx_debug("lx_call_init() fail: " "process must be single threaded"); return (NULL); } /* Tell libproc.so where the real procfs is mounted. */ Pset_procfs_path("/native/proc"); /* Tell librtld_db.so where the real /native is */ (void) rd_ctl(RD_CTL_SET_HELPPATH, "/native"); /* Grab ourselves but don't stop ourselves. */ if ((ph = Pgrab(getpid(), PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &err)) == NULL) { lx_debug("lx_call_init() fail: Pgrab failed: %s", Pgrab_error(err)); return (NULL); } lca.lca_ph = ph; lca.lca_ptr = NULL; if (Pobject_iter(ph, lookup_cb, &lca) == -1) { lx_debug("lx_call_init() fail: couldn't find Linux dlsym"); return (NULL); } lx_debug("lx_call_init(): Linux dlsym = 0x%p", lca.lca_ptr); return ((lx_handle_dlsym_t)lca.lca_ptr); }
static int python_db_init(void) { struct ps_prochandle *Ph; if (mdb_get_xdata("pshandle", &Ph, sizeof (Ph)) == -1) { mdb_warn("couldn't read pshandle xdata\n"); dlclose(pydb_dlhdl); pydb_dlhdl = NULL; return (-1); } (void) Pobject_iter(Ph, python_object_iter, Ph); pydb_agent_create = (pydb_agent_create_f) dlsym(pydb_dlhdl, "pydb_agent_create"); pydb_agent_destroy = (pydb_agent_destroy_f) dlsym(pydb_dlhdl, "pydb_agent_destroy"); pydb_get_frameinfo = (pydb_get_frameinfo_f) dlsym(pydb_dlhdl, "pydb_get_frameinfo"); pydb_frame_iter_init = (pydb_iter_init_f) dlsym(pydb_dlhdl, "pydb_frame_iter_init"); pydb_interp_iter_init = (pydb_iter_init_f) dlsym(pydb_dlhdl, "pydb_interp_iter_init"); pydb_thread_iter_init = (pydb_iter_init_f) dlsym(pydb_dlhdl, "pydb_thread_iter_init"); pydb_iter_next = (pydb_iter_next_f)dlsym(pydb_dlhdl, "pydb_iter_next"); pydb_iter_fini = (pydb_iter_fini_f)dlsym(pydb_dlhdl, "pydb_iter_fini"); if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || pydb_get_frameinfo == NULL || pydb_frame_iter_init == NULL || pydb_interp_iter_init == NULL || pydb_thread_iter_init == NULL || pydb_iter_next == NULL || pydb_iter_fini == NULL) { mdb_warn("couldn't load pydb functions"); dlclose(pydb_dlhdl); pydb_dlhdl = NULL; return (-1); } pydb_hdl = pydb_agent_create(Ph, PYDB_VERSION); if (pydb_hdl == NULL) { mdb_warn("unable to create pydb_agent"); dlclose(pydb_dlhdl); pydb_dlhdl = NULL; return (-1); } return (0); }
static int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr) { struct ps_prochandle *P = dpr->dpr_proc; int ret = 0; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); #if defined(sun) (void) Pupdate_maps(P); if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) { ret = -1; (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT, "failed to instantiate probes for pid %d: %s", #if defined(sun) (int)Pstatus(P)->pr_pid, strerror(errno)); #else (int)proc_getpid(P), strerror(errno)); #endif }
static int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr) { struct ps_prochandle *P = dpr->dpr_proc; int ret = 0; assert(MUTEX_HELD(&dpr->dpr_lock)); (void) Pupdate_maps(P); if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) { ret = -1; (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT, "failed to instantiate probes for pid %d: %s", (int)Pstatus(P)->pr_pid, strerror(errno)); } /* * Put the module name in its canonical form. */ (void) dt_pid_fix_mod(pdp, P); return (ret); }
static int dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr) { dt_pid_probe_t pp; int ret = 0; pp.dpp_dtp = dtp; pp.dpp_dpr = dpr; pp.dpp_pr = dpr->dpr_proc; pp.dpp_pcb = pcb; #ifdef DOODAD /* * We can only trace dynamically-linked executables (since we've * hidden some magic in ld.so.1 as well as libc.so.1). */ if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) { return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN, "process %s is not a dynamically-linked executable", &pdp->dtpd_provider[3])); } #endif pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*"; pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*"; pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*"; pp.dpp_last_taken = 0; if (strcmp(pp.dpp_func, "-") == 0) { const prmap_t *aout, *pmp; if (pdp->dtpd_mod[0] == '\0') { pp.dpp_mod = pdp->dtpd_mod; (void) strcpy(pdp->dtpd_mod, "a.out"); } else if (strisglob(pp.dpp_mod) || (aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL || (pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL || aout->pr_vaddr != pmp->pr_vaddr) { return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB, "only the a.out module is valid with the " "'-' function")); } if (strisglob(pp.dpp_name)) { return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_NAME, "only individual addresses may be specified " "with the '-' function")); } } /* * If pp.dpp_mod contains any globbing meta-characters, we need * to iterate over each module and compare its name against the * pattern. An empty module name is treated as '*'. */ if (strisglob(pp.dpp_mod)) { ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp); } else { const prmap_t *pmp; char *obj; /* * If we can't find a matching module, don't sweat it -- either * we'll fail the enabling because the probes don't exist or * we'll wait for that module to come along. */ if ((pmp = dt_pid_fix_mod(pdp, pp.dpp_pr)) != NULL) { if ((obj = strchr(pdp->dtpd_mod, '`')) == NULL) obj = pdp->dtpd_mod; else obj++; ret = dt_pid_per_mod(&pp, pmp, obj); } } return (ret); }
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: 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)); }