Example #1
0
static int
show_cwd(const char *arg)
{
	char cwd[MAXPATHLEN], proc[128];
	psinfo_t p;
	int gcode;
	int ret;

	if (proc_arg_psinfo(arg, PR_ARG_PIDS, &p, &gcode) == -1) {
		(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
		    command, arg, Pgrab_error(gcode));
		return (1);
	}

	(void) snprintf(proc, sizeof (proc), "/proc/%d/path/cwd",
	    (int)p.pr_pid);

	if ((ret = readlink(proc, cwd, sizeof (cwd) - 1)) <= 0) {
		(void) fprintf(stderr, "%s: cannot resolve cwd for %s: %s\n",
		    command, arg, strerror(errno));
		return (1);
	}

	cwd[ret] = '\0';

	(void) printf("%d:\t%s\n", (int)p.pr_pid, cwd);
	return (0);
}
Example #2
0
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);
}
Example #3
0
static int
stop(char *arg)
{
	int gcode;
	int rc = 0;

	if ((P = proc_arg_xgrab(arg, NULL, PR_ARG_PIDS, PGRAB_RETAIN |
	    PGRAB_NOSTOP | PGRAB_FORCE, &gcode, &lwps)) == NULL) {
		(void) fprintf(stderr, "%s: cannot control %s: %s\n",
		    command, arg, Pgrab_error(gcode));
		return (1);
	} else if (lwps != NULL) {
		/*
		 * The user has provided an lwp specification.  Let's consider
		 * the lwp specification as a mask.  We iterate over all lwps in
		 * the process and stop every lwp, which matches the mask.  If
		 * there is no lwp matching the mask or an error occured during
		 * the iteration, set the return code to 1 as indication of an
		 * error.
		 */
		int lwpcount = 0;

		(void) Plwp_iter_all(P, (proc_lwp_all_f *)lwpstop, &lwpcount);
		if (lwpcount == 0) {
			(void) fprintf(stderr, "%s: cannot control %s:"
			    " no matching LWPs found\n", command, arg);
			rc = 1;
		} else if (lwpcount == -1)
			rc = 1;
	} else {
		(void) Pdstop(P);	/* Stop the process. */
	}

	/*
	 * Prelease could change the tracing flags, use Pfree and unset
	 * run-on-last-close flag to prevent the process being set running
	 * after detaching from it.
	 */
	(void) Punsetflags(P, PR_RLC);
	Pfree(P);
	return (rc);
}
Example #4
0
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);
}
Example #5
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);
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #8
0
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);
}
Example #9
0
/*
 * 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);
}
Example #10
0
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);
}
Example #11
0
int
main(int argc, char *argv[], char *envp[])
{
	extern int mdb_kvm_is_compressed_dump(mdb_io_t *);
	mdb_tgt_ctor_f *tgt_ctor = NULL;
	const char **tgt_argv = alloca(argc * sizeof (char *));
	int tgt_argc = 0;
	mdb_tgt_t *tgt;

	char object[MAXPATHLEN], execname[MAXPATHLEN];
	mdb_io_t *in_io, *out_io, *err_io, *null_io;
	struct termios tios;
	int status, c;
	char *p;

	const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL;
	int fflag = 0, Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0;

	int ttylike;
	int longmode = 0;

	stack_t sigstack;

	if (realpath(getexecname(), execname) == NULL) {
		(void) strncpy(execname, argv[0], MAXPATHLEN);
		execname[MAXPATHLEN - 1] = '\0';
	}

	mdb_create(execname, argv[0]);
	bzero(tgt_argv, argc * sizeof (char *));
	argv[0] = (char *)mdb.m_pname;
	_mdb_self_fd = open("/proc/self/as", O_RDONLY);

	mdb.m_env = envp;

	out_io = mdb_fdio_create(STDOUT_FILENO);
	mdb.m_out = mdb_iob_create(out_io, MDB_IOB_WRONLY);

	err_io = mdb_fdio_create(STDERR_FILENO);
	mdb.m_err = mdb_iob_create(err_io, MDB_IOB_WRONLY);
	mdb_iob_clrflags(mdb.m_err, MDB_IOB_AUTOWRAP);

	null_io = mdb_nullio_create();
	mdb.m_null = mdb_iob_create(null_io, MDB_IOB_WRONLY);

	in_io = mdb_fdio_create(STDIN_FILENO);
	if ((mdb.m_termtype = getenv("TERM")) != NULL) {
		mdb.m_termtype = strdup(mdb.m_termtype);
		mdb.m_flags |= MDB_FL_TERMGUESS;
	}
	mdb.m_term = NULL;

	mdb_dmode(mdb_dstr2mode(getenv("MDB_DEBUG")));
	mdb.m_pgid = getpgrp();

	if (getenv("_MDB_EXEC") != NULL)
		mdb.m_flags |= MDB_FL_EXEC;

	/*
	 * Setup an alternate signal stack.  When tearing down pipelines in
	 * terminate(), we may have to destroy the stack of the context in
	 * which we are currently executing the signal handler.
	 */
	sigstack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
	    MAP_PRIVATE | MAP_ANON, -1, 0);
	if (sigstack.ss_sp == MAP_FAILED)
		die("could not allocate signal stack");
	sigstack.ss_size = SIGSTKSZ;
	sigstack.ss_flags = 0;
	if (sigaltstack(&sigstack, NULL) != 0)
		die("could not set signal stack");

	(void) mdb_signal_sethandler(SIGPIPE, SIG_IGN, NULL);
	(void) mdb_signal_sethandler(SIGQUIT, SIG_IGN, NULL);

	(void) mdb_signal_sethandler(SIGILL, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGTRAP, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGIOT, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGEMT, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGFPE, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGBUS, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGSEGV, flt_handler, NULL);

	(void) mdb_signal_sethandler(SIGHUP, (mdb_signal_f *)terminate, NULL);
	(void) mdb_signal_sethandler(SIGTERM, (mdb_signal_f *)terminate, NULL);

	for (mdb.m_rdvers = RD_VERSION; mdb.m_rdvers > 0; mdb.m_rdvers--) {
		if (rd_init(mdb.m_rdvers) == RD_OK)
			break;
	}

	for (mdb.m_ctfvers = CTF_VERSION; mdb.m_ctfvers > 0; mdb.m_ctfvers--) {
		if (ctf_version(mdb.m_ctfvers) != -1)
			break;
	}

	if ((p = getenv("HISTSIZE")) != NULL && strisnum(p)) {
		mdb.m_histlen = strtoi(p);
		if (mdb.m_histlen < 1)
			mdb.m_histlen = 1;
	}

	while (optind < argc) {
		while ((c = getopt(argc, argv,
		    "fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
			switch (c) {
			case 'f':
				fflag++;
				tgt_ctor = mdb_rawfile_tgt_create;
				break;
			case 'k':
				tgt_ctor = mdb_kvm_tgt_create;
				break;
			case 'm':
				mdb.m_tgtflags |= MDB_TGT_F_NOLOAD;
				mdb.m_tgtflags &= ~MDB_TGT_F_PRELOAD;
				break;
			case 'o':
				if (!mdb_set_options(optarg, TRUE))
					terminate(2);
				break;
			case 'p':
				tgt_ctor = mdb_proc_tgt_create;
				pidarg = optarg;
				break;
			case 's':
				if (!strisnum(optarg)) {
					warn("expected integer following -s\n");
					terminate(2);
				}
				mdb.m_symdist = (size_t)(uint_t)strtoi(optarg);
				break;
			case 'u':
				tgt_ctor = mdb_proc_tgt_create;
				break;
			case 'w':
				mdb.m_tgtflags |= MDB_TGT_F_RDWR;
				break;
			case 'y':
				mdb.m_flags |= MDB_FL_USECUP;
				break;
			case 'A':
				(void) mdb_set_options("nomods", TRUE);
				break;
			case 'C':
				(void) mdb_set_options("noctf", TRUE);
				break;
			case 'D':
				mdb_dmode(mdb_dstr2mode(optarg));
				break;
			case 'F':
				mdb.m_tgtflags |= MDB_TGT_F_FORCE;
				break;
			case 'I':
				Iflag = optarg;
				break;
			case 'L':
				Lflag = optarg;
				break;
			case 'K':
				Kflag++;
				break;
			case 'M':
				mdb.m_tgtflags |= MDB_TGT_F_PRELOAD;
				mdb.m_tgtflags &= ~MDB_TGT_F_NOLOAD;
				break;
			case 'O':
				Oflag++;
				break;
			case 'P':
				if (!mdb_set_prompt(optarg))
					terminate(2);
				break;
			case 'R':
				(void) strncpy(mdb.m_root, optarg, MAXPATHLEN);
				mdb.m_root[MAXPATHLEN - 1] = '\0';
				Rflag++;
				break;
			case 'S':
				Sflag++;
				break;
			case 'U':
				Uflag++;
				break;
			case 'V':
				Vflag = optarg;
				break;
			case 'W':
				mdb.m_tgtflags |= MDB_TGT_F_ALLOWIO;
				break;
			case '?':
				if (optopt == '?')
					usage(0);
				/* FALLTHROUGH */
			default:
				usage(2);
			}
		}

		if (optind < argc) {
			const char *arg = argv[optind++];

			if (arg[0] == '+' && strlen(arg) == 2) {
				if (arg[1] != 'o') {
					warn("illegal option -- %s\n", arg);
					terminate(2);
				}
				if (optind >= argc) {
					warn("option requires an argument -- "
					    "%s\n", arg);
					terminate(2);
				}
				if (!mdb_set_options(argv[optind++], FALSE))
					terminate(2);
			} else
				tgt_argv[tgt_argc++] = arg;
		}
	}

	if (rd_ctl(RD_CTL_SET_HELPPATH, (void *)mdb.m_root) != RD_OK) {
		warn("cannot set librtld_db helper path to %s\n", mdb.m_root);
		terminate(2);
	}

	if (mdb.m_debug & MDB_DBG_HELP)
		terminate(0); /* Quit here if we've printed out the tokens */


	if (Iflag != NULL && strchr(Iflag, ';') != NULL) {
		warn("macro path cannot contain semicolons\n");
		terminate(2);
	}

	if (Lflag != NULL && strchr(Lflag, ';') != NULL) {
		warn("module path cannot contain semicolons\n");
		terminate(2);
	}

	if (Kflag || Uflag) {
		char *nm;

		if (tgt_ctor != NULL || Iflag != NULL) {
			warn("neither -f, -k, -p, -u, nor -I "
			    "may be used with -K\n");
			usage(2);
		}

		if (Lflag != NULL)
			mdb_set_lpath(Lflag);

		if ((nm = ttyname(STDIN_FILENO)) == NULL ||
		    strcmp(nm, "/dev/console") != 0) {
			/*
			 * Due to the consequences of typing mdb -K instead of
			 * mdb -k on a tty other than /dev/console, we require
			 * -F when starting kmdb from a tty other than
			 * /dev/console.
			 */
			if (!(mdb.m_tgtflags & MDB_TGT_F_FORCE)) {
				die("-F must also be supplied to start kmdb "
				    "from non-console tty\n");
			}

			if (mdb.m_termtype == NULL || (mdb.m_flags &
			    MDB_FL_TERMGUESS)) {
				if (mdb.m_termtype != NULL)
					strfree(mdb.m_termtype);

				if ((mdb.m_termtype = mdb_scf_console_term()) !=
				    NULL)
					mdb.m_flags |= MDB_FL_TERMGUESS;
			}
		} else {
			/*
			 * When on console, $TERM (if set) takes precedence over
			 * the SMF setting.
			 */
			if (mdb.m_termtype == NULL && (mdb.m_termtype =
			    mdb_scf_console_term()) != NULL)
				mdb.m_flags |= MDB_FL_TERMGUESS;
		}

		control_kmdb(Kflag);
		terminate(0);
		/*NOTREACHED*/
	}

	/*
	 * If standard input appears to have tty attributes, attempt to
	 * initialize a terminal i/o backend on top of stdin and stdout.
	 */
	ttylike = (IOP_CTL(in_io, TCGETS, &tios) == 0);
	if (ttylike) {
		if ((mdb.m_term = mdb_termio_create(mdb.m_termtype,
		    in_io, out_io)) == NULL) {
			if (!(mdb.m_flags & MDB_FL_EXEC)) {
				warn("term init failed: command-line editing "
				    "and prompt will not be available\n");
			}
		} else {
			in_io = mdb.m_term;
		}
	}

	mdb.m_in = mdb_iob_create(in_io, MDB_IOB_RDONLY);
	if (mdb.m_term != NULL) {
		mdb_iob_setpager(mdb.m_out, mdb.m_term);
		if (mdb.m_flags & MDB_FL_PAGER)
			mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
		else
			mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE);
	} else if (ttylike)
		mdb_iob_setflags(mdb.m_in, MDB_IOB_TTYLIKE);
	else
		mdb_iob_setbuf(mdb.m_in, mdb_alloc(1, UM_SLEEP), 1);

	mdb_pservice_init();
	mdb_lex_reset();

	if ((mdb.m_shell = getenv("SHELL")) == NULL)
		mdb.m_shell = "/bin/sh";

	/*
	 * If the debugger state is to be inherited from a previous instance,
	 * restore it now prior to path evaluation so that %R is updated.
	 */
	if ((p = getenv(MDB_CONFIG_ENV_VAR)) != NULL) {
		mdb_set_config(p);
		(void) unsetenv(MDB_CONFIG_ENV_VAR);
	}

	/*
	 * Path evaluation part 1: Create the initial module path to allow
	 * the target constructor to load a support module.  Then expand
	 * any command-line arguments that modify the paths.
	 */
	if (Iflag != NULL)
		mdb_set_ipath(Iflag);
	else
		mdb_set_ipath(MDB_DEF_IPATH);

	if (Lflag != NULL)
		mdb_set_lpath(Lflag);
	else
		mdb_set_lpath(MDB_DEF_LPATH);

	if (mdb_get_prompt() == NULL && !(mdb.m_flags & MDB_FL_ADB))
		(void) mdb_set_prompt(MDB_DEF_PROMPT);

	if (tgt_ctor == mdb_kvm_tgt_create) {
		if (pidarg != NULL) {
			warn("-p and -k options are mutually exclusive\n");
			terminate(2);
		}

		if (tgt_argc == 0)
			tgt_argv[tgt_argc++] = "/dev/ksyms";
		if (tgt_argc == 1 && strisnum(tgt_argv[0]) == 0) {
			if (mdb.m_tgtflags & MDB_TGT_F_ALLOWIO)
				tgt_argv[tgt_argc++] = "/dev/allkmem";
			else
				tgt_argv[tgt_argc++] = "/dev/kmem";
		}
	}

	if (pidarg != NULL) {
		if (tgt_argc != 0) {
			warn("-p may not be used with other arguments\n");
			terminate(2);
		}
		if (proc_arg_psinfo(pidarg, PR_ARG_PIDS, NULL, &status) == -1) {
			die("cannot attach to %s: %s\n",
			    pidarg, Pgrab_error(status));
		}
		if (strchr(pidarg, '/') != NULL)
			(void) mdb_iob_snprintf(object, MAXPATHLEN,
			    "%s/object/a.out", pidarg);
		else
			(void) mdb_iob_snprintf(object, MAXPATHLEN,
			    "/proc/%s/object/a.out", pidarg);
		tgt_argv[tgt_argc++] = object;
		tgt_argv[tgt_argc++] = pidarg;
	}

	/*
	 * Find the first argument that is not a special "-" token.  If one is
	 * found, we will examine this file and make some inferences below.
	 */
	for (c = 0; c < tgt_argc && strcmp(tgt_argv[c], "-") == 0; c++)
		continue;

	if (c < tgt_argc) {
		Elf32_Ehdr ehdr;
		mdb_io_t *io;

		/*
		 * If special "-" tokens preceded an argument, shift the entire
		 * argument list to the left to remove the leading "-" args.
		 */
		if (c > 0) {
			bcopy(&tgt_argv[c], tgt_argv,
			    sizeof (const char *) * (tgt_argc - c));
			tgt_argc -= c;
		}

		if (fflag)
			goto tcreate; /* skip re-exec and just create target */

		/*
		 * If we just have an object file name, and that file doesn't
		 * exist, and it's a string of digits, infer it to be a
		 * sequence number referring to a pair of crash dump files.
		 */
		if (tgt_argc == 1 && access(tgt_argv[0], F_OK) == -1 &&
		    strisnum(tgt_argv[0])) {

			size_t len = strlen(tgt_argv[0]) + 8;
			const char *object = tgt_argv[0];

			tgt_argv[0] = mdb_alloc(len, UM_SLEEP);
			tgt_argv[1] = mdb_alloc(len, UM_SLEEP);

			(void) strcpy((char *)tgt_argv[0], "unix.");
			(void) strcat((char *)tgt_argv[0], object);
			(void) strcpy((char *)tgt_argv[1], "vmcore.");
			(void) strcat((char *)tgt_argv[1], object);

			if (access(tgt_argv[0], F_OK) == -1 &&
			    access(tgt_argv[1], F_OK) == -1) {
				(void) strcpy((char *)tgt_argv[1], "vmdump.");
				(void) strcat((char *)tgt_argv[1], object);
				if (access(tgt_argv[1], F_OK) == 0) {
					mdb_iob_printf(mdb.m_err,
					    "cannot open compressed dump; "
					    "decompress using savecore -f %s\n",
					    tgt_argv[1]);
					terminate(0);
				}
			}

			tgt_argc = 2;
		}

		/*
		 * We need to open the object file in order to determine its
		 * ELF class and potentially re-exec ourself.
		 */
		if ((io = mdb_fdio_create_path(NULL, tgt_argv[0],
		    O_RDONLY, 0)) == NULL)
			die("failed to open %s", tgt_argv[0]);

		/*
		 * Check for a single vmdump.N compressed dump file,
		 * and give a helpful message.
		 */
		if (tgt_argc == 1) {
			if (mdb_kvm_is_compressed_dump(io)) {
				mdb_iob_printf(mdb.m_err,
				    "cannot open compressed dump; "
				    "decompress using savecore -f %s\n",
				    tgt_argv[0]);
				terminate(0);
			}
		}

		/*
		 * If the target is unknown or is not the rawfile target, do
		 * a gelf_check to determine if the file is an ELF file.  If
		 * it is not and the target is unknown, use the rawfile tgt.
		 * Otherwise an ELF-based target is needed, so we must abort.
		 */
		if (mdb_gelf_check(io, &ehdr, ET_NONE) == -1) {
			if (tgt_ctor != NULL) {
				(void) mdb_gelf_check(io, &ehdr, ET_EXEC);
				mdb_io_destroy(io);
				terminate(1);
			} else
				tgt_ctor = mdb_rawfile_tgt_create;
		}

		mdb_io_destroy(io);

		if (identify_xvm_file(tgt_argv[0], &longmode) == 1) {
#ifdef _LP64
			if (!longmode)
				goto reexec;
#else
			if (longmode)
				goto reexec;
#endif
			tgt_ctor = mdb_kvm_tgt_create;
			goto tcreate;
		}

		/*
		 * The object file turned out to be a user core file (ET_CORE),
		 * and no other arguments were specified, swap 0 and 1.  The
		 * proc target will infer the executable for us.
		 */
		if (ehdr.e_type == ET_CORE) {
			tgt_argv[tgt_argc++] = tgt_argv[0];
			tgt_argv[0] = NULL;
			tgt_ctor = mdb_proc_tgt_create;
		}

		/*
		 * If tgt_argv[1] is filled in, open it up and determine if it
		 * is a vmcore file.  If it is, gelf_check will fail and we
		 * set tgt_ctor to 'kvm'; otherwise we use the default.
		 */
		if (tgt_argc > 1 && strcmp(tgt_argv[1], "-") != 0 &&
		    tgt_argv[0] != NULL && pidarg == NULL) {
			Elf32_Ehdr chdr;

			if (access(tgt_argv[1], F_OK) == -1)
				die("failed to access %s", tgt_argv[1]);

			/* *.N case: drop vmdump.N from the list */
			if (tgt_argc == 3) {
				if ((io = mdb_fdio_create_path(NULL,
				    tgt_argv[2], O_RDONLY, 0)) == NULL)
					die("failed to open %s", tgt_argv[2]);
				if (mdb_kvm_is_compressed_dump(io))
					tgt_argv[--tgt_argc] = NULL;
				mdb_io_destroy(io);
			}

			if ((io = mdb_fdio_create_path(NULL, tgt_argv[1],
			    O_RDONLY, 0)) == NULL)
				die("failed to open %s", tgt_argv[1]);

			if (mdb_gelf_check(io, &chdr, ET_NONE) == -1)
				tgt_ctor = mdb_kvm_tgt_create;

			mdb_io_destroy(io);
		}

		/*
		 * At this point, we've read the ELF header for either an
		 * object file or core into ehdr.  If the class does not match
		 * ours, attempt to exec the mdb of the appropriate class.
		 */
#ifdef _LP64
		if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
			goto reexec;
#else
		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
			goto reexec;
#endif
	}

tcreate:
	if (tgt_ctor == NULL)
		tgt_ctor = mdb_proc_tgt_create;

	tgt = mdb_tgt_create(tgt_ctor, mdb.m_tgtflags, tgt_argc, tgt_argv);

	if (tgt == NULL) {
		if (errno == EINVAL)
			usage(2); /* target can return EINVAL to get usage */
		if (errno == EMDB_TGT)
			terminate(1); /* target already printed error msg */
		die("failed to initialize target");
	}

	mdb_tgt_activate(tgt);

	mdb_create_loadable_disasms();

	if (Vflag != NULL && mdb_dis_select(Vflag) == -1)
		warn("invalid disassembler mode -- %s\n", Vflag);


	if (Rflag && mdb.m_term != NULL)
		warn("Using proto area %s\n", mdb.m_root);

	/*
	 * If the target was successfully constructed and -O was specified,
	 * we now attempt to enter piggy-mode for debugging jurassic problems.
	 */
	if (Oflag) {
		pcinfo_t pci;

		(void) strcpy(pci.pc_clname, "RT");

		if (priocntl(P_LWPID, P_MYID, PC_GETCID, (caddr_t)&pci) != -1) {
			pcparms_t pcp;
			rtparms_t *rtp = (rtparms_t *)pcp.pc_clparms;

			rtp->rt_pri = 35;
			rtp->rt_tqsecs = 0;
			rtp->rt_tqnsecs = RT_TQDEF;

			pcp.pc_cid = pci.pc_cid;

			if (priocntl(P_LWPID, P_MYID, PC_SETPARMS,
			    (caddr_t)&pcp) == -1) {
				warn("failed to set RT parameters");
				Oflag = 0;
			}
		} else {
			warn("failed to get RT class id");
			Oflag = 0;
		}

		if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
			warn("failed to lock address space");
			Oflag = 0;
		}

		if (Oflag)
			mdb_printf("%s: oink, oink!\n", mdb.m_pname);
	}

	/*
	 * Path evaluation part 2: Re-evaluate the path now that the target
	 * is ready (and thus we have access to the real platform string).
	 * Do this before reading ~/.mdbrc to allow path modifications prior
	 * to performing module auto-loading.
	 */
	mdb_set_ipath(mdb.m_ipathstr);
	mdb_set_lpath(mdb.m_lpathstr);

	if (!Sflag && (p = getenv("HOME")) != NULL) {
		char rcpath[MAXPATHLEN];
		mdb_io_t *rc_io;
		int fd;

		(void) mdb_iob_snprintf(rcpath, MAXPATHLEN, "%s/.mdbrc", p);
		fd = open64(rcpath, O_RDONLY);

		if (fd >= 0 && (rc_io = mdb_fdio_create_named(fd, rcpath))) {
			mdb_iob_t *iob = mdb_iob_create(rc_io, MDB_IOB_RDONLY);
			mdb_iob_t *old = mdb.m_in;

			mdb.m_in = iob;
			(void) mdb_run();
			mdb.m_in = old;
		}
	}

	if (!(mdb.m_flags & MDB_FL_NOMODS))
		mdb_module_load_all(0);

	(void) mdb_signal_sethandler(SIGINT, int_handler, NULL);
	while ((status = mdb_run()) == MDB_ERR_ABORT ||
	    status == MDB_ERR_OUTPUT) {
		/*
		 * If a write failed on stdout, give up.  A more informative
		 * error message will already have been printed by mdb_run().
		 */
		if (status == MDB_ERR_OUTPUT &&
		    mdb_iob_getflags(mdb.m_out) & MDB_IOB_ERR) {
			mdb_warn("write to stdout failed, exiting\n");
			break;
		}
		continue;
	}

	terminate((status == MDB_ERR_QUIT || status == 0) ? 0 : 1);
	/*NOTREACHED*/
	return (0);

reexec:
	if ((p = strrchr(execname, '/')) == NULL)
		die("cannot determine absolute pathname\n");
#ifdef _LP64
#ifdef __sparc
	(void) strcpy(p, "/../sparcv7/");
#else
	(void) strcpy(p, "/../i86/");
#endif
#else
#ifdef __sparc
	(void) strcpy(p, "/../sparcv9/");
#else
	(void) strcpy(p, "/../amd64/");
#endif
#endif
	(void) strcat(p, mdb.m_pname);

	if (mdb.m_term != NULL)
		(void) IOP_CTL(in_io, TCSETSW, &tios);

	(void) putenv("_MDB_EXEC=1");
	(void) execv(execname, argv);

	/*
	 * If execv fails, suppress ENOEXEC.  Experience shows the most common
	 * reason is that the machine is booted under a 32-bit kernel, in which
	 * case it is clearer to only print the message below.
	 */
	if (errno != ENOEXEC)
		warn("failed to exec %s", execname);
#ifdef _LP64
	die("64-bit %s cannot debug 32-bit program %s\n",
	    mdb.m_pname, tgt_argv[0] ?
	    tgt_argv[0] : tgt_argv[1]);
#else
	die("32-bit %s cannot debug 64-bit program %s\n",
	    mdb.m_pname, tgt_argv[0] ?
	    tgt_argv[0] : tgt_argv[1]);
#endif

	goto tcreate;
}
Example #12
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);
}
Example #13
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);
}