summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1996-02-22 19:25:43 +0000
committerPeter Wemm <peter@FreeBSD.org>1996-02-22 19:25:43 +0000
commit31cdc03245ac76d861b4aa811bbdd70ac29a2ff3 (patch)
tree343ec2b8c52fce9d442531d42238d2dc8b7401d9
parent059f274907c4a88ad8e31791698683c75e1134c8 (diff)
Notes
-rw-r--r--lib/libkvm/kvm_private.h1
-rw-r--r--lib/libkvm/kvm_proc.c146
2 files changed, 113 insertions, 34 deletions
diff --git a/lib/libkvm/kvm_private.h b/lib/libkvm/kvm_private.h
index 5df73eb7ddf9..92ab1464e38c 100644
--- a/lib/libkvm/kvm_private.h
+++ b/lib/libkvm/kvm_private.h
@@ -57,6 +57,7 @@ struct __kvm {
int arglen; /* length of the above */
char **argv; /* (dynamic) storage for argv pointers */
int argc; /* length of above (not actual # present) */
+ char *argbuf; /* (dynamic) temporary storage */
/*
* Kernel virtual address translation state. This only gets filled
* in for dead kernels; otherwise, the running kernel (i.e. kmem)
diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c
index 6b29d4041e51..c26e680b79a0 100644
--- a/lib/libkvm/kvm_proc.c
+++ b/lib/libkvm/kvm_proc.c
@@ -65,6 +65,7 @@ static char sccsid[] = "@(#)kvm_proc.c 8.3 (Berkeley) 9/23/93";
#include <sys/sysctl.h>
#include <limits.h>
+#include <memory.h>
#include <db.h>
#include <paths.h>
@@ -158,6 +159,8 @@ kvm_proclist(kd, what, arg, p, bp, maxcnt)
pgrp.pg_session);
return (-1);
}
+ (void)memcpy(eproc.e_login, sess.s_login,
+ sizeof(eproc.e_login));
if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) {
if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) {
_kvm_err(kd, kd->program,
@@ -361,19 +364,20 @@ _kvm_realloc(kd, p, n)
/*
* Read in an argument vector from the user address space of process p.
- * addr is the user-space base address of narg null-terminated contiguous
+ * addr if the user-space base address of narg null-terminated contiguous
* strings. This is used to read in both the command arguments and
* environment strings. Read at most maxcnt characters of strings.
*/
static char **
kvm_argv(kd, p, addr, narg, maxcnt)
kvm_t *kd;
- struct proc *p;
+ const struct proc *p;
register u_long addr;
register int narg;
register int maxcnt;
{
- register char *cp;
+ register char *np, *cp, *ep, *ap;
+ register u_long oaddr = -1;
register int len, cc;
register char **argv;
@@ -384,6 +388,10 @@ kvm_argv(kd, p, addr, narg, maxcnt)
if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS)
return (0);
+ /*
+ * kd->argv : work space for fetching the strings from the target
+ * process's space, and is converted for returning to caller
+ */
if (kd->argv == 0) {
/*
* Try to avoid reallocs.
@@ -400,23 +408,84 @@ kvm_argv(kd, p, addr, narg, maxcnt)
if (kd->argv == 0)
return (0);
}
+ /*
+ * kd->argspc : returned to user, this is where the kd->argv
+ * arrays are left pointing to the collected strings.
+ */
if (kd->argspc == 0) {
kd->argspc = (char *)_kvm_malloc(kd, NBPG);
if (kd->argspc == 0)
return (0);
kd->arglen = NBPG;
}
- cp = kd->argspc;
+ /*
+ * kd->argbuf : used to pull in pages from the target process.
+ * the strings are copied out of here.
+ */
+ if (kd->argbuf == 0) {
+ kd->argbuf = (char *)_kvm_malloc(kd, NBPG);
+ if (kd->argbuf == 0)
+ return (0);
+ }
+
+ /* Pull in the target process'es argv vector */
+ cc = sizeof(char *) * narg;
+ if (kvm_uread(kd, p, addr, (char *)kd->argv, cc) != cc)
+ return (0);
+ /*
+ * ap : saved start address of string we're working on in kd->argspc
+ * np : pointer to next place to write in kd->argspc
+ * len: length of data in kd->argspc
+ * argv: pointer to the argv vector that we are hunting around the
+ * target process space for, and converting to addresses in
+ * our address space (kd->argspc).
+ */
+ ap = np = kd->argspc;
argv = kd->argv;
- *argv = cp;
len = 0;
/*
* Loop over pages, filling in the argument vector.
+ * Note that the argv strings could be pointing *anywhere* in
+ * the user address space and are no longer contiguous.
+ * Note that *argv is modified when we are going to fetch a string
+ * that crosses a page boundary. We copy the next part of the string
+ * into to "np" and eventually convert the pointer.
*/
- while (addr < VM_MAXUSER_ADDRESS) {
- cc = NBPG - (addr & PGOFSET);
+ while (argv < kd->argv + narg && *argv != 0) {
+
+ /* get the address that the current argv string is on */
+ addr = (u_long)*argv & ~(NBPG - 1);
+
+ /* is it the same page as the last one? */
+ if (addr != oaddr) {
+ if (kvm_uread(kd, p, addr, kd->argbuf, NBPG) !=
+ NBPG)
+ return (0);
+ oaddr = addr;
+ }
+
+ /* offset within the page... kd->argbuf */
+ addr = (u_long)*argv & (NBPG - 1);
+
+ /* cp = start of string, cc = count of chars in this chunk */
+ cp = kd->argbuf + addr;
+ cc = NBPG - addr;
+
+ /* dont get more than asked for by user process */
if (maxcnt > 0 && cc > maxcnt - len)
- cc = maxcnt - len;;
+ cc = maxcnt - len;
+
+ /* pointer to end of string if we found it in this page */
+ ep = memchr(cp, '\0', cc);
+ if (ep != 0)
+ cc = ep - cp + 1;
+ /*
+ * at this point, cc is the count of the chars that we are
+ * going to retrieve this time. we may or may not have found
+ * the end of it. (ep points to the null if the end is known)
+ */
+
+ /* will we exceed the malloc/realloced buffer? */
if (len + cc > kd->arglen) {
register int off;
register char **pp;
@@ -427,45 +496,52 @@ kvm_argv(kd, p, addr, narg, maxcnt)
kd->arglen);
if (kd->argspc == 0)
return (0);
- cp = &kd->argspc[len];
/*
* Adjust argv pointers in case realloc moved
* the string space.
*/
off = kd->argspc - op;
- for (pp = kd->argv; pp < argv; ++pp)
+ for (pp = kd->argv; pp < argv; pp++)
*pp += off;
+ ap += off;
+ np += off;
}
- if (kvm_uread(kd, p, addr, cp, cc) != cc)
- /* XXX */
- return (0);
+ /* np = where to put the next part of the string in kd->argspc*/
+ /* np is kinda redundant.. could use "kd->argspc + len" */
+ memcpy(np, cp, cc);
+ np += cc; /* inc counters */
len += cc;
- addr += cc;
- if (maxcnt == 0 && len > 16 * NBPG)
- /* sanity */
- return (0);
-
- while (--cc >= 0) {
- if (*cp++ == 0) {
- if (--narg <= 0 || (struct ps_strings *)(addr - cc) >= PS_STRINGS) {
- *++argv = 0;
- return (kd->argv);
- } else
- *++argv = cp;
- }
+ /*
+ * if end of string found, set the *argv pointer to the
+ * saved beginning of string, and advance. argv points to
+ * somewhere in kd->argv.. This is initially relative
+ * to the target process, but when we close it off, we set
+ * it to point in our address space.
+ */
+ if (ep != 0) {
+ *argv++ = ap;
+ ap = np;
+ } else {
+ /* update the address relative to the target process */
+ *argv += cc;
}
+
if (maxcnt > 0 && len >= maxcnt) {
/*
* We're stopping prematurely. Terminate the
- * argv and current string.
+ * current string.
*/
- *++argv = 0;
- *cp = 0;
- return (kd->argv);
+ if (ep == 0) {
+ *np = '\0';
+ *argv++ = ap;
+ }
+ break;
}
}
- return (0);
+ /* Make sure argv is terminated. */
+ *argv = 0;
+ return (kd->argv);
}
static void
@@ -517,7 +593,7 @@ kvm_doargv(kd, kp, nchr, info)
kvm_t *kd;
const struct kinfo_proc *kp;
int nchr;
- int (*info)(struct ps_strings*, u_long *, int *);
+ void (*info)(struct ps_strings *, u_long *, int *);
{
register const struct proc *p = &kp->kp_proc;
register char **ap;
@@ -529,11 +605,13 @@ kvm_doargv(kd, kp, nchr, info)
* Pointers are stored at the top of the user stack.
*/
if (p->p_stat == SZOMB ||
- kvm_uread(kd, p, USRSTACK - sizeof(arginfo) - SPARE_USRSPACE,
- (char *)&arginfo, sizeof(arginfo)) != sizeof(arginfo))
+ kvm_uread(kd, p, USRSTACK - sizeof(arginfo), (char *)&arginfo,
+ sizeof(arginfo)) != sizeof(arginfo))
return (0);
(*info)(&arginfo, &addr, &cnt);
+ if (cnt == 0)
+ return (0);
ap = kvm_argv(kd, p, addr, cnt, nchr);
/*
* For live kernels, make sure this process didn't go away.