/*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); } }
/* * 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); }
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 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); }
struct ps_prochandle * dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor) { dt_proc_hash_t *dph = dtp->dt_procs; uint_t h = pid & (dph->dph_hashlen - 1); dt_proc_t *dpr, *opr; int err; /* * Search the hash table for the pid. If it is already grabbed or * created, move the handle to the front of the lrulist, increment * the reference count, and return the existing ps_prochandle. */ for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) { if (dpr->dpr_pid == pid && !dpr->dpr_stale) { /* * If the cached handle was opened read-only and * this request is for a writeable handle, mark * the cached handle as stale and open a new handle. * Since it's stale, unmark it as cacheable. */ if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) { dt_dprintf("upgrading pid %d\n", (int)pid); dpr->dpr_stale = B_TRUE; dpr->dpr_cacheable = B_FALSE; dph->dph_lrucnt--; break; } dt_dprintf("grabbed pid %d (cached)\n", (int)pid); dt_list_delete(&dph->dph_lrulist, dpr); dt_list_prepend(&dph->dph_lrulist, dpr); dpr->dpr_refs++; return (dpr->dpr_proc); } } if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); //printf("grabbing pid %d\n", pid); if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) { return (dt_proc_error(dtp, dpr, "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err))); } dpr->dpr_hdl = dtp; dpr->dpr_pid = pid; (void) Punsetflags(dpr->dpr_proc, PR_KLC); (void) Psetflags(dpr->dpr_proc, PR_RLC); /* * If we are attempting to grab the process without a monitor * thread, then mark the process cacheable only if it's being * grabbed read-only. If we're currently caching more process * handles than dph_lrulim permits, attempt to find the * least-recently-used handle that is currently unreferenced and * release it from the cache. Otherwise we are grabbing the process * for control: create a control thread for this process and store * its ID in dpr->dpr_tid. */ if (nomonitor || (flags & PGRAB_RDONLY)) { if (dph->dph_lrucnt >= dph->dph_lrulim) { for (opr = dt_list_prev(&dph->dph_lrulist); opr != NULL; opr = dt_list_prev(opr)) { if (opr->dpr_cacheable && opr->dpr_refs == 0) { dt_proc_destroy(dtp, opr->dpr_proc); break; } } } if (flags & PGRAB_RDONLY) { dpr->dpr_cacheable = B_TRUE; dpr->dpr_rdonly = B_TRUE; dph->dph_lrucnt++; } } else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0) return (NULL); /* dt_proc_error() has been called for us */ dpr->dpr_hash = dph->dph_hash[h]; dph->dph_hash[h] = dpr; dt_list_prepend(&dph->dph_lrulist, dpr); dt_dprintf("grabbed pid %d\n", (int)pid); dpr->dpr_refs++; return (dpr->dpr_proc); }
/* * 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); }
/* ARGSUSED1 */ uint_t la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) { uint_t flags; static int first = 1; int perr; /* * If this is the first time in, then l_name is the app * and unless the user gave an explict from list * we will trace calls from it. */ if (first && bindfrom_list == NULL) { flags = LA_FLG_BINDFROM | LA_FLG_BINDTO; first = 0; goto work; } /* * If we have no bindto_list, then we assume that we * bindto everything (apptrace -T \*) * * Otherwise we make sure that l_name is on the list. */ flags = 0; if (bindto_list == NULL) { flags = LA_FLG_BINDTO; } else if (check_list(bindto_list, lmp->l_name) != NULL) { flags |= LA_FLG_BINDTO; } /* * If l_name is on the exclusion list, zero the bit. */ if ((bindto_excl != NULL) && check_list(bindto_excl, lmp->l_name) != NULL) { flags &= ~LA_FLG_BINDTO; } /* * If l_name is on the bindfrom list then trace */ if (check_list(bindfrom_list, lmp->l_name) != NULL) { flags |= LA_FLG_BINDFROM; } /* * If l_name is on the exclusion list, zero the bit * else trace, (this allows "-F !foo" to imply * "-F '*' -F !foo") */ if (check_list(bindfrom_excl, lmp->l_name) != NULL) { flags &= ~LA_FLG_BINDFROM; } else if (bindfrom_excl != NULL && bindfrom_list == NULL) { flags |= LA_FLG_BINDFROM; } work: if (flags) { *cookie = (uintptr_t)abibasename(lmp->l_name); /* * only call Pgrab() once to get the ps_prochandle */ if (proc_hdl == NULL) proc_hdl = Pgrab(getpid(), PGRAB_RDONLY, &perr); } return (flags); }