static uint64_t get_zone_cap(zoneid_t zid) { rctlblk_t *rblk; uint64_t mcap; struct ps_prochandle *pr; if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) return (UINT64_MAX); if ((pr = grab_zone_proc(zid)) == NULL) { free(rblk); return (UINT64_MAX); } if (pr_getrctl(pr, "zone.max-physical-memory", NULL, rblk, RCTL_FIRST)) { Pdestroy_agent(pr); Prelease(pr, 0); free(rblk); return (UINT64_MAX); } Pdestroy_agent(pr); Prelease(pr, 0); mcap = rctlblk_get_value(rblk); free(rblk); return (mcap); }
static struct ps_prochandle * grab_zone_proc(zoneid_t zid) { DIR *dirp; struct dirent *dentp; int pid, pid_self, tmp; psinfo_t psinfo; struct ps_prochandle *pr = NULL; pid_self = getpid(); if ((dirp = opendir("/proc")) == NULL) return (NULL); while (dentp = readdir(dirp)) { pid = atoi(dentp->d_name); /* Skip self */ if (pid == pid_self) continue; if (proc_get_psinfo(pid, &psinfo) != 0) continue; if (psinfo.pr_zoneid != zid) continue; /* attempt to grab process */ if ((pr = Pgrab(pid, 0, &tmp)) != NULL) { if (Psetflags(pr, PR_RLC) != 0) { Prelease(pr, 0); } if (Pcreate_agent(pr) == 0) { if (pr_getzoneid(pr) != zid) { Prelease(pr, 0); continue; } (void) closedir(dirp); return (pr); } else { Prelease(pr, 0); } } } (void) closedir(dirp); return (NULL); }
/* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: detach0 * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_detach0 (JNIEnv *env, jobject this_obj) { struct ps_prochandle* ph = get_proc_handle(env, this_obj); if (ph != NULL) { Prelease(ph); } }
/*ARGSUSED*/ void la_activity(uintptr_t *cookie, uint_t flags) { struct ps_prochandle *P; int err, ret; GElf_Sym sym; if (flags != LA_ACT_CONSISTENT) return; while (list != NULL) { obj_list_t *node = list; char *name = node->ol_name; list = node->ol_next; P = Pgrab(getpid(), PGRAB_RDONLY, &err); ret = Plookup_by_name(P, name, "___SUNW_dof", &sym); Prelease(P, 0); if (ret == 0) { dtrace_link_dof((void *)(uintptr_t)sym.st_value, node->ol_lmid, node->ol_name, node->ol_addr); } free(node->ol_name); free(node); } }
/*PRINTFLIKE3*/ static struct ps_prochandle * dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...) { va_list ap; va_start(ap, format); dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); va_end(ap); if (dpr->dpr_proc != NULL) Prelease(dpr->dpr_proc, 0); dt_free(dtp, dpr); (void) dt_set_errno(dtp, EDT_COMPILER); return (NULL); }
// attach to the process. One and only one exposed stuff struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { struct ps_prochandle* ph = NULL; thread_info* thr = NULL; if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); print_debug("%s\n", err_buf); return NULL; } if (ptrace_attach(pid, err_buf, err_buf_len) != true) { free(ph); return NULL; } // initialize ps_prochandle ph->pid = pid; // initialize vtable ph->ops = &process_ops; // read library info and symbol tables, must do this before attaching threads, // as the symbols in the pthread library will be used to figure out // the list of threads within the same process. read_lib_info(ph); // read thread info read_thread_info(ph, add_new_thread); // attach to the threads thr = ph->threads; while (thr) { // don't attach to the main thread again if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) { // even if one attach fails, we get return NULL Prelease(ph); return NULL; } thr = thr->next; } return ph; }
static int ptime_pid(const char *pidstr) { struct ps_prochandle *Pr; pid_t pid; int gret; if ((Pr = proc_arg_grab(pidstr, PR_ARG_PIDS, Fflag | PGRAB_RDONLY, &gret)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, pidstr, Pgrab_error(gret)); return (1); } pid = Pstatus(Pr)->pr_pid; (void) sprintf(procname, "%d", (int)pid); /* for perr() */ (void) look(pid); Prelease(Pr, 0); return (0); }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: detach0 * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0 (JNIEnv *env, jobject this_obj) { jlong ps_prochandle_ptr; ps_prochandle_ptr = env->GetLongField(this_obj, ps_prochandle_ptr_ID); if(ps_prochandle_ptr != 0L) Prelease((struct ps_prochandle*) ps_prochandle_ptr, PRELEASE_CLEAR); // release libthread.so void* tdb_handle = (void*) env->GetLongField(this_obj, tdb_handle_ID); if (tdb_handle != 0) dlclose(tdb_handle); // Part of workaround for 4705086. // get libjvm[_g].so file descriptor and close it. int libjvm_fd = env->GetIntField(this_obj, libjvm_fd_ID); if (libjvm_fd != -1) close(libjvm_fd); }
static void detach_internal(JNIEnv* env, jobject this_obj) { // clear libthread_db stuff clear_libthread_db_ptrs(env, this_obj); // release ptr to ps_prochandle jlong p_ps_prochandle; p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID); if (p_ps_prochandle != 0L) { Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR); } // part of the class sharing workaround int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID); if (classes_jsa_fd != -1) { close(classes_jsa_fd); struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); if (pheader != NULL) { free(pheader); } } }
int main(int argc, char **argv) { struct ps_prochandle *P; int gerr; char *prefix = NULL; int opt; int opt_p = 0, opt_g = 0, opt_c = 0; int oflags = 0; int i; char fname[MAXPATHLEN]; char path[MAXPATHLEN]; int err = 0; core_content_t content = CC_CONTENT_DEFAULT; struct rlimit rlim; if ((pname = strrchr(argv[0], '/')) == NULL) pname = argv[0]; else argv[0] = ++pname; /* for getopt() */ while ((opt = getopt(argc, argv, "o:Fgpc:")) != EOF) { switch (opt) { case 'o': prefix = optarg; break; case 'c': if (proc_str2content(optarg, &content) != 0) { (void) fprintf(stderr, "%s: invalid " "content string '%s'\n", pname, optarg); goto usage; } opt_c = 1; break; case 'F': oflags |= PGRAB_FORCE; break; case 'p': opt_p = 1; break; case 'g': opt_g = 1; break; default: goto usage; } } if ((opt_p | opt_g) == 0) { if (prefix == NULL) prefix = "core"; } else { int options; if ((options = core_get_options()) == -1) { perror("core_get_options()"); return (1); } if (opt_p && !(options & CC_PROCESS_PATH)) { (void) fprintf(stderr, "%s: per-process core dumps " "are disabled (ignoring -p)\n", pname); opt_p = 0; } if (opt_g && !(options & CC_GLOBAL_PATH)) { (void) fprintf(stderr, "%s: global core dumps " "are disabled (ignoring -g)\n", pname); opt_g = 0; } if ((opt_p | opt_g) == 0 && prefix == NULL) return (1); } argc -= optind; argv += optind; if (argc == 0) goto usage; /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } for (i = 0; i < argc; i++) { P = proc_arg_grab(argv[i], PR_ARG_PIDS, oflags, &gerr); if (P == NULL) { (void) fprintf(stderr, "%s: cannot grab %s: %s\n", pname, argv[i], Pgrab_error(gerr)); err++; continue; } if (prefix != NULL) { (void) snprintf(path, sizeof (path), "%s.%%p", prefix); convert_path(path, fname, sizeof (fname), P); gcore(P, fname, content, &err); } if (opt_p) { pid_t pid = Pstatus(P)->pr_pid; (void) core_get_process_path(path, sizeof (path), pid); convert_path(path, fname, sizeof (fname), P); if (!opt_c) (void) core_get_process_content(&content, pid); gcore(P, fname, content, &err); } if (opt_g) { /* * Global core files are always just readable and * writable by their owner so we temporarily change * the umask. */ mode_t oldmode = umask(S_IXUSR | S_IRWXG | S_IRWXO); (void) core_get_global_path(path, sizeof (path)); convert_path(path, fname, sizeof (fname), P); if (!opt_c) (void) core_get_global_content(&content); gcore(P, fname, content, &err); (void) umask(oldmode); } Prelease(P, 0); } return (err != 0); usage: (void) fprintf(stderr, "usage: %s " "[ -pgF ] [ -o filename ] [ -c content ] pid ...\n", pname); return (2); }
/* * Force the parent process (ppid) to wait for its child process (pid). */ static int reap(char *arg, pid_t *reap_pid, int *exit_status) { struct ps_prochandle *Pr; siginfo_t siginfo; psinfo_t psinfo; prusage_t usage; pid_t pid, ppid; time_t elapsed; int gret; /* * get the specified pid and the psinfo struct */ if ((pid = proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gret)) == -1) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gret)); return (1); } if (psinfo.pr_nlwp != 0) { (void) fprintf(stderr, "%s: process not defunct: %d\n", command, (int)pid); return (1); } *exit_status = psinfo.pr_wstat; *reap_pid = psinfo.pr_pid; ppid = psinfo.pr_ppid; if (ppid == 1) { (void) fprintf(stderr, "%s: Failed to reap %d: the only " "non-defunct ancestor is 'init'\n", command, (int)pid); return (1); } if (proc_usage(pid, &usage, &gret) == 0) { elapsed = usage.pr_tstamp.tv_sec - usage.pr_term.tv_sec; } else { (void) fprintf(stderr, "%s: cannot examine %d: %s\n", command, (int)pid, Pgrab_error(gret)); return (1); } if ((Fflag == 0) && (elapsed < NOREAP_TIME)) { (void) fprintf(stderr, "%s: unsafe to reap %d; it has been " "defunct less than %d seconds\n", command, (int)pid, NOREAP_TIME); return (1); } if ((Pr = Pgrab(ppid, Fflag | PGRAB_NOSTOP, &gret)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %d: %s\n", command, (int)ppid, Pgrab_error(gret)); return (1); } if ((Fflag == 0) && (Pstate(Pr) == PS_STOP)) { Prelease(Pr, 0); (void) fprintf(stderr, "%s: unsafe to reap %d; parent is " "stopped and may reap status upon restart\n", command, (int)pid); return (1); } /* * Pstop() will fail if the process to be stopped has become a zombie. * This means that we can say with certainty that the child of this * process has not changed parents (i.e. been reparented to init) once * the Pstop() succeeds. */ if (Pstop(Pr, 1000) != 0) { Prelease(Pr, 0); (void) fprintf(stderr, "%s: failed to stop %d: %s", command, (int)ppid, strerror(errno)); return (1); } if (pr_waitid(Pr, P_PID, pid, &siginfo, WEXITED|WNOHANG) != 0) { Prelease(Pr, 0); (void) fprintf(stderr, "%s: waitid() in process %d failed: %s", command, (int)ppid, strerror(errno)); return (1); } Prelease(Pr, 0); return (0); }
// the one and only one exposed stuff from this file struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { ELF_EHDR core_ehdr; ELF_EHDR exec_ehdr; ELF_EHDR lib_ehdr; struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); if (ph == NULL) { print_debug("can't allocate ps_prochandle\n"); return NULL; } if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { free(ph); print_debug("can't allocate ps_prochandle\n"); return NULL; } // initialize ph ph->ops = &core_ops; ph->core->core_fd = -1; ph->core->exec_fd = -1; ph->core->interp_fd = -1; // open the core file if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { print_debug("can't open core file\n"); goto err; } // read core file ELF header if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { print_debug("core file is not a valid ELF ET_CORE file\n"); goto err; } if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { print_debug("can't open executable file\n"); goto err; } if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { print_debug("executable file is not a valid ELF ET_EXEC file\n"); goto err; } // process core file segments if (read_core_segments(ph, &core_ehdr) != true) goto err; // process exec file segments if (read_exec_segments(ph, &exec_ehdr) != true) goto err; // exec file is also treated like a shared object for symbol search if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) goto err; // allocate and sort maps into map_array, we need to do this // here because read_shared_lib_info needs to read from debuggee // address space if (sort_map_array(ph) != true) goto err; if (read_shared_lib_info(ph) != true) goto err; // sort again because we have added more mappings from shared objects if (sort_map_array(ph) != true) goto err; if (init_classsharing_workaround(ph) != true) goto err; return ph; err: Prelease(ph); return NULL; }
static int look(char *arg) { struct ps_prochandle *Pr; static prcred_t *prcred = NULL; int gcode; procname = arg; /* for perr() */ if (prcred == NULL) { prcred = malloc(sizeof (prcred_t) + (ngroups_max - 1) * sizeof (gid_t)); if (prcred == NULL) { (void) perr("malloc"); exit(1); } } if ((Pr = proc_arg_grab(arg, doset ? PR_ARG_PIDS : PR_ARG_ANY, PGRAB_RETAIN | PGRAB_FORCE | (doset ? 0 : PGRAB_RDONLY) | PGRAB_NOSTOP, &gcode)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gcode)); return (1); } if (Pcred(Pr, prcred, ngroups_max) == -1) { (void) perr("getcred"); Prelease(Pr, 0); return (1); } if (doset) { credupdate(prcred); if (Psetcred(Pr, prcred) != 0) { (void) perr("setcred"); Prelease(Pr, 0); return (1); } Prelease(Pr, 0); return (0); } if (Pstate(Pr) == PS_DEAD) (void) printf("core of %d:\t", (int)Pstatus(Pr)->pr_pid); else (void) printf("%d:\t", (int)Pstatus(Pr)->pr_pid); if (!all && prcred->pr_euid == prcred->pr_ruid && prcred->pr_ruid == prcred->pr_suid) (void) printf("e/r/suid=%u ", prcred->pr_euid); else (void) printf("euid=%u ruid=%u suid=%u ", prcred->pr_euid, prcred->pr_ruid, prcred->pr_suid); if (!all && prcred->pr_egid == prcred->pr_rgid && prcred->pr_rgid == prcred->pr_sgid) (void) printf("e/r/sgid=%u\n", prcred->pr_egid); else (void) printf("egid=%u rgid=%u sgid=%u\n", prcred->pr_egid, prcred->pr_rgid, prcred->pr_sgid); if (prcred->pr_ngroups != 0 && (all || prcred->pr_ngroups != 1 || prcred->pr_groups[0] != prcred->pr_rgid)) { int i; (void) printf("\tgroups:"); for (i = 0; i < prcred->pr_ngroups; i++) (void) printf(" %u", prcred->pr_groups[i]); (void) printf("\n"); } Prelease(Pr, 0); return (0); }
static int look(char *arg) { struct ps_prochandle *Pr; int gcode; size_t sz; void *pdata; char *x; int i; boolean_t nodata; prpriv_t *ppriv; procname = arg; /* for perr() */ if ((Pr = proc_arg_grab(arg, set ? PR_ARG_PIDS : PR_ARG_ANY, PGRAB_RETAIN | PGRAB_FORCE | (set ? 0 : PGRAB_RDONLY) | PGRAB_NOSTOP, &gcode)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gcode)); return (1); } if (Ppriv(Pr, &ppriv) == -1) { perr(command); Prelease(Pr, 0); return (1); } sz = PRIV_PRPRIV_SIZE(ppriv); /* * The ppriv fields are unsigned and may overflow, so check them * separately. Size must be word aligned, so check that too. * Make sure size is "smallish" too. */ if ((sz & 3) || ppriv->pr_nsets == 0 || sz / ppriv->pr_nsets < ppriv->pr_setsize || ppriv->pr_infosize > sz || sz > 1024 * 1024) { (void) fprintf(stderr, "%s: %s: bad PRNOTES section, size = %lx\n", command, arg, (long)sz); Prelease(Pr, 0); Ppriv_free(Pr, ppriv); return (1); } if (set) { privupdate(ppriv, arg); if (Psetpriv(Pr, ppriv) != 0) { perr(command); Prelease(Pr, 0); Ppriv_free(Pr, ppriv); return (1); } Prelease(Pr, 0); Ppriv_free(Pr, ppriv); return (0); } if (Pstate(Pr) == PS_DEAD) { (void) printf("core '%s' of %d:\t%.70s\n", arg, (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs); pdata = Pprivinfo(Pr); nodata = Pstate(Pr) == PS_DEAD && pdata == NULL; } else { (void) printf("%d:\t%.70s\n", (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs); pdata = NULL; nodata = B_FALSE; } x = (char *)ppriv + sz - ppriv->pr_infosize; while (x < (char *)ppriv + sz) { /* LINTED: alignment */ priv_info_t *pi = (priv_info_t *)x; priv_info_uint_t *pii; switch (pi->priv_info_type) { case PRIV_INFO_FLAGS: /* LINTED: alignment */ pii = (priv_info_uint_t *)x; (void) printf("flags ="); flags2str(pii->val); (void) putchar('\n'); break; default: (void) fprintf(stderr, "%s: unknown priv_info: %d\n", arg, pi->priv_info_type); break; } if (pi->priv_info_size > ppriv->pr_infosize || pi->priv_info_size <= sizeof (priv_info_t) || (pi->priv_info_size & 3) != 0) { (void) fprintf(stderr, "%s: bad priv_info_size: %u\n", arg, pi->priv_info_size); break; } x += pi->priv_info_size; } for (i = 0; i < ppriv->pr_nsets; i++) { extern const char *__priv_getsetbynum(const void *, int); const char *setnm = pdata ? __priv_getsetbynum(pdata, i) : priv_getsetbynum(i); priv_chunk_t *pc = (priv_chunk_t *)&ppriv->pr_sets[ppriv->pr_setsize * i]; (void) printf("\t%c: ", setnm && !nodata ? *setnm : '?'); if (!nodata) { extern char *__priv_set_to_str(void *, const priv_set_t *, char, int); priv_set_t *pset = (priv_set_t *)pc; char *s; if (pdata) s = __priv_set_to_str(pdata, pset, ',', mode); else s = priv_set_to_str(pset, ',', mode); (void) puts(s); free(s); } else { int j; for (j = 0; j < ppriv->pr_setsize; j++) (void) printf("%08x", pc[j]); (void) putchar('\n'); } } Prelease(Pr, 0); Ppriv_free(Pr, ppriv); return (0); }
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); }
static void dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P) { dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE); dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_notify_t *npr, **npp; int rflag; assert(dpr != NULL); /* * If neither PR_KLC nor PR_RLC is set, then the process is stopped by * an external debugger and we were waiting in dt_proc_waitrun(). * Leave the process in this condition using PRELEASE_HANG. */ printf("dt_proc_destroy flags=%d\n", Pstatus(dpr->dpr_proc)->pr_flags); if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) { dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid); rflag = PRELEASE_HANG; } else { dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid); rflag = 0; /* apply kill or run-on-last-close */ } if (dpr->dpr_tid) { /* * Set the dpr_quit flag to tell the daemon thread to exit. We * send it a SIGCANCEL to poke it out of PCWSTOP or any other * long-term /proc system call. Our daemon threads have POSIX * cancellation disabled, so EINTR will be the only effect. We * then wait for dpr_done to indicate the thread has exited. * * We can't use pthread_kill() to send SIGCANCEL because the * interface forbids it and we can't use pthread_cancel() * because with cancellation disabled it won't actually * send SIGCANCEL to the target thread, so we use _lwp_kill() * to do the job. This is all built on evil knowledge of * the details of the cancellation mechanism in libc. */ (void) pthread_mutex_lock(&dpr->dpr_lock); dpr->dpr_quit = B_TRUE; #if defined(sun) (void) _lwp_kill(dpr->dpr_tid, SIGCANCEL); #else (void) pthread_kill(dpr->dpr_tid, SIGUSR1); #endif /* * If the process is currently idling in dt_proc_stop(), re- * enable breakpoints and poke it into running again. */ if (dpr->dpr_stop & DT_PROC_STOP_IDLE) { dt_proc_bpenable(dpr); dpr->dpr_stop &= ~DT_PROC_STOP_IDLE; (void) pthread_cond_broadcast(&dpr->dpr_cv); } while (!dpr->dpr_done) (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); (void) pthread_mutex_unlock(&dpr->dpr_lock); } /* * Before we free the process structure, remove this dt_proc_t from the * lookup hash, and then walk the dt_proc_hash_t's notification list * and remove this dt_proc_t if it is enqueued. */ (void) pthread_mutex_lock(&dph->dph_lock); (void) dt_proc_lookup(dtp, P, B_TRUE); npp = &dph->dph_notify; while ((npr = *npp) != NULL) { if (npr->dprn_dpr == dpr) { *npp = npr->dprn_next; dt_free(dtp, npr); } else { npp = &npr->dprn_next; } } (void) pthread_mutex_unlock(&dph->dph_lock); /* * Remove the dt_proc_list from the LRU list, release the underlying * libproc handle, and free our dt_proc_t data structure. */ if (dpr->dpr_cacheable) { assert(dph->dph_lrucnt != 0); dph->dph_lrucnt--; } dt_list_delete(&dph->dph_lrulist, dpr); Prelease(dpr->dpr_proc, rflag); dt_free(dtp, dpr); }
static int look(char *arg) { int gcode; int gcode2; pstatus_t pstatus; psinfo_t psinfo; int flags; sigset_t sigmask; fltset_t fltmask; sysset_t entryset; sysset_t exitset; uint32_t sigtrace, sigtrace1, sigtrace2, fltbits; uint32_t sigpend, sigpend1, sigpend2; uint32_t *bits; char buf[PRSIGBUFSZ]; look_arg_t lookarg; if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, PGRAB_RETAIN | PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &gcode, &lookarg.lwps)) == NULL) { if (gcode == G_NOPROC && proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gcode2) > 0 && psinfo.pr_nlwp == 0) { (void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid); return (0); } (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gcode)); return (1); } (void) memcpy(&pstatus, Pstatus(Pr), sizeof (pstatus_t)); (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); proc_unctrl_psinfo(&psinfo); if (psinfo.pr_nlwp == 0) { (void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid); Prelease(Pr, PRELEASE_RETAIN); return (0); } is64 = (pstatus.pr_dmodel == PR_MODEL_LP64); sigmask = pstatus.pr_sigtrace; fltmask = pstatus.pr_flttrace; entryset = pstatus.pr_sysentry; exitset = pstatus.pr_sysexit; if (Pstate(Pr) == PS_DEAD) { (void) printf("core '%s' of %d:\t%.70s\n", arg, (int)psinfo.pr_pid, psinfo.pr_psargs); } else { (void) printf("%d:\t%.70s\n", (int)psinfo.pr_pid, psinfo.pr_psargs); } (void) printf("\tdata model = %s", is64? "_LP64" : "_ILP32"); if ((flags = (pstatus.pr_flags & PROCFLAGS)) != 0) (void) printf(" flags = %s", prflags(flags)); (void) printf("\n"); fltbits = *((uint32_t *)&fltmask); if (fltbits) (void) printf("\tflttrace = 0x%.8x\n", fltbits); #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */ sigtrace = *((uint32_t *)&sigmask); sigtrace1 = *((uint32_t *)&sigmask + 1); sigtrace2 = *((uint32_t *)&sigmask + 2); #else #error "fix me: MAXSIG out of bounds" #endif if (sigtrace | sigtrace1 | sigtrace2) (void) printf("\tsigtrace = 0x%.8x 0x%.8x 0x%.8x\n\t %s\n", sigtrace, sigtrace1, sigtrace2, proc_sigset2str(&sigmask, "|", 1, buf, sizeof (buf))); bits = ((uint32_t *)&entryset); if (bits[0] | bits[1] | bits[2] | bits[3] | bits[4] | bits[5] | bits[6] | bits[7]) (void) printf( "\tentryset = " "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" "\t " "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); bits = ((uint32_t *)&exitset); if (bits[0] | bits[1] | bits[2] | bits[3] | bits[4] | bits[5] | bits[6] | bits[7]) (void) printf( "\texitset = " "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" "\t " "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]); #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */ sigpend = *((uint32_t *)&pstatus.pr_sigpend); sigpend1 = *((uint32_t *)&pstatus.pr_sigpend + 1); sigpend2 = *((uint32_t *)&pstatus.pr_sigpend + 2); #else #error "fix me: MAXSIG out of bounds" #endif if (sigpend | sigpend1 | sigpend2) (void) printf("\tsigpend = 0x%.8x,0x%.8x,0x%.8x\n", sigpend, sigpend1, sigpend2); lookarg.pflags = pstatus.pr_flags; lookarg.count = 0; (void) Plwp_iter_all(Pr, (proc_lwp_all_f *)lwplook, &lookarg); if (lookarg.count == 0) (void) printf("No matching lwps found"); (void) printf("\n"); Prelease(Pr, PRELEASE_RETAIN); return (0); }
int main(int argc, char **argv) { int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; int errflg = 0, Sflag = 0; int rc = 0; int opt; const char *bar8 = "-------"; const char *bar16 = "----------"; const char *bar; struct rlimit rlim; struct stat64 statbuf; char buf[128]; int mapfd; int prg_gflags = PGRAB_RDONLY; int prr_flags = 0; boolean_t use_agent_lwp = B_FALSE; if ((command = strrchr(argv[0], '/')) != NULL) command++; else command = argv[0]; while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { switch (opt) { case 'a': /* include shared mappings in -[xS] */ aflag = 1; break; case 'r': /* show reserved mappings */ rflag = 1; break; case 's': /* show hardware page sizes */ sflag = 1; break; case 'S': /* show swap reservations */ Sflag = 1; break; case 'x': /* show extended mappings */ xflag = 1; break; case 'l': /* show unresolved link map names */ lflag = 1; break; case 'L': /* show lgroup information */ Lflag = 1; use_agent_lwp = B_TRUE; break; case 'F': /* force grabbing (no O_EXCL) */ Fflag = PGRAB_FORCE; break; case 'A': if (parse_addr_range(optarg, &start_addr, &end_addr) != 0) errflg++; break; default: errflg = 1; break; } } argc -= optind; argv += optind; if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || (aflag && (!xflag && !Sflag)) || (Lflag && (xflag || Sflag))) { errflg = 1; } if (errflg || argc <= 0) { (void) fprintf(stderr, "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", command); (void) fprintf(stderr, "\t\t(report process address maps)\n"); (void) fprintf(stderr, "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); (void) fprintf(stderr, "\t\t(report process address maps lgroups mappings)\n"); (void) fprintf(stderr, "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); (void) fprintf(stderr, "\t\t(show resident/anon/locked mapping details)\n"); (void) fprintf(stderr, "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", command); (void) fprintf(stderr, "\t\t(show swap reservations)\n\n"); (void) fprintf(stderr, "\t-a: include shared mappings in -[xS] summary\n"); (void) fprintf(stderr, "\t-r: show reserved address maps\n"); (void) fprintf(stderr, "\t-s: show hardware page sizes\n"); (void) fprintf(stderr, "\t-l: show unresolved dynamic linker map names\n"); (void) fprintf(stderr, "\t-F: force grabbing of the target process\n"); (void) fprintf(stderr, "\t-L: show lgroup mappings\n"); (void) fprintf(stderr, "\t-A start,end: limit output to the specified range\n"); return (2); } /* * Make sure we'll have enough file descriptors to handle a target * that has many many mappings. */ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rlim); (void) enable_extended_FILE_stdio(-1, -1); } /* * The implementation of -L option creates an agent LWP in the target * process address space. The agent LWP issues meminfo(2) system calls * on behalf of the target process. If we are interrupted prematurely, * the target process remains in the stopped state with the agent still * attached to it. To prevent such situation we catch signals from * terminal and terminate gracefully. */ if (use_agent_lwp) { /* * Buffer output to stdout, stderr while process is grabbed. * Prevents infamous deadlocks due to pmap `pgrep xterm` and * other variants. */ (void) proc_initstdio(); prg_gflags = PGRAB_RETAIN | Fflag; prr_flags = PRELEASE_RETAIN; if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) (void) sigset(SIGHUP, intr); if (sigset(SIGINT, SIG_IGN) == SIG_DFL) (void) sigset(SIGINT, intr); if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) (void) sigset(SIGQUIT, intr); (void) sigset(SIGPIPE, intr); (void) sigset(SIGTERM, intr); } while (argc-- > 0) { char *arg; int gcode; psinfo_t psinfo; int tries = 0; if (use_agent_lwp) (void) proc_flushstdio(); if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, prg_gflags, &gcode)) == NULL) { (void) fprintf(stderr, "%s: cannot examine %s: %s\n", command, arg, Pgrab_error(gcode)); rc++; continue; } procname = arg; /* for perr() */ addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; bar = addr_width == 8 ? bar8 : bar16; (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); proc_unctrl_psinfo(&psinfo); if (Pstate(Pr) != PS_DEAD) { (void) snprintf(buf, sizeof (buf), "/proc/%d/map", (int)psinfo.pr_pid); if ((mapfd = open(buf, O_RDONLY)) < 0) { (void) fprintf(stderr, "%s: cannot " "examine %s: lost control of " "process\n", command, arg); rc++; Prelease(Pr, prr_flags); continue; } } else { mapfd = -1; } again: map_count = 0; if (Pstate(Pr) == PS_DEAD) { (void) printf("core '%s' of %d:\t%.70s\n", arg, (int)psinfo.pr_pid, psinfo.pr_psargs); if (rflag || sflag || xflag || Sflag || Lflag) { (void) printf(" -%c option is not compatible " "with core files\n", xflag ? 'x' : sflag ? 's' : rflag ? 'r' : Lflag ? 'L' : 'S'); Prelease(Pr, prr_flags); rc++; continue; } } else { (void) printf("%d:\t%.70s\n", (int)psinfo.pr_pid, psinfo.pr_psargs); } if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { struct totals t; /* * Since we're grabbing the process readonly, we need * to make sure the address space doesn't change during * execution. */ if (Pstate(Pr) != PS_DEAD) { if (tries++ == MAX_TRIES) { Prelease(Pr, prr_flags); (void) close(mapfd); (void) fprintf(stderr, "%s: cannot " "examine %s: address space is " "changing\n", command, arg); continue; } if (fstat64(mapfd, &statbuf) != 0) { Prelease(Pr, prr_flags); (void) close(mapfd); (void) fprintf(stderr, "%s: cannot " "examine %s: lost control of " "process\n", command, arg); continue; } } nstacks = psinfo.pr_nlwp * 2; stacks = calloc(nstacks, sizeof (stacks[0])); if (stacks != NULL) { int n = 0; (void) Plwp_iter(Pr, getstack, &n); qsort(stacks, nstacks, sizeof (stacks[0]), cmpstacks); } (void) memset(&t, 0, sizeof (t)); if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { (void) fprintf(stderr, "%s: warning: " "librtld_db failed to initialize; " "shared library information will not be " "available\n", command); } /* * Gather data */ if (xflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 0); else if (Sflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 1); else { if (rflag) rc += rmapping_iter(Pr, gather_map, NULL); else if (sflag) rc += xmapping_iter(Pr, gather_xmap, NULL, 0); else if (lflag) rc += Pmapping_iter(Pr, gather_map, NULL); else rc += Pmapping_iter_resolved(Pr, gather_map, NULL); } /* * Ensure mappings are consistent. */ if (Pstate(Pr) != PS_DEAD) { struct stat64 newbuf; if (fstat64(mapfd, &newbuf) != 0 || memcmp(&newbuf.st_mtim, &statbuf.st_mtim, sizeof (newbuf.st_mtim)) != 0) { if (stacks != NULL) { free(stacks); stacks = NULL; } goto again; } } /* * Display data. */ if (xflag) { (void) printf("%*s%*s%*s%*s%*s " "%sMode Mapped File\n", addr_width, "Address", size_width, "Kbytes", size_width, "RSS", size_width, "Anon", size_width, "Locked", sflag ? "Pgsz " : ""); rc += iter_xmap(sflag ? look_xmap : look_xmap_nopgsz, &t); (void) printf("%s%s %s %s %s %s\n", addr_width == 8 ? "-" : "------", bar, bar, bar, bar, bar); (void) printf("%stotal Kb", addr_width == 16 ? " " : ""); printK(t.total_size, size_width); printK(t.total_rss, size_width); printK(t.total_anon, size_width); printK(t.total_locked, size_width); (void) printf("\n"); } else if (Sflag) { (void) printf("%*s%*s%*s Mode" " Mapped File\n", addr_width, "Address", size_width, "Kbytes", size_width, "Swap"); rc += iter_xmap(look_xmap_nopgsz, &t); (void) printf("%s%s %s %s\n", addr_width == 8 ? "-" : "------", bar, bar, bar); (void) printf("%stotal Kb", addr_width == 16 ? " " : ""); printK(t.total_size, size_width); printK(t.total_swap, size_width); (void) printf("\n"); } else { if (rflag) { rc += iter_map(look_map, &t); } else if (sflag) { if (Lflag) { (void) printf("%*s %*s %4s" " %-6s %s %s\n", addr_width, "Address", size_width, "Bytes", "Pgsz", "Mode ", "Lgrp", "Mapped File"); rc += iter_xmap(look_smap, &t); } else { (void) printf("%*s %*s %4s" " %-6s %s\n", addr_width, "Address", size_width, "Bytes", "Pgsz", "Mode ", "Mapped File"); rc += iter_xmap(look_smap, &t); } } else { rc += iter_map(look_map, &t); } (void) printf(" %stotal %*luK\n", addr_width == 16 ? " " : "", size_width, t.total_size); } if (stacks != NULL) { free(stacks); stacks = NULL; } } Prelease(Pr, prr_flags); if (mapfd != -1) (void) close(mapfd); } if (use_agent_lwp) (void) proc_finistdio(); return (rc); }
int main(int argc, char **argv) { secflagdelta_t act; psecflagwhich_t which = PSF_INHERIT; int ret = 0; int pgrab_flags = PGRAB_RDONLY; int opt; char *idtypename = NULL; idtype_t idtype = P_PID; boolean_t usage = B_FALSE; boolean_t e_flag = B_FALSE; boolean_t l_flag = B_FALSE; boolean_t s_flag = B_FALSE; int errc = 0; while ((opt = getopt(argc, argv, "eFi:ls:")) != -1) { switch (opt) { case 'e': e_flag = B_TRUE; break; case 'F': pgrab_flags |= PGRAB_FORCE; break; case 'i': idtypename = optarg; break; case 's': s_flag = B_TRUE; if ((strlen(optarg) >= 2) && ((optarg[1] == '='))) { switch (optarg[0]) { case 'L': which = PSF_LOWER; break; case 'U': which = PSF_UPPER; break; case 'I': which = PSF_INHERIT; break; case 'E': errx(1, "the effective flags cannot " "be changed", optarg[0]); default: errx(1, "unknown security flag " "set: '%c'", optarg[0]); } optarg += 2; } if (secflags_parse(NULL, optarg, &act) == -1) errx(1, "couldn't parse security flags: %s", optarg); break; case 'l': l_flag = B_TRUE; break; default: usage = B_TRUE; break; } } argc -= optind; argv += optind; if (l_flag && ((idtypename != NULL) || s_flag || (argc != 0))) usage = B_TRUE; if ((idtypename != NULL) && !s_flag) usage = B_TRUE; if (e_flag && !s_flag) usage = B_TRUE; if (!l_flag && argc <= 0) usage = B_TRUE; if (usage) { (void) fprintf(stderr, gettext("usage:\t%s [-F] { pid | core } ...\n"), __progname); (void) fprintf(stderr, gettext("\t%s -s spec [-i idtype] id ...\n"), __progname); (void) fprintf(stderr, gettext("\t%s -s spec -e command [arg]...\n"), __progname); (void) fprintf(stderr, gettext("\t%s -l\n"), __progname); return (2); } if (l_flag) { secflag_t i; const char *name; for (i = 0; (name = secflag_to_str(i)) != NULL; i++) (void) printf("%s\n", name); return (0); } else if (s_flag && e_flag) { /* * Don't use the strerror() message for EPERM, "Not Owner" * which is misleading. */ errc = psecflags(P_PID, P_MYID, which, &act); switch (errc) { case 0: break; case EPERM: errx(1, gettext("failed setting " "security-flags: Permission denied")); break; default: err(1, gettext("failed setting security-flags")); } (void) execvp(argv[0], &argv[0]); err(1, "%s", argv[0]); } else if (s_flag) { int i; id_t id; if (idtypename != NULL) if (str2idtype(idtypename, &idtype) == -1) errx(1, gettext("No such id type: '%s'"), idtypename); for (i = 0; i < argc; i++) { if ((id = getid(idtype, argv[i])) == (id_t)-1) { errx(1, gettext("invalid or non-existent " "identifier: '%s'"), argv[i]); } /* * Don't use the strerror() message for EPERM, "Not * Owner" which is misleading. */ if (psecflags(idtype, id, which, &act) != 0) { switch (errno) { case EPERM: errx(1, gettext("failed setting " "security-flags: " "Permission denied")); break; default: err(1, gettext("failed setting " "security-flags")); } } } return (0); } /* Display the flags for the given pids */ while (argc-- > 0) { struct ps_prochandle *Pr; const char *arg; psinfo_t psinfo; prsecflags_t *psf; int gcode; if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, pgrab_flags, &gcode)) == NULL) { warnx(gettext("cannot examine %s: %s"), arg, Pgrab_error(gcode)); ret = 1; continue; } (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); proc_unctrl_psinfo(&psinfo); if (Pstate(Pr) == PS_DEAD) { (void) printf(gettext("core '%s' of %d:\t%.70s\n"), arg, (int)psinfo.pr_pid, psinfo.pr_psargs); } else { (void) printf("%d:\t%.70s\n", (int)psinfo.pr_pid, psinfo.pr_psargs); } if (Psecflags(Pr, &psf) != 0) err(1, gettext("cannot read secflags of %s"), arg); print_flags("E", psf->pr_effective); print_flags("I", psf->pr_inherit); print_flags("L", psf->pr_lower); print_flags("U", psf->pr_upper); Psecflags_free(psf); Prelease(Pr, 0); } return (ret); }