Пример #1
0
static int
dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    uint8_t *text, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
{
	ulong_t i;
	int size;
#if defined(sun)
	pid_t pid = Pstatus(P)->pr_pid;
	char dmodel = Pstatus(P)->pr_dmodel;
#else
	pid_t pid = proc_getpid(P);
#if __i386__
	char dmodel = PR_MODEL_ILP32;
#elif __amd64__
	char dmodel = PR_MODEL_LP64;
#endif
#endif

	/*
	 * Take a pass through the function looking for a register-dependant
	 * jmp instruction. This could be a jump table so we have to be
	 * ultra conservative.
	 */
	for (i = 0; i < ftp->ftps_size; i += size) {
		size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i,
		    dmodel);

		/*
		 * Assume the worst if we hit an illegal instruction.
		 */
		if (size <= 0) {
			dt_dprintf("error at %#lx (assuming jump table)\n", i);
			return (1);
		}

#ifdef notyet
		/*
		 * Register-dependant jmp instructions start with a 0xff byte
		 * and have the modrm.reg field set to 4. They can have an
		 * optional REX prefix on the 64-bit ISA.
		 */
		if ((text[i] == 0xff && DT_MODRM_REG(text[i + 1]) == 4) ||
		    (dmodel == PR_MODEL_LP64 && (text[i] & 0xf0) == 0x40 &&
		    text[i + 1] == 0xff && DT_MODRM_REG(text[i + 2]) == 4)) {
			dt_dprintf("found a suspected jump table at %s:%lx\n",
			    ftp->ftps_func, i);
			return (1);
		}
#endif
	}

	return (0);
}
Пример #2
0
/*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;
	}
}
Пример #3
0
/*
 * Wait for a stopped process to be set running again by some other debugger.
 * This is typically not required by /proc-based debuggers, since the usual
 * model is that one debugger controls one victim.  But DTrace, as usual, has
 * its own needs: the stop() action assumes that prun(1) or some other tool
 * will be applied to resume the victim process.  This could be solved by
 * adding a PCWRUN directive to /proc, but that seems like overkill unless
 * other debuggers end up needing this functionality, so we implement a cheap
 * equivalent to PCWRUN using the set of existing kernel mechanisms.
 *
 * Our intent is really not just to wait for the victim to run, but rather to
 * wait for it to run and then stop again for a reason other than the current
 * PR_REQUESTED stop.  Since PCWSTOP/Pstopstatus() can be applied repeatedly
 * to a stopped process and will return the same result without affecting the
 * victim, we can just perform these operations repeatedly until Pstate()
 * changes, the representative LWP ID changes, or the stop timestamp advances.
 * dt_gproc_control() will then rediscover the new state and continue as usual.
 * When the process is still stopped in the same exact state, we sleep for a
 * brief interval before waiting again so as not to spin consuming CPU cycles.
 */
static void
dt_proc_waitrun(dt_proc_t *dpr)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;

	int krflag = psp->pr_flags & (PR_KLC | PR_RLC);
	timestruc_t tstamp = psp->pr_tstamp;
	lwpid_t lwpid = psp->pr_lwpid;

	const long wstop = PCWSTOP;
	int pfd = Pctlfd(P);

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
	assert(psp->pr_flags & PR_STOPPED);
	assert(Pstate(P) == PS_STOP);

	/*
	 * While we are waiting for the victim to run, clear PR_KLC and PR_RLC
	 * so that if the libdtrace client is killed, the victim stays stopped.
	 * dt_proc_destroy() will also observe this and perform PRELEASE_HANG.
	 */
	(void) Punsetflags(P, krflag);
	Psync(P);

	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	while (!dpr->dpr_quit) {
		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
			continue; /* check dpr_quit and continue waiting */

		(void) pthread_mutex_lock(&dpr->dpr_lock);
		(void) Pstopstatus(P, PCNULL, 0);
		psp = &Pstatus(P)->pr_lwp;

		/*
		 * If we've reached a new state, found a new representative, or
		 * the stop timestamp has changed, restore PR_KLC/PR_RLC to its
		 * original setting and then return with dpr_lock held.
		 */
		if (Pstate(P) != PS_STOP || psp->pr_lwpid != lwpid ||
		    bcmp(&psp->pr_tstamp, &tstamp, sizeof (tstamp)) != 0) {
			(void) Psetflags(P, krflag);
			Psync(P);
			return;
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
		(void) poll(NULL, 0, MILLISEC / 2);
	}

	(void) pthread_mutex_lock(&dpr->dpr_lock);
}
Пример #4
0
/*
 * statvfs() system call -- executed by subject process
 */
int
pr_statvfs(struct ps_prochandle *Pr, const char *path, statvfs_t *buf)
{
	sysret_t rval;			/* return value from statvfs() */
	argdes_t argd[2];		/* arg descriptors for statvfs() */
	argdes_t *adp = &argd[0];	/* first argument */
	int error;
#ifdef _LP64
	statvfs32_t statvfs32;
#endif	/* _LP64 */

	if (Pr == NULL)		/* no subject process */
		return (statvfs(path, buf));

	adp->arg_value = 0;
	adp->arg_object = (void *)path;
	adp->arg_type = AT_BYREF;
	adp->arg_inout = AI_INPUT;
	adp->arg_size = strlen(path)+1;
	adp++;			/* move to buffer argument */

	adp->arg_value = 0;
	adp->arg_type = AT_BYREF;
	adp->arg_inout = AI_OUTPUT;
#ifdef _LP64
	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
		adp->arg_object = &statvfs32;
		adp->arg_size = sizeof (statvfs32);
	} else {
		adp->arg_object = buf;
		adp->arg_size = sizeof (*buf);
	}
#else	/* _LP64 */
	adp->arg_object = buf;
	adp->arg_size = sizeof (*buf);
#endif	/* _LP64 */

	error = Psyscall(Pr, &rval, SYS_statvfs, 2, &argd[0]);

	if (error) {
		errno = (error > 0)? error : ENOSYS;
		return (-1);
	}
#ifdef _LP64
	if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
		statvfs_32_to_n(&statvfs32, buf);
#endif	/* _LP64 */
	return (0);
}
Пример #5
0
dt_proc_t *
dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
{
	dt_proc_hash_t *dph = dtp->dt_procs;
#if defined(sun)
	pid_t pid = Pstatus(P)->pr_pid;
#else
	pid_t pid = proc_getpid(P);
#endif
	dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)];

	for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) {
		if (dpr->dpr_pid == pid)
			break;
		else
			dpp = &dpr->dpr_hash;
	}

	assert(dpr != NULL);
	assert(dpr->dpr_proc == P);

	if (remove)
		*dpp = dpr->dpr_hash; /* remove from pid hash chain */

	return (dpr);
}
Пример #6
0
/* ARGSUSED */
static int
lwpstop(int *lwpcount, const lwpstatus_t *status, const lwpsinfo_t *info)
{
	struct ps_lwphandle *L;
	int gcode;

	if (proc_lwp_in_set(lwps, info->pr_lwpid)) {
		/*
		 * There is a race between the callback from the iterator and
		 * grabbing of the lwp.  If the lwp has already exited, Lgrab
		 * will return the error code G_NOPROC.  It's not a real error,
		 * only if there is no lwp matching the specification.
		 */
		if ((L = Lgrab(P, info->pr_lwpid, &gcode)) != NULL) {
			(void) Ldstop(L);
			Lfree(L);
			if (*lwpcount >= 0)
				(*lwpcount)++;
		} else if (gcode != G_NOPROC) {
			(void) fprintf(stderr, "%s: cannot control %d/%d: %s\n",
			    command, (int)Pstatus(P)->pr_pid,
			    (int)info->pr_lwpid, Lgrab_error(gcode));
			*lwpcount = -1;
		}
	}
	return (0);
}
Пример #7
0
struct ps_prochandle *
dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
{
	dt_proc_hash_t *dph = dtp->dt_procs;
	dt_proc_t *dpr;
	int err;

	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);
	if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0, dtp->dt_arch)) == NULL) {
		return (dt_proc_error(dtp, dpr,
		    "failed to execute %s: %s\n", file, Pcreate_error(err)));
	}

	dpr->dpr_hdl = dtp;
	dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;

	(void) Punsetflags(dpr->dpr_proc, PR_RLC);
	(void) Psetflags(dpr->dpr_proc, PR_KLC);

	if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
		return (NULL); /* dt_proc_error() has been called for us */

	dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
	dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr;
	dt_list_prepend(&dph->dph_lrulist, dpr);

	dt_dprintf("created pid %d\n", (int)dpr->dpr_pid);
	dpr->dpr_refs++;

	return (dpr->dpr_proc);
}
Пример #8
0
/*ARGSUSED*/
static int
python_object_iter(void *cd, const prmap_t *pmp, const char *obj)
{
	char path[PATH_MAX];
	char *name;
	char *s1, *s2;
	struct ps_prochandle *Pr = cd;

	name = strstr(obj, "/libpython");

	if (name) {
		(void) strcpy(path, obj);
		if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
			s1 = name;
			s2 = path + (s1 - obj);
			(void) strcpy(s2, "/64");
			s2 += 3;
			(void) strcpy(s2, s1);
		}

		s1 = strstr(obj, ".so");
		s2 = strstr(path, ".so");
		(void) strcpy(s2, "_db");
		s2 += 3;
		(void) strcpy(s2, s1);

		if ((pydb_dlhdl = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL)
			return (1);
	}

	return (0);
}
Пример #9
0
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	for (dbp = dt_list_next(&dpr->dpr_bps);
	    dbp != NULL; dbp = dt_list_next(dbp)) {
		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
			break;
	}

	if (dbp == NULL) {
		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
		return;
	}

	dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n",
	    (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);

	dbp->dbp_func(dtp, dpr, dbp->dbp_data);
	(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
Пример #10
0
/*
 * We cannot rely on pr_instr, because if we hit a breakpoint or the user has
 * artifically modified memory, it will no longer be correct.
 */
static uint32_t
pt_read_instr(mdb_tgt_t *t)
{
	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
	uint32_t ret = 0;

	(void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[R_PC]);

	return (ret);
}
Пример #11
0
static int
xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap)
{
    char mapname[PATH_MAX];
    int mapfd, nmap, i, rc;
    struct stat st;
    prxmap_t *prmapp, *pmp;
    ssize_t n;

    (void) snprintf(mapname, sizeof (mapname),
                    "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid);

    if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) {
        if (mapfd >= 0)
            (void) close(mapfd);
        return (perr(mapname));
    }

    nmap = st.st_size / sizeof (prxmap_t);
    nmap *= 2;
again:
    prmapp = malloc((nmap + 1) * sizeof (prxmap_t));

    if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) {
        (void) close(mapfd);
        free(prmapp);
        return (perr("read xmap"));
    }

    if (nmap < n / sizeof (prxmap_t)) {
        free(prmapp);
        nmap *= 2;
        goto again;
    }

    (void) close(mapfd);
    nmap = n / sizeof (prxmap_t);

    for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) {
        if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) {
            free(prmapp);
            return (rc);
        }
    }

    /*
     * Mark the last element.
     */
    if (map_count > 0)
        maps[map_count - 1].md_last = B_TRUE;

    free(prmapp);
    return (0);
}
Пример #12
0
struct ps_prochandle *
dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
{
	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
	struct ps_prochandle *P = dt_proc_create(dtp, file, argv);

	if (P != NULL && idp != NULL && idp->di_id == 0)
		idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */

	return (P);
}
Пример #13
0
/*ARGSUSED*/
static int
look_xmap(void *data,
          const prxmap_t *pmp,
          const char *object_name,
          int last, int doswap)
{
    struct totals *t = data;
    const pstatus_t *Psp = Pstatus(Pr);
    char mname[PATH_MAX];
    char *lname = NULL;
    char *ln;

    /*
     * If the mapping is not anon or not part of the heap, make a name
     * for it.  We don't want to report the heap as a.out's data.
     */
    if (!(pmp->pr_mflags & MA_ANON) ||
            pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
            pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
        lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
                          mname, sizeof (mname));
    }

    if (lname != NULL) {
        if ((ln = strrchr(lname, '/')) != NULL)
            lname = ln + 1;
    } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) {
        lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
                          pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
    }

    (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr);

    printK(ROUNDUP_KB(pmp->pr_size), size_width);
    printK(pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE), size_width);
    printK(ANON(pmp) * (pmp->pr_pagesize / KILOBYTE), size_width);
    printK(pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE), size_width);
    (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n",
                  pagesize(pmp), mflags(pmp->pr_mflags), lname);

    t->total_size += ROUNDUP_KB(pmp->pr_size);
    t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE);
    t->total_anon += ANON(pmp) * (pmp->pr_pagesize / KILOBYTE);
    t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE));

    return (0);
}
Пример #14
0
/*
 * Create labels for non-anon, non-heap mappings
 */
char *
make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr,
    const char *mapname, char *buf, size_t bufsz)
{
	const pstatus_t		*Psp = Pstatus(Pr);
	struct stat		statb;
	char			path[PATH_MAX];
	int			len;

	if (lflag || Pstate(Pr) == PS_DEAD) {
		if (Pobjname(Pr, addr, buf, bufsz) != NULL)
			return (buf);
	} else {
		if (Pobjname_resolved(Pr, addr, buf, bufsz) != NULL) {
			/* Verify that the path exists */
			if ((len = resolvepath(buf, buf, bufsz)) > 0) {
				buf[len] = '\0';
				return (buf);
			}
		}
	}

	if (Pstate(Pr) == PS_DEAD || *mapname == '\0')
		return (NULL);

	/* first see if we can find a path via /proc */
	(void) proc_snprintf(path, sizeof (path), "/proc/%d/path/%s",
	    (int)Psp->pr_pid, mapname);
	len = readlink(path, buf, bufsz - 1);
	if (len >= 0) {
		buf[len] = '\0';
		return (buf);
	}

	/* fall back to object information reported by /proc */
	(void) proc_snprintf(path, sizeof (path),
	    "/proc/%d/object/%s", (int)Psp->pr_pid, mapname);
	if (stat(path, &statb) == 0) {
		dev_t dev = statb.st_dev;
		ino_t ino = statb.st_ino;
		(void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu",
		    (ulong_t)major(dev), (ulong_t)minor(dev), ino);
		return (buf);
	}

	return (NULL);
}
Пример #15
0
static int
dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
    dt_pcb_t *pcb, dt_proc_t *dpr)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	int ret = 0;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#if defined(sun)
	(void) Pupdate_maps(P);
	if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
		ret = -1;
		(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
		    "failed to instantiate probes for pid %d: %s",
#if defined(sun)
		    (int)Pstatus(P)->pr_pid, strerror(errno));
#else
		    (int)proc_getpid(P), strerror(errno));
#endif
	}
Пример #16
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);
}
Пример #17
0
static int
rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd)
{
    char mapname[PATH_MAX];
    int mapfd, nmap, i, rc;
    struct stat st;
    prmap_t *prmapp, *pmp;
    ssize_t n;

    (void) snprintf(mapname, sizeof (mapname),
                    "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid);

    if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) {
        if (mapfd >= 0)
            (void) close(mapfd);
        return (perr(mapname));
    }

    nmap = st.st_size / sizeof (prmap_t);
    prmapp = malloc((nmap + 1) * sizeof (prmap_t));

    if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) {
        (void) close(mapfd);
        free(prmapp);
        return (perr("read rmap"));
    }

    (void) close(mapfd);
    nmap = n / sizeof (prmap_t);

    for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) {
        if ((rc = func(cd, pmp, NULL)) != 0) {
            free(prmapp);
            return (rc);
        }
    }

    free(prmapp);
    return (0);
}
Пример #18
0
/*
 * Common code for enabling events associated with the run-time linker after
 * attaching to a process or after a victim process completes an exec(2).
 */
static void
dt_proc_attach(dt_proc_t *dpr, int exec)
{
	const pstatus_t *psp = Pstatus(dpr->dpr_proc);
	rd_err_e err;
	GElf_Sym sym;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	if (exec) {
		if (psp->pr_lwp.pr_errno != 0)
			return; /* exec failed: nothing needs to be done */

		dt_proc_bpdestroy(dpr, B_FALSE);
		Preset_maps(dpr->dpr_proc);
	}

	if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
	    (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
		dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
		dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
		dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
	} else {
		dt_dprintf("pid %d: failed to enable rtld events: %s\n",
		    (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
		    "rtld_db agent initialization failed");
	}

	Pupdate_maps(dpr->dpr_proc);

	if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE,
	    "a.out", "main", &sym, NULL) == 0) {
		(void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value,
		    (dt_bkpt_f *)dt_proc_bpmain, "a.out`main");
	} else {
		dt_dprintf("pid %d: failed to find a.out`main: %s\n",
		    (int)dpr->dpr_pid, strerror(errno));
	}
}
Пример #19
0
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
#ifdef illumos
	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
#else
	unsigned long pc;
#endif
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

#ifndef illumos
	proc_regget(dpr->dpr_proc, REG_PC, &pc);
	proc_bkptregadj(&pc);
#endif

	for (dbp = dt_list_next(&dpr->dpr_bps);
	    dbp != NULL; dbp = dt_list_next(dbp)) {
#ifdef illumos
		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
			break;
#else
		if (pc == dbp->dbp_addr)
			break;
#endif
	}

	if (dbp == NULL) {
		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
#ifdef illumos
		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
#else
		    (int)dpr->dpr_pid, pc);
#endif
		return;
	}
Пример #20
0
static int
dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
    dt_pcb_t *pcb, dt_proc_t *dpr)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	int ret = 0;

	assert(MUTEX_HELD(&dpr->dpr_lock));

	(void) Pupdate_maps(P);
	if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
		ret = -1;
		(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
		    "failed to instantiate probes for pid %d: %s",
		    (int)Pstatus(P)->pr_pid, strerror(errno));
	}

	/*
	 * Put the module name in its canonical form.
	 */
	(void) dt_pid_fix_mod(pdp, P);

	return (ret);
}
Пример #21
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);
}
Пример #22
0
/*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);
}
Пример #23
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);
}
Пример #24
0
static void
dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
{
	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
	dt_proc_hash_t *dph = dtp->dt_procs;
	dt_proc_notify_t *npr, **npp;
	int rflag;

	assert(dpr != NULL);

	/*
	 * If neither PR_KLC nor PR_RLC is set, then the process is stopped by
	 * an external debugger and we were waiting in dt_proc_waitrun().
	 * Leave the process in this condition using PRELEASE_HANG.
	 */
printf("dt_proc_destroy flags=%d\n", Pstatus(dpr->dpr_proc)->pr_flags);
	if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
		dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
		rflag = PRELEASE_HANG;
	} else {
		dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
		rflag = 0; /* apply kill or run-on-last-close */
	}

	if (dpr->dpr_tid) {
		/*
		 * Set the dpr_quit flag to tell the daemon thread to exit.  We
		 * send it a SIGCANCEL to poke it out of PCWSTOP or any other
		 * long-term /proc system call.  Our daemon threads have POSIX
		 * cancellation disabled, so EINTR will be the only effect.  We
		 * then wait for dpr_done to indicate the thread has exited.
		 *
		 * We can't use pthread_kill() to send SIGCANCEL because the
		 * interface forbids it and we can't use pthread_cancel()
		 * because with cancellation disabled it won't actually
		 * send SIGCANCEL to the target thread, so we use _lwp_kill()
		 * to do the job.  This is all built on evil knowledge of
		 * the details of the cancellation mechanism in libc.
		 */
		(void) pthread_mutex_lock(&dpr->dpr_lock);
		dpr->dpr_quit = B_TRUE;
#if defined(sun)
		(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
#else
		(void) pthread_kill(dpr->dpr_tid, SIGUSR1);
#endif

		/*
		 * If the process is currently idling in dt_proc_stop(), re-
		 * enable breakpoints and poke it into running again.
		 */
		if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
			dt_proc_bpenable(dpr);
			dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
			(void) pthread_cond_broadcast(&dpr->dpr_cv);
		}

		while (!dpr->dpr_done)
			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
	}

	/*
	 * Before we free the process structure, remove this dt_proc_t from the
	 * lookup hash, and then walk the dt_proc_hash_t's notification list
	 * and remove this dt_proc_t if it is enqueued.
	 */
	(void) pthread_mutex_lock(&dph->dph_lock);
	(void) dt_proc_lookup(dtp, P, B_TRUE);
	npp = &dph->dph_notify;

	while ((npr = *npp) != NULL) {
		if (npr->dprn_dpr == dpr) {
			*npp = npr->dprn_next;
			dt_free(dtp, npr);
		} else {
			npp = &npr->dprn_next;
		}
	}

	(void) pthread_mutex_unlock(&dph->dph_lock);

	/*
	 * Remove the dt_proc_list from the LRU list, release the underlying
	 * libproc handle, and free our dt_proc_t data structure.
	 */
	if (dpr->dpr_cacheable) {
		assert(dph->dph_lrucnt != 0);
		dph->dph_lrucnt--;
	}

	dt_list_delete(&dph->dph_lrulist, dpr);
	Prelease(dpr->dpr_proc, rflag);
	dt_free(dtp, dpr);
}
Пример #25
0
/*
 * Main loop for all victim process control threads.  We initialize all the
 * appropriate /proc control mechanisms, and then enter a loop waiting for
 * the process to stop on an event or die.  We process any events by calling
 * appropriate subroutines, and exit when the victim dies or we lose control.
 *
 * The control thread synchronizes the use of dpr_proc with other libdtrace
 * threads using dpr_lock.  We hold the lock for all of our operations except
 * waiting while the process is running: this is accomplished by writing a
 * PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.  If the
 * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used.
 */
static void *
dt_proc_control(void *arg)
{
	dt_proc_control_data_t *datap = arg;
	dtrace_hdl_t *dtp = datap->dpcd_hdl;
	dt_proc_t *dpr = datap->dpcd_proc;
	dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs;
	struct ps_prochandle *P = dpr->dpr_proc;

#if defined(sun)
	int pfd = Pctlfd(P);

	const long wstop = PCWSTOP;
#endif
	int notify = B_FALSE;

	/*
	 * We disable the POSIX thread cancellation mechanism so that the
	 * client program using libdtrace can't accidentally cancel our thread.
	 * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out
	 * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit.
	 */
	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

	dpr->dpr_pid = proc_getpid(P);
	int pid = dpr->dpr_pid;

	/*
	 * Set up the corresponding process for tracing by libdtrace.  We want
	 * to be able to catch breakpoints and efficiently single-step over
	 * them, and we need to enable librtld_db to watch libdl activity.
	 */
	do_ptrace(__func__, PTRACE_ATTACH, dpr->dpr_pid, 0, 0);
	(void) pthread_mutex_lock(&dpr->dpr_lock);

	(void) Punsetflags(P, PR_ASYNC);	/* require synchronous mode */
	(void) Psetflags(P, PR_BPTADJ);		/* always adjust eip on x86 */
	(void) Punsetflags(P, PR_FORK);		/* do not inherit on fork */

	(void) Pfault(P, FLTBPT, B_TRUE);	/* always trace breakpoints */
	(void) Pfault(P, FLTTRACE, B_TRUE);	/* always trace single-step */

	/*
	 * We must trace exit from exec() system calls so that if the exec is
	 * successful, we can reset our breakpoints and re-initialize libproc.
	 */
	(void) Psysexit(P, SYS_exec, B_TRUE);
	(void) Psysexit(P, SYS_execve, B_TRUE);

	/*
	 * We must trace entry and exit for fork() system calls in order to
	 * disable our breakpoints temporarily during the fork.  We do not set
	 * the PR_FORK flag, so if fork succeeds the child begins executing and
	 * does not inherit any other tracing behaviors or a control thread.
	 */
	(void) Psysentry(P, SYS_vfork, B_TRUE);
	(void) Psysexit(P, SYS_vfork, B_TRUE);
	(void) Psysentry(P, SYS_fork1, B_TRUE);
	(void) Psysexit(P, SYS_fork1, B_TRUE);
	(void) Psysentry(P, SYS_forkall, B_TRUE);
	(void) Psysexit(P, SYS_forkall, B_TRUE);
	(void) Psysentry(P, SYS_forksys, B_TRUE);
	(void) Psysexit(P, SYS_forksys, B_TRUE);

	Psync(P);				/* enable all /proc changes */
	dt_proc_attach(dpr, B_FALSE);		/* enable rtld breakpoints */

	/*
	 * If PR_KLC is set, we created the process; otherwise we grabbed it.
	 * Check for an appropriate stop request and wait for dt_proc_continue.
	 */
	dpr->dpr_stop |= DT_PROC_STOP_CREATE;
	if (Pstatus(P)->pr_flags & PR_KLC)
		dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
	else
		dt_proc_stop(dpr, DT_PROC_STOP_GRAB);

	if (Psetrun(P, 0, 0) == -1) {
		dt_dprintf("pid %d: failed to set running: %s\n",
		    (int)dpr->dpr_pid, strerror(errno));
	}

	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	/*
	 * Wait for the process corresponding to this control thread to stop,
	 * process the event, and then set it running again.  We want to sleep
	 * with dpr_lock *unheld* so that other parts of libdtrace can use the
	 * ps_prochandle in the meantime (e.g. ustack()).  To do this, we write
	 * a PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.
	 * Once the process stops, we wake up, grab dpr_lock, and then call
	 * Pwait() (which will return immediately) and do our processing.
	 */
//printf("%s: waiting to quit\n", __func__);
	while (!dpr->dpr_quit) {
		const lwpstatus_t *psp;
#if defined(sun)

		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
			continue; /* check dpr_quit and continue waiting */
#else
		/* Wait for the process to report status. */
                proc_wait(P);
#endif
		(void) pthread_mutex_lock(&dpr->dpr_lock);
pwait_locked:
		if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
//printf("%s stopstatus (loop) pr_pid pid=%d\n", __func__, Pstatus(dpr->dpr_proc)->pr_pid);
			(void) pthread_mutex_unlock(&dpr->dpr_lock);
			continue; /* check dpr_quit and continue waiting */
		}

		switch (Pstate(P)) {
		case PS_STOP:
			psp = &Pstatus(P)->pr_lwp;

			dt_dprintf("pid %d: proc stopped showing %d/%d\n",
			    pid, psp->pr_why, psp->pr_what);

#if defined(sun)
			/*
			 * If the process stops showing PR_REQUESTED, then the
			 * DTrace stop() action was applied to it or another
			 * debugging utility (e.g. pstop(1)) asked it to stop.
			 * In either case, the user's intention is for the
			 * process to remain stopped until another external
			 * mechanism (e.g. prun(1)) is applied.  So instead of
			 * setting the process running ourself, we wait for
			 * someone else to do so.  Once that happens, we return
			 * to our normal loop waiting for an event of interest.
			 */
			if (psp->pr_why == PR_REQUESTED) {
				dt_proc_waitrun(dpr);
				(void) pthread_mutex_unlock(&dpr->dpr_lock);
				continue;
			}

			/*
			 * If the process stops showing one of the events that
			 * we are tracing, perform the appropriate response.
			 * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and
			 * PR_JOBCONTROL by design: if one of these conditions
			 * occurs, we will fall through to Psetrun() but the
			 * process will remain stopped in the kernel by the
			 * corresponding mechanism (e.g. job control stop).
			 */
			if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT)
				dt_proc_bpmatch(dtp, dpr);
			else if (psp->pr_why == PR_SYSENTRY &&
			    IS_SYS_FORK(psp->pr_what))
				dt_proc_bpdisable(dpr);
			else if (psp->pr_why == PR_SYSEXIT &&
			    IS_SYS_FORK(psp->pr_what))
				dt_proc_bpenable(dpr);
			else if (psp->pr_why == PR_SYSEXIT &&
			    IS_SYS_EXEC(psp->pr_what))
				dt_proc_attach(dpr, B_TRUE);
#endif
//printf("In PS_STOP dpr_stop=%x\n", dpr->dpr_stop);
			break;

		case PS_LOST:
//printf("in PS_LOST\n");
			if (Preopen(P) == 0)
				goto pwait_locked;

			dt_dprintf("pid %d: proc lost: %s\n",
			    pid, strerror(errno));

			dpr->dpr_quit = B_TRUE;
			notify = B_TRUE;
			break;

		case PS_UNDEAD:
		case PS_DEAD:
			dt_dprintf("pid %d: proc died\n", pid);
			dpr->dpr_quit = B_TRUE;
			notify = B_TRUE;
			break;

		}

		if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
			dt_dprintf("pid %d: failed to set running: %s\n",
			    (int)dpr->dpr_pid, strerror(errno));
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
	}

	/*
	 * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
	 * the dt_proc_t structure on the dt_proc_hash_t notification list.
	 */
	if (notify)
		dt_proc_notify(dtp, dph, dpr, NULL);

	/*
	 * Destroy and remove any remaining breakpoints, set dpr_done and clear
	 * dpr_tid to indicate the control thread has exited, and notify any
	 * waiting thread in dt_proc_destroy() that we have succesfully exited.
	 */
	(void) pthread_mutex_lock(&dpr->dpr_lock);

	dt_proc_bpdestroy(dpr, B_TRUE);
	dpr->dpr_done = B_TRUE;
	dpr->dpr_tid = 0;

	(void) pthread_cond_broadcast(&dpr->dpr_cv);
	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	return (NULL);
}
Пример #26
0
int
main(int argc, char **argv)
{
	int err;
	int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0;
	char c, *p, *end;
	struct sigaction act;
	int done = 0;

	g_pname = basename(argv[0]);
	argv[0] = g_pname; /* rewrite argv[0] for getopt errors */

	while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
		switch (c) {
		case 'n':
			errno = 0;
			g_nent = strtoul(optarg, &end, 10);
			if (*end != '\0' || errno != 0) {
				(void) fprintf(stderr, "%s: invalid count "
				    "'%s'\n", g_pname, optarg);
				usage();
			}
			break;

		case 'p':
			opt_p = 1;
			break;

		case 'v':
			opt_v = 1;
			break;

		case 'A':
			opt_C = opt_H = 1;
			break;

		case 'C':
			opt_C = 1;
			break;

		case 'H':
			opt_H = 1;
			break;

		case 'V':
			g_opt_V = 1;
			break;

		default:
			if (strchr(PLOCKSTAT_OPTSTR, c) == NULL)
				usage();
		}
	}

	/*
	 * We need a command or at least one pid.
	 */
	if (argc == optind)
		usage();

	if (opt_C == 0 && opt_H == 0)
		opt_C = 1;

	if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL)
		fatal("failed to initialize dtrace: %s\n",
		    dtrace_errmsg(NULL, err));

	/*
	 * The longest string we trace is 23 bytes long -- so 32 is plenty.
	 */
	if (dtrace_setopt(g_dtp, "strsize", "32") == -1)
		dfatal("failed to set 'strsize'");

	/*
	 * 1k should be more than enough for all trace() and printa() actions.
	 */
	if (dtrace_setopt(g_dtp, "bufsize", "1k") == -1)
		dfatal("failed to set 'bufsize'");

	/*
	 * The table we produce has the hottest locks at the top.
	 */
	if (dtrace_setopt(g_dtp, "aggsortrev", NULL) == -1)
		dfatal("failed to set 'aggsortrev'");

	/*
	 * These are two reasonable defaults which should suffice.
	 */
	if (dtrace_setopt(g_dtp, "aggsize", "256k") == -1)
		dfatal("failed to set 'aggsize'");
	if (dtrace_setopt(g_dtp, "aggrate", "1sec") == -1)
		dfatal("failed to set 'aggrate'");

	/*
	 * Take a second pass through to look for options that set options now
	 * that we have an open dtrace handle.
	 */
	optind = 1;
	while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
		switch (c) {
		case 's':
			g_opt_s = 1;
			if (dtrace_setopt(g_dtp, "ustackframes", optarg) == -1)
				dfatal("failed to set 'ustackframes'");
			break;

		case 'x':
			if ((p = strchr(optarg, '=')) != NULL)
				*p++ = '\0';

			if (dtrace_setopt(g_dtp, optarg, p) != 0)
				dfatal("failed to set -x %s", optarg);
			break;

		case 'e':
			errno = 0;
			(void) strtoul(optarg, &end, 10);
			if (*optarg == '-' || *end != '\0' || errno != 0) {
				(void) fprintf(stderr, "%s: invalid timeout "
				    "'%s'\n", g_pname, optarg);
				usage();
			}

			/*
			 * Construct a DTrace enabling that will exit after
			 * the specified number of seconds.
			 */
			dprog_add("BEGIN\n{\n\tend = timestamp + ");
			dprog_add(optarg);
			dprog_add(" * 1000000000;\n}\n");
			dprog_add("tick-10hz\n/timestamp >= end/\n");
			dprog_add("{\n\texit(0);\n}\n");
			break;
		}
	}

	argc -= optind;
	argv += optind;

	if (opt_H) {
		dprog_add(g_hold_init);
		if (g_opt_s == NULL)
			dprog_add(g_hold_times);
		else
			dprog_add(g_hold_histogram);
	}

	if (opt_C) {
		dprog_add(g_ctnd_init);
		if (g_opt_s == NULL)
			dprog_add(g_ctnd_times);
		else
			dprog_add(g_ctnd_histogram);
	}

	if (opt_p) {
		ulong_t pid;

		if (argc > 1) {
			(void) fprintf(stderr, "%s: only one pid is allowed\n",
			    g_pname);
			usage();
		}

		errno = 0;
		pid = strtoul(argv[0], &end, 10);
		if (*end != '\0' || errno != 0 || (pid_t)pid != pid) {
			(void) fprintf(stderr, "%s: invalid pid '%s'\n",
			    g_pname, argv[0]);
			usage();
		}

		if ((g_pr = dtrace_proc_grab(g_dtp, (pid_t)pid, 0)) == NULL)
			dfatal(NULL);
	} else {
		if ((g_pr = dtrace_proc_create(g_dtp, argv[0], argv)) == NULL)
			dfatal(NULL);
	}

	dprog_compile();

	if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
		dfatal("failed to establish proc handler");

	(void) sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = intr;
	(void) sigaction(SIGINT, &act, NULL);
	(void) sigaction(SIGTERM, &act, NULL);

	if (dtrace_go(g_dtp) != 0)
		dfatal("dtrace_go()");

	if (dtrace_getopt(g_dtp, "ustackframes", &g_nframes) != 0)
		dfatal("failed to get 'ustackframes'");

	dtrace_proc_continue(g_dtp, g_pr);

	if (opt_v)
		(void) printf("%s: tracing enabled for pid %d\n", g_pname,
		    (int)Pstatus(g_pr)->pr_pid);

	do {
		if (!g_intr && !done)
			dtrace_sleep(g_dtp);

		if (done || g_intr || g_exited) {
			done = 1;
			if (dtrace_stop(g_dtp) == -1)
				dfatal("couldn't stop tracing");
		}

		switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
		case DTRACE_WORKSTATUS_DONE:
			done = 1;
			break;
		case DTRACE_WORKSTATUS_OKAY:
			break;
		default:
			dfatal("processing aborted");
		}

	} while (!done);

	dtrace_close(g_dtp);

	return (0);
}
Пример #27
0
/*ARGSUSED*/
static int
look_smap(void *data,
          const prxmap_t *pmp,
          const char *object_name,
          int last, int doswap)
{
    struct totals *t = data;
    const pstatus_t *Psp = Pstatus(Pr);
    size_t size;
    char mname[PATH_MAX];
    char *lname = NULL;
    const char *format;
    size_t	psz = pmp->pr_pagesize;
    uintptr_t vaddr = pmp->pr_vaddr;
    uintptr_t segment_end = vaddr + pmp->pr_size;
    lgrp_id_t lgrp;
    memory_chunk_t mchunk;

    /*
     * If the mapping is not anon or not part of the heap, make a name
     * for it.  We don't want to report the heap as a.out's data.
     */
    if (!(pmp->pr_mflags & MA_ANON) ||
            pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
            pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
        lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
                          mname, sizeof (mname));
    }

    if (lname == NULL &&
            ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) {
        lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
                          pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
    }

    /*
     * Adjust the address range if -A is specified.
     */
    size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz,
                             &vaddr, &segment_end);

    if (size == 0)
        return (0);

    if (!Lflag) {
        /*
         * Display the whole mapping
         */
        if (lname != NULL)
            format = "%.*lX %*luK %4s %-6s %s\n";
        else
            format = "%.*lX %*luK %4s %s\n";

        size = ROUNDUP_KB(size);

        (void) printf(format, addr_width, vaddr, size_width - 1, size,
                      pagesize(pmp), mflags(pmp->pr_mflags), lname);

        t->total_size += size;
        return (0);
    }

    if (lname != NULL)
        format = "%.*lX %*luK %4s %-6s%s %s\n";
    else
        format = "%.*lX %*luK %4s%s %s\n";

    /*
     * We need to display lgroups backing physical memory, so we break the
     * segment into individual pages and coalesce pages with the same lgroup
     * into one "segment".
     */

    /*
     * Initialize address descriptions for the mapping.
     */
    mem_chunk_init(&mchunk, segment_end, psz);
    size = 0;

    /*
     * Walk mapping (page by page) and display contiguous ranges of memory
     * allocated to same lgroup.
     */
    do {
        size_t		size_contig;

        /*
         * Get contiguous region of memory starting from vaddr allocated
         * from the same lgroup.
         */
        size_contig = get_contiguous_region(&mchunk, vaddr,
                                            segment_end, pmp->pr_pagesize, &lgrp);

        (void) printf(format, addr_width, vaddr,
                      size_width - 1, size_contig / KILOBYTE,
                      pagesize(pmp), mflags(pmp->pr_mflags),
                      lgrp2str(lgrp), lname);

        vaddr += size_contig;
        size += size_contig;
    } while (vaddr < segment_end && !interrupt);

    t->total_size += ROUNDUP_KB(size);
    return (0);
}
Пример #28
0
/*ARGSUSED*/
int
pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	mdb_tgt_t *t = mdb.m_target;
	mdb_tgt_tid_t tid;
	prgregset_t grs;
	uint64_t xgregs[8];
	uint64_t xoregs[8];
	int rwidth, i;

#if defined(__sparc) && defined(_ILP32)
	static const uint32_t zero[8] = { 0 };
	prxregset_t xrs;
#endif

#define	GETREG2(x) ((uintptr_t)grs[(x)]), ((uintptr_t)grs[(x)])

	if (argc != 0)
		return (DCMD_USAGE);

	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
		mdb_warn("no process active\n");
		return (DCMD_ERR);
	}

	if (Pstate(t->t_pshandle) == PS_LOST) {
		mdb_warn("debugger has lost control of process\n");
		return (DCMD_ERR);
	}

	if (flags & DCMD_ADDRSPEC)
		tid = (mdb_tgt_tid_t)addr;
	else
		tid = PTL_TID(t);

	if (PTL_GETREGS(t, tid, grs) != 0) {
		mdb_warn("failed to get current register set");
		return (DCMD_ERR);
	}

	for (i = 0; i < 8; i++) {
		xgregs[i] = (ulong_t)grs[R_G0 + i];
		xoregs[i] = (ulong_t)grs[R_O0 + i];
	}

	if (Pstatus(t->t_pshandle)->pr_dmodel == PR_MODEL_LP64)
		rwidth = 16;
	else
		rwidth = 8;

#if defined(__sparc) && defined(_ILP32)
	/*
	 * If we are debugging a 32-bit SPARC process on an UltraSPARC CPU,
	 * the globals and outs can have 32 upper bits hiding in the xregs.
	 */
	if (PTL_GETXREGS(t, tid, &xrs) == 0 && xrs.pr_type == XR_TYPE_V8P) {
		for (i = 0; i < 8; i++) {
			xgregs[i] |= (uint64_t)
			    xrs.pr_un.pr_v8p.pr_xg[XR_G0 + i] << 32;
			xoregs[i] |= (uint64_t)
			    xrs.pr_un.pr_v8p.pr_xo[XR_O0 + i] << 32;
		}

		if (bcmp(xrs.pr_un.pr_v8p.pr_xg, zero, sizeof (zero)) ||
		    bcmp(xrs.pr_un.pr_v8p.pr_xo, zero, sizeof (zero)))
			rwidth = 16; /* one or more have upper bits set */
	}
#endif	/* __sparc && _ILP32 */

	for (i = 0; i < 8; i++) {
		mdb_printf("%%g%d = 0x%0*llx %15llA %%l%d = 0x%0?p %A\n",
		    i, rwidth, xgregs[i], xgregs[i], i, GETREG2(R_L0 + i));
	}

	for (i = 0; i < 8; i++) {
		mdb_printf("%%o%d = 0x%0*llx %15llA %%i%d = 0x%0?p %A\n",
		    i, rwidth, xoregs[i], xoregs[i], i, GETREG2(R_I0 + i));
	}

	mdb_printf("\n");

#ifdef __sparcv9
	mdb_printf(" %%ccr = 0x%02x xcc=%c%c%c%c icc=%c%c%c%c\n", grs[R_CCR],
	    (grs[R_CCR] & KREG_CCR_XCC_N_MASK) ? 'N' : 'n',
	    (grs[R_CCR] & KREG_CCR_XCC_Z_MASK) ? 'Z' : 'z',
	    (grs[R_CCR] & KREG_CCR_XCC_V_MASK) ? 'V' : 'v',
	    (grs[R_CCR] & KREG_CCR_XCC_C_MASK) ? 'C' : 'c',
	    (grs[R_CCR] & KREG_CCR_ICC_N_MASK) ? 'N' : 'n',
	    (grs[R_CCR] & KREG_CCR_ICC_Z_MASK) ? 'Z' : 'z',
	    (grs[R_CCR] & KREG_CCR_ICC_V_MASK) ? 'V' : 'v',
	    (grs[R_CCR] & KREG_CCR_ICC_C_MASK) ? 'C' : 'c');
#else	/* __sparcv9 */
	mdb_printf(" %%psr = 0x%08x impl=0x%x ver=0x%x icc=%c%c%c%c\n"
	    "                   ec=%u ef=%u pil=%u s=%u ps=%u et=%u cwp=0x%x\n",
	    grs[R_PSR],
	    (grs[R_PSR] & KREG_PSR_IMPL_MASK) >> KREG_PSR_IMPL_SHIFT,
	    (grs[R_PSR] & KREG_PSR_VER_MASK) >> KREG_PSR_VER_SHIFT,
	    (grs[R_PSR] & KREG_PSR_ICC_N_MASK) ? 'N' : 'n',
	    (grs[R_PSR] & KREG_PSR_ICC_Z_MASK) ? 'Z' : 'z',
	    (grs[R_PSR] & KREG_PSR_ICC_V_MASK) ? 'V' : 'v',
	    (grs[R_PSR] & KREG_PSR_ICC_C_MASK) ? 'C' : 'c',
	    grs[R_PSR] & KREG_PSR_EC_MASK, grs[R_PSR] & KREG_PSR_EF_MASK,
	    (grs[R_PSR] & KREG_PSR_PIL_MASK) >> KREG_PSR_PIL_SHIFT,
	    grs[R_PSR] & KREG_PSR_S_MASK, grs[R_PSR] & KREG_PSR_PS_MASK,
	    grs[R_PSR] & KREG_PSR_ET_MASK,
	    (grs[R_PSR] & KREG_PSR_CWP_MASK) >> KREG_PSR_CWP_SHIFT);
#endif	/* __sparcv9 */

	mdb_printf("   %%y = 0x%0?p\n", grs[R_Y]);

	mdb_printf("  %%pc = 0x%0?p %A\n", GETREG2(R_PC));
	mdb_printf(" %%npc = 0x%0?p %A\n", GETREG2(R_nPC));

	mdb_printf("  %%sp = 0x%0?p\n", grs[R_SP]);
	mdb_printf("  %%fp = 0x%0?p\n\n", grs[R_FP]);

#ifdef __sparcv9
	mdb_printf(" %%asi = 0x%02lx\n", grs[R_ASI]);
	mdb_printf("%%fprs = 0x%02lx\n", grs[R_FPRS]);
#else	/* __sparcv9 */
	mdb_printf(" %%wim = 0x%08x\n", grs[R_WIM]);
	mdb_printf(" %%tbr = 0x%08x\n", grs[R_TBR]);
#endif	/* __sparcv9 */

	return (DCMD_OK);
}
Пример #29
0
/*ARGSUSED*/
static int
look_xmap_nopgsz(void *data,
                 const prxmap_t *pmp,
                 const char *object_name,
                 int last, int doswap)
{
    struct totals *t = data;
    const pstatus_t *Psp = Pstatus(Pr);
    char mname[PATH_MAX];
    char *lname = NULL;
    char *ln;
    static uintptr_t prev_vaddr;
    static size_t prev_size;
    static offset_t prev_offset;
    static int prev_mflags;
    static char *prev_lname;
    static char prev_mname[PATH_MAX];
    static ulong_t prev_rss;
    static ulong_t prev_anon;
    static ulong_t prev_locked;
    static ulong_t prev_swap;
    int merged = 0;
    static int first = 1;
    ulong_t swap = 0;
    int kperpage;

    /*
     * Calculate swap reservations
     */
    if (pmp->pr_mflags & MA_SHARED) {
        if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) {
            /* Swap reserved for entire non-ism SHM */
            swap = pmp->pr_size / pmp->pr_pagesize;
        }
    } else if (pmp->pr_mflags & MA_NORESERVE) {
        /* Swap reserved on fault for each anon page */
        swap = pmp->pr_anon;
    } else if (pmp->pr_mflags & MA_WRITE) {
        /* Swap reserve for entire writable segment */
        swap = pmp->pr_size / pmp->pr_pagesize;
    }

    /*
     * If the mapping is not anon or not part of the heap, make a name
     * for it.  We don't want to report the heap as a.out's data.
     */
    if (!(pmp->pr_mflags & MA_ANON) ||
            pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
            pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
        lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
                          mname, sizeof (mname));
    }

    if (lname != NULL) {
        if ((ln = strrchr(lname, '/')) != NULL)
            lname = ln + 1;
    } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) {
        lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr,
                          pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL);
    }

    kperpage = pmp->pr_pagesize / KILOBYTE;

    t->total_size += ROUNDUP_KB(pmp->pr_size);
    t->total_rss += pmp->pr_rss * kperpage;
    t->total_anon += ANON(pmp) * kperpage;
    t->total_locked += pmp->pr_locked * kperpage;
    t->total_swap += swap * kperpage;

    if (first == 1) {
        first = 0;
        prev_vaddr = pmp->pr_vaddr;
        prev_size = pmp->pr_size;
        prev_offset = pmp->pr_offset;
        prev_mflags = pmp->pr_mflags;
        if (lname == NULL) {
            prev_lname = NULL;
        } else {
            (void) strcpy(prev_mname, lname);
            prev_lname = prev_mname;
        }
        prev_rss = pmp->pr_rss * kperpage;
        prev_anon = ANON(pmp) * kperpage;
        prev_locked = pmp->pr_locked * kperpage;
        prev_swap = swap * kperpage;
        if (last == 0) {
            return (0);
        }
        merged = 1;
    } else if (prev_vaddr + prev_size == pmp->pr_vaddr &&
               prev_mflags == pmp->pr_mflags &&
               ((prev_mflags & MA_ISM) ||
                prev_offset + prev_size == pmp->pr_offset) &&
               ((lname == NULL && prev_lname == NULL) ||
                (lname != NULL && prev_lname != NULL &&
                 strcmp(lname, prev_lname) == 0))) {
        prev_size += pmp->pr_size;
        prev_rss += pmp->pr_rss * kperpage;
        prev_anon += ANON(pmp) * kperpage;
        prev_locked += pmp->pr_locked * kperpage;
        prev_swap += swap * kperpage;
        if (last == 0) {
            return (0);
        }
        merged = 1;
    }

    (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr);
    printK(ROUNDUP_KB(prev_size), size_width);

    if (doswap)
        printK(prev_swap, size_width);
    else {
        printK(prev_rss, size_width);
        printK(prev_anon, size_width);
        printK(prev_locked, size_width);
    }
    (void) printf(prev_lname ? " %-6s %s\n" : "%s\n",
                  mflags(prev_mflags), prev_lname);

    if (last == 0) {
        prev_vaddr = pmp->pr_vaddr;
        prev_size = pmp->pr_size;
        prev_offset = pmp->pr_offset;
        prev_mflags = pmp->pr_mflags;
        if (lname == NULL) {
            prev_lname = NULL;
        } else {
            (void) strcpy(prev_mname, lname);
            prev_lname = prev_mname;
        }
        prev_rss = pmp->pr_rss * kperpage;
        prev_anon = ANON(pmp) * kperpage;
        prev_locked = pmp->pr_locked * kperpage;
        prev_swap = swap * kperpage;
    } else if (merged == 0) {
        (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr);
        printK(ROUNDUP_KB(pmp->pr_size), size_width);
        if (doswap)
            printK(swap * kperpage, size_width);
        else {
            printK(pmp->pr_rss * kperpage, size_width);
            printK(ANON(pmp) * kperpage, size_width);
            printK(pmp->pr_locked * kperpage, size_width);
        }
        (void) printf(lname ? " %-6s %s\n" : " %s\n",
                      mflags(pmp->pr_mflags), lname);
    }

    if (last != 0)
        first = 1;

    return (0);
}
Пример #30
0
/*ARGSUSED*/
int
pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	mdb_tgt_t *t = mdb.m_target;
	mdb_tgt_tid_t tid;
	int is_v8plus, is_v9, i;
#ifdef	__sparcv9
	prgregset_t grs;
#endif
	prfpregset_t fprs;
	prxregset_t xrs;
	uint32_t *regs;
	int ns, nd, nq;

	enum {
		FPR_MIXED	= 0x0, /* show single, double, and status */
		FPR_SINGLE	= 0x1, /* show single-precision only */
		FPR_DOUBLE	= 0x2, /* show double-precision only */
		FPR_QUAD	= 0x4  /* show quad-precision only */
	};

	uint_t opts = FPR_MIXED;

	/*
	 * The prfpregset structure only provides us with the FPU in the form
	 * of 32-bit integers, doubles, or quads.  We use this union of the
	 * various types to display floats, doubles, and long doubles.
	 */
	union {
		struct {
			uint32_t i1;
			uint32_t i2;
			uint32_t i3;
			uint32_t i4;
		} ip;
		float f;
		double d;
		long double ld;
	} fpu;

	if (mdb_getopts(argc, argv,
	    's', MDB_OPT_SETBITS, FPR_SINGLE, &opts,
	    'd', MDB_OPT_SETBITS, FPR_DOUBLE, &opts,
	    'q', MDB_OPT_SETBITS, FPR_QUAD, &opts, NULL) != argc)
		return (DCMD_USAGE);

	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
		mdb_warn("no process active\n");
		return (DCMD_ERR);
	}

	if (Pstate(t->t_pshandle) == PS_LOST) {
		mdb_warn("debugger has lost control of process\n");
		return (DCMD_ERR);
	}

	if (flags & DCMD_ADDRSPEC)
		tid = (mdb_tgt_tid_t)addr;
	else
		tid = PTL_TID(t);

	is_v9 = Pstatus(t->t_pshandle)->pr_dmodel == PR_MODEL_LP64;
	is_v8plus = is_v9 == 0 && PTL_GETXREGS(t, tid, &xrs) == 0 &&
	    xrs.pr_type == XR_TYPE_V8P;

#ifdef	__sparcv9
	if (is_v9 && opts == FPR_MIXED) {
		if (PTL_GETREGS(t, tid, grs) == 0)
			mdb_printf("fprs %lx\n", grs[R_FPRS]);
		else
			mdb_warn("failed to read fprs register");
	}
#endif
	if (is_v8plus && opts == FPR_MIXED)
		mdb_printf("fprs %x\n", xrs.pr_un.pr_v8p.pr_fprs);

	if (PTL_GETFPREGS(t, tid, &fprs) != 0) {
		mdb_warn("failed to get floating point registers");
		return (DCMD_ERR);
	}

	if (opts == FPR_MIXED) {
		uint64_t fsr = fprs.pr_fsr;
		if (is_v8plus)
			fsr |= (uint64_t)xrs.pr_un.pr_v8p.pr_xfsr << 32;
		mdb_printf("fsr  %llx\n", fsr);
	}

	/*
	 * Set up the regs pointer to be a pointer to a contiguous chunk of
	 * memory containing all the floating pointer register data.  Set
	 * ns, nd, and nq to indicate the number of registers of each type.
	 */
	if (is_v9) {
		regs = fprs.pr_fr.pr_regs;
		ns = 64;
		nd = 32;
		nq = 16;
	} else if (is_v8plus) {
		regs = mdb_alloc(sizeof (uint32_t) * 64, UM_SLEEP | UM_GC);
		bcopy(fprs.pr_fr.pr_regs, regs, sizeof (uint32_t) * 32);
		bcopy(xrs.pr_un.pr_v8p.pr_xfr.pr_regs, regs + 32,
		    sizeof (uint32_t) * 32);
		ns = 64;
		nd = 32;
		nq = 16;
	} else {
		regs = fprs.pr_fr.pr_regs;
		ns = 32;
		nd = 16;
		nq = 0;
	}

	if (opts == FPR_MIXED) {
		for (i = 0; i < ns; i++) {
			fpu.ip.i1 = regs[i];
			mdb_printf("f%-3d %08x   %e", i, fpu.ip.i1, fpu.f);
			if (i & 1) {
				fpu.ip.i1 = regs[i - 1];
				fpu.ip.i2 = regs[i];
				mdb_printf("   %g", fpu.d);
			}
			mdb_printf("\n");
		}
	}

	if (opts & FPR_SINGLE) {
		for (i = 0; i < ns; i++) {
			fpu.ip.i1 = regs[i];
			mdb_printf("f%-3d %08x   %e\n", i, fpu.ip.i1, fpu.f);
		}
	}

	if (opts & FPR_DOUBLE) {
		for (i = 0; i < nd; i++) {
			fpu.ip.i1 = regs[i * 2 + 0];
			fpu.ip.i2 = regs[i * 2 + 1];
			mdb_printf("f%-3d %08x.%08x   %g\n", i * 2,
			    fpu.ip.i1, fpu.ip.i2, fpu.d);
		}
	}

	if (opts & FPR_QUAD) {
		for (i = 0; i < nq; i++) {
			fpu.ip.i1 = regs[i * 4 + 0];
			fpu.ip.i2 = regs[i * 4 + 1];
			fpu.ip.i3 = regs[i * 4 + 2];
			fpu.ip.i4 = regs[i * 4 + 3];
			mdb_printf("f%-3d %08x.%08x.%08x.%08x   %s\n", i * 4,
			    fpu.ip.i1, fpu.ip.i2, fpu.ip.i3, fpu.ip.i4,
			    longdoubletos(&fpu.ld, 16, 'e'));
		}
	}

	return (DCMD_OK);
}