/*ARGSUSED*/ static void prochandler(struct ps_prochandle *P, const char *msg, void *arg) { #if !defined(__APPLE__) const psinfo_t *prp = Ppsinfo(P); int pid = Pstatus(P)->pr_pid; char name[SIG2STR_MAX]; #else #define SIG2STR_MAX 32 /* Not referenced so long as prp just below is NULL. */ #define proc_signame(x,y,z) "Unknown" /* Not referenced so long as prp just below is NULL. */ typedef struct psinfo { int pr_wstat; } psinfo_t; const psinfo_t *prp = NULL; int pid = Pstatus(P)->pr_pid; #endif /* __APPLE__ */ if (msg != NULL) { notice("pid %d: %s\n", pid, msg); return; } switch (Pstate(P)) { case PS_UNDEAD: /* * Ideally we would like to always report pr_wstat here, but it * isn't possible given current /proc semantics. If we grabbed * the process, Ppsinfo() will either fail or return a zeroed * psinfo_t depending on how far the parent is in reaping it. * When /proc provides a stable pr_wstat in the status file, * this code can be improved by examining this new pr_wstat. */ if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { notice("pid %d terminated by %s\n", pid, proc_signame(WTERMSIG(prp->pr_wstat), name, sizeof (name))); } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { notice("pid %d exited with status %d\n", pid, WEXITSTATUS(prp->pr_wstat)); } else { notice("pid %d has exited\n", pid); } g_exited = 1; break; case PS_LOST: #if !defined(__APPLE__) notice("pid %d exec'd a set-id or unobservable program\n", pid); #else notice("pid %d has exited\n", pid); #endif g_exited = 1; break; } }
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); }
/*ARGSUSED*/ static void prochandler(struct ps_prochandle *P, const char *msg, void *arg) { #if defined(sun) const psinfo_t *prp = Ppsinfo(P); int pid = Pstatus(P)->pr_pid; char name[SIG2STR_MAX]; #else int wstatus = proc_getwstat(P); int pid = proc_getpid(P); #endif if (msg != NULL) { notice("pid %d: %s\n", pid, msg); return; } #if defined(sun) switch (Pstate(P)) { #else switch (proc_state(P)) { #endif case PS_UNDEAD: #if defined(sun) /* * Ideally we would like to always report pr_wstat here, but it * isn't possible given current /proc semantics. If we grabbed * the process, Ppsinfo() will either fail or return a zeroed * psinfo_t depending on how far the parent is in reaping it. * When /proc provides a stable pr_wstat in the status file, * this code can be improved by examining this new pr_wstat. */ if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { notice("pid %d terminated by %s\n", pid, proc_signame(WTERMSIG(prp->pr_wstat), name, sizeof (name))); #else if (WIFSIGNALED(wstatus)) { notice("pid %d terminated by %d\n", pid, WTERMSIG(wstatus)); #endif #if defined(sun) } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { notice("pid %d exited with status %d\n", pid, WEXITSTATUS(prp->pr_wstat)); #else } else if (WEXITSTATUS(wstatus) != 0) { notice("pid %d exited with status %d\n", pid, WEXITSTATUS(wstatus)); #endif } else { notice("pid %d has exited\n", pid); } g_pslive--; break; case PS_LOST: notice("pid %d exec'd a set-id or unobservable program\n", pid); g_pslive--; break; } } /*ARGSUSED*/ static int errhandler(const dtrace_errdata_t *data, void *arg) { error(data->dteda_msg); return (DTRACE_HANDLE_OK); } /*ARGSUSED*/ static int drophandler(const dtrace_dropdata_t *data, void *arg) { error(data->dtdda_msg); return (DTRACE_HANDLE_OK); }
static int dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop) { dt_proc_control_data_t data; sigset_t nset, oset; pthread_attr_t a; int err; #if defined(linux) /***********************************************/ /* Kernel bug -- a parent which attaches to */ /* a proc -- cannot share with a child */ /* thread. So we have to detach and */ /* reattach in the child thread if we are */ /* to work properly. */ /***********************************************/ if (stop == DT_PROC_STOP_GRAB) { do_ptrace(__func__, PTRACE_DETACH, dpr->dpr_pid, 0, 0); } #endif (void) pthread_mutex_lock(&dpr->dpr_lock); dpr->dpr_stop |= stop; /* set bit for initial rendezvous */ (void) pthread_attr_init(&a); (void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); (void) sigfillset(&nset); (void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */ #if defined(sun) (void) sigdelset(&nset, SIGCANCEL); /* see dt_proc_destroy() */ #else (void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */ #endif data.dpcd_hdl = dtp; data.dpcd_proc = dpr; (void) pthread_sigmask(SIG_SETMASK, &nset, &oset); err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data); (void) pthread_sigmask(SIG_SETMASK, &oset, NULL); do_ptrace(__func__, PTRACE_DETACH, dpr->dpr_pid, 0, 0); /* * If the control thread was created, then wait on dpr_cv for either * dpr_done to be set (the victim died or the control thread failed) * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now * stopped by /proc and the control thread is at the rendezvous event. * On success, we return with the process and control thread stopped: * the caller can then apply dt_proc_continue() to resume both. */ if (err == 0) { //printf("0..waiting for dt_proc_control....dpr_done=%d stop=%d !stop=%d\n", dpr->dpr_done, dpr->dpr_stop, !(dpr->dpr_stop & DT_PROC_STOP_IDLE)); while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE)) { //printf("1..waiting for dt_proc_control....dpr_done=%d stop=%d\n", dpr->dpr_done, dpr->dpr_stop); (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); } //printf("2..waiting for dt_proc_control....dpr_done=%d stop=%d\n", dpr->dpr_done, dpr->dpr_stop); /* * If dpr_done is set, the control thread aborted before it * reached the rendezvous event. This is either due to PS_LOST * or PS_UNDEAD (i.e. the process died). We try to provide a * small amount of useful information to help figure it out. */ if (dpr->dpr_done) { const psinfo_t *prp = Ppsinfo(dpr->dpr_proc); int stat = prp ? prp->pr_wstat : 0; int pid = dpr->dpr_pid; if (Pstate(dpr->dpr_proc) == PS_LOST) { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process exec'd " "set-id or unobservable program\n", pid); } else if (WIFSIGNALED(stat)) { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process died " "from signal %d\n", pid, WTERMSIG(stat)); } else { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to control pid %d: process exited " "with status %d\n", pid, WEXITSTATUS(stat)); } err = ESRCH; /* cause grab() or create() to fail */ } } else { (void) dt_proc_error(dpr->dpr_hdl, dpr, "failed to create control thread for process-id %d: %s\n", (int)dpr->dpr_pid, strerror(err)); } (void) pthread_mutex_unlock(&dpr->dpr_lock); (void) pthread_attr_destroy(&a); return (err); }
static void convert_path(const char *path, char *fname, size_t size, struct ps_prochandle *P) { char *p, *s; ssize_t len; const psinfo_t *pip = Ppsinfo(P); int got_uts = 0; struct utsname uts; char exec[PATH_MAX]; fname[size - 1] = '\0'; size--; while ((p = strchr(path, '%')) != NULL && size != 0) { len = MIN(size, p - path); bcopy(path, fname, len); fname += len; if ((size -= len) == 0) break; p++; switch (*p) { case 'p': len = snprintf(fname, size, "%d", (int)pip->pr_pid); break; case 'u': len = snprintf(fname, size, "%d", (int)pip->pr_uid); break; case 'g': len = snprintf(fname, size, "%d", (int)pip->pr_gid); break; case 'f': len = snprintf(fname, size, "%s", pip->pr_fname); break; case 'd': len = 0; if (Pexecname(P, exec, sizeof (exec)) == NULL || exec[0] != '/' || (s = strrchr(exec, '/')) == NULL) break; *s = '\0'; len = snprintf(fname, size, "%s", &exec[1]); break; case 'n': if (got_uts++ == 0) (void) uname(&uts); len = snprintf(fname, size, "%s", uts.nodename); break; case 'm': if (got_uts++ == 0) (void) uname(&uts); len = snprintf(fname, size, "%s", uts.machine); break; case 't': len = snprintf(fname, size, "%ld", (long)time(NULL)); break; case 'z': /* * getzonenamebyid() returns the size including the * terminating null byte so we need to adjust len. */ if ((len = getzonenamebyid(pip->pr_zoneid, fname, size)) < 0) len = snprintf(fname, size, "%d", (int)pip->pr_zoneid); else len--; break; case '%': *fname = '%'; len = 1; break; default: len = snprintf(fname, size, "%%%c", *p); } if (len >= size) return; fname += len; size -= len; path = p + 1; } (void) strncpy(fname, path, size); }
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); }
/* * Don't explicity stop the process; that's up to the consumer. */ int Pfgcore(struct ps_prochandle *P, int fd, core_content_t content) { char plat[SYS_NMLN]; char zonename[ZONENAME_MAX]; int platlen = -1; pgcore_t pgc; off64_t poff, soff, doff, boff; struct utsname uts; uint_t nphdrs, nshdrs; if (ftruncate64(fd, 0) != 0) return (-1); if (content == CC_CONTENT_INVALID) { errno = EINVAL; return (-1); } /* * Cache the mappings and other useful data. */ (void) Prd_agent(P); (void) Ppsinfo(P); pgc.P = P; pgc.pgc_fd = fd; pgc.pgc_poff = &poff; pgc.pgc_soff = &soff; pgc.pgc_doff = &doff; pgc.pgc_content = content; pgc.pgc_chunksz = PAGESIZE; if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL) return (-1); shstrtab_init(&pgc.pgc_shstrtab); /* * There are two PT_NOTE program headers for ancillary data, and * one for each mapping. */ nphdrs = 2 + P->map_count; nshdrs = count_sections(&pgc); (void) Pplatform(P, plat, sizeof (plat)); platlen = strlen(plat) + 1; Preadauxvec(P); (void) Puname(P, &uts); if (Pzonename(P, zonename, sizeof (zonename)) == NULL) zonename[0] = '\0'; /* * The core file contents may required zero section headers, but if we * overflow the 16 bits allotted to the program header count in the ELF * header, we'll need that program header at index zero. */ if (nshdrs == 0 && nphdrs >= PN_XNUM) nshdrs = 1; /* * Set up the ELF header. */ if (P->status.pr_dmodel == PR_MODEL_ILP32) { Elf32_Ehdr ehdr; bzero(&ehdr, sizeof (ehdr)); ehdr.e_ident[EI_MAG0] = ELFMAG0; ehdr.e_ident[EI_MAG1] = ELFMAG1; ehdr.e_ident[EI_MAG2] = ELFMAG2; ehdr.e_ident[EI_MAG3] = ELFMAG3; ehdr.e_type = ET_CORE; ehdr.e_ident[EI_CLASS] = ELFCLASS32; #if defined(__sparc) ehdr.e_machine = EM_SPARC; ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #elif defined(__i386) || defined(__amd64) ehdr.e_machine = EM_386; ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #else #error "unknown machine type" #endif ehdr.e_ident[EI_VERSION] = EV_CURRENT; ehdr.e_version = EV_CURRENT; ehdr.e_ehsize = sizeof (ehdr); if (nphdrs >= PN_XNUM) ehdr.e_phnum = PN_XNUM; else ehdr.e_phnum = (unsigned short)nphdrs; ehdr.e_phentsize = sizeof (Elf32_Phdr); ehdr.e_phoff = ehdr.e_ehsize; if (nshdrs > 0) { if (nshdrs >= SHN_LORESERVE) ehdr.e_shnum = 0; else ehdr.e_shnum = (unsigned short)nshdrs; if (nshdrs - 1 >= SHN_LORESERVE) ehdr.e_shstrndx = SHN_XINDEX; else ehdr.e_shstrndx = (unsigned short)(nshdrs - 1); ehdr.e_shentsize = sizeof (Elf32_Shdr); ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs; } if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0) goto err; poff = ehdr.e_phoff; soff = ehdr.e_shoff; doff = boff = ehdr.e_ehsize + ehdr.e_phentsize * nphdrs + ehdr.e_shentsize * nshdrs; #ifdef _LP64 } else { Elf64_Ehdr ehdr; bzero(&ehdr, sizeof (ehdr)); ehdr.e_ident[EI_MAG0] = ELFMAG0; ehdr.e_ident[EI_MAG1] = ELFMAG1; ehdr.e_ident[EI_MAG2] = ELFMAG2; ehdr.e_ident[EI_MAG3] = ELFMAG3; ehdr.e_type = ET_CORE; ehdr.e_ident[EI_CLASS] = ELFCLASS64; #if defined(__sparc) ehdr.e_machine = EM_SPARCV9; ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #elif defined(__i386) || defined(__amd64) ehdr.e_machine = EM_AMD64; ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #else #error "unknown machine type" #endif ehdr.e_ident[EI_VERSION] = EV_CURRENT; ehdr.e_version = EV_CURRENT; ehdr.e_ehsize = sizeof (ehdr); if (nphdrs >= PN_XNUM) ehdr.e_phnum = PN_XNUM; else ehdr.e_phnum = (unsigned short)nphdrs; ehdr.e_phentsize = sizeof (Elf64_Phdr); ehdr.e_phoff = ehdr.e_ehsize; if (nshdrs > 0) { if (nshdrs >= SHN_LORESERVE) ehdr.e_shnum = 0; else ehdr.e_shnum = (unsigned short)nshdrs; if (nshdrs - 1 >= SHN_LORESERVE) ehdr.e_shstrndx = SHN_XINDEX; else ehdr.e_shstrndx = (unsigned short)(nshdrs - 1); ehdr.e_shentsize = sizeof (Elf64_Shdr); ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs; } if (gc_pwrite64(fd, &ehdr, sizeof (ehdr), 0) != 0) goto err; poff = ehdr.e_phoff; soff = ehdr.e_shoff; doff = boff = ehdr.e_ehsize + ehdr.e_phentsize * nphdrs + ehdr.e_shentsize * nshdrs; #endif /* _LP64 */ } /* * Write the zero indexed section if it exists. */ if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0, nshdrs >= SHN_LORESERVE ? nshdrs : 0, nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0, nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0) goto err; /* * Construct the old-style note header and section. */ if (P->status.pr_dmodel == PR_MODEL_NATIVE) { prpsinfo_t prpsinfo; mkprpsinfo(P, &prpsinfo); if (write_note(fd, NT_PRPSINFO, &prpsinfo, sizeof (prpsinfo_t), &doff) != 0) { goto err; } if (write_note(fd, NT_AUXV, P->auxv, P->nauxv * sizeof (P->auxv[0]), &doff) != 0) { goto err; } #ifdef _LP64 } else { prpsinfo32_t pi32; auxv32_t *av32; size_t size = sizeof (auxv32_t) * P->nauxv; int i; mkprpsinfo32(P, &pi32); if (write_note(fd, NT_PRPSINFO, &pi32, sizeof (prpsinfo32_t), &doff) != 0) { goto err; } if ((av32 = malloc(size)) == NULL) goto err; for (i = 0; i < P->nauxv; i++) { auxv_n_to_32(&P->auxv[i], &av32[i]); } if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) { free(av32); goto err; } free(av32); #endif /* _LP64 */ } if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0) goto err; if (Plwp_iter_all(P, old_per_lwp, &pgc) != 0) goto err; if (P->status.pr_dmodel == PR_MODEL_ILP32) { Elf32_Phdr phdr; bzero(&phdr, sizeof (phdr)); phdr.p_type = PT_NOTE; phdr.p_flags = PF_R; phdr.p_offset = (Elf32_Off)boff; phdr.p_filesz = doff - boff; boff = doff; if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0) goto err; poff += sizeof (phdr); #ifdef _LP64 } else { Elf64_Phdr phdr; bzero(&phdr, sizeof (phdr)); phdr.p_type = PT_NOTE; phdr.p_flags = PF_R; phdr.p_offset = boff; phdr.p_filesz = doff - boff; boff = doff; if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0) goto err; poff += sizeof (phdr); #endif /* _LP64 */ } /* * Construct the new-style note header and section. */ if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t), &doff) != 0) { goto err; } if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t), &doff) != 0) { goto err; } if (write_note(fd, NT_AUXV, P->auxv, P->nauxv * sizeof (P->auxv[0]), &doff) != 0) { goto err; } #ifdef _LP64 } else { psinfo32_t pi32; pstatus32_t ps32; auxv32_t *av32; size_t size = sizeof (auxv32_t) * P->nauxv; int i; psinfo_n_to_32(&P->psinfo, &pi32); if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t), &doff) != 0) { goto err; } pstatus_n_to_32(&P->status, &ps32); if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t), &doff) != 0) { goto err; } if ((av32 = malloc(size)) == NULL) goto err; for (i = 0; i < P->nauxv; i++) { auxv_n_to_32(&P->auxv[i], &av32[i]); } if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) { free(av32); goto err; } free(av32); #endif /* _LP64 */ } if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 || write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 || write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0) goto err; { prcred_t cred, *cp; size_t size = sizeof (prcred_t); if (Pcred(P, &cred, 0) != 0) goto err; if (cred.pr_ngroups > 0) size += sizeof (gid_t) * (cred.pr_ngroups - 1); if ((cp = malloc(size)) == NULL) goto err; if (Pcred(P, cp, cred.pr_ngroups) != 0 || write_note(fd, NT_PRCRED, cp, size, &doff) != 0) { free(cp); goto err; } free(cp); } { prpriv_t *ppriv = NULL; const priv_impl_info_t *pinfo; size_t pprivsz, pinfosz; if (Ppriv(P, &ppriv) == -1) goto err; pprivsz = PRIV_PRPRIV_SIZE(ppriv); if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) { Ppriv_free(P, ppriv); goto err; } Ppriv_free(P, ppriv); if ((pinfo = getprivimplinfo()) == NULL) goto err; pinfosz = PRIV_IMPL_INFO_SIZE(pinfo); if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0) goto err; } if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1, &doff) != 0) goto err; { fditer_t iter; iter.fd_fd = fd; iter.fd_doff = &doff; if (Pfdinfo_iter(P, iter_fd, &iter) != 0) goto err; } { prsecflags_t *psf = NULL; if (Psecflags(P, &psf) != 0) goto err; if (write_note(fd, NT_SECFLAGS, psf, sizeof (prsecflags_t), &doff) != 0) { Psecflags_free(psf); goto err; } Psecflags_free(psf); } #if defined(__i386) || defined(__amd64) /* CSTYLED */ { struct ssd *ldtp; size_t size; int nldt; /* * Only dump out non-zero sized LDT notes. */ if ((nldt = Pldt(P, NULL, 0)) != 0) { size = sizeof (struct ssd) * nldt; if ((ldtp = malloc(size)) == NULL) goto err; if (Pldt(P, ldtp, nldt) == -1 || write_note(fd, NT_LDT, ldtp, size, &doff) != 0) { free(ldtp); goto err; } free(ldtp); } } #endif /* __i386 || __amd64 */ if (Plwp_iter_all(P, new_per_lwp, &pgc) != 0) goto err; if (P->status.pr_dmodel == PR_MODEL_ILP32) { Elf32_Phdr phdr; bzero(&phdr, sizeof (phdr)); phdr.p_type = PT_NOTE; phdr.p_flags = PF_R; phdr.p_offset = (Elf32_Off)boff; phdr.p_filesz = doff - boff; boff = doff; if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0) goto err; poff += sizeof (phdr); #ifdef _LP64 } else { Elf64_Phdr phdr; bzero(&phdr, sizeof (phdr)); phdr.p_type = PT_NOTE; phdr.p_flags = PF_R; phdr.p_offset = boff; phdr.p_filesz = doff - boff; boff = doff; if (gc_pwrite64(fd, &phdr, sizeof (phdr), poff) != 0) goto err; poff += sizeof (phdr); #endif /* _LP64 */ } /* * Construct the headers for each mapping and write out its data * if the content parameter indicates that it should be present * in the core file. */ if (Pmapping_iter(P, dump_map, &pgc) != 0) goto err; if (dump_sections(&pgc) != 0) goto err; if (write_shstrtab(P, &pgc) != 0) goto err; free(pgc.pgc_chunk); return (0); err: /* * Wipe out anything we may have written if there was an error. */ (void) ftruncate64(fd, 0); free(pgc.pgc_chunk); return (-1); }
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); }
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); }