diff options
| author | Peter Wemm <peter@FreeBSD.org> | 1996-02-22 19:25:43 +0000 |
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 1996-02-22 19:25:43 +0000 |
| commit | 31cdc03245ac76d861b4aa811bbdd70ac29a2ff3 (patch) | |
| tree | 343ec2b8c52fce9d442531d42238d2dc8b7401d9 | |
| parent | 059f274907c4a88ad8e31791698683c75e1134c8 (diff) | |
Notes
| -rw-r--r-- | lib/libkvm/kvm_private.h | 1 | ||||
| -rw-r--r-- | lib/libkvm/kvm_proc.c | 146 |
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. |
