1) UCB code to scroll portion of screen with al/dl works only for fullscreen
[unix-history] / lib / libutil / kvm.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
15637ed4
RG
33 */
34
35#if defined(LIBC_SCCS) && !defined(lint)
36static char sccsid[] = "@(#)kvm.c 5.18 (Berkeley) 5/7/91";
37#endif /* LIBC_SCCS and not lint */
38
8387d405 39#define DEBUG 0
15637ed4
RG
40
41#include <sys/param.h>
42#include <sys/user.h>
43#include <sys/proc.h>
44#include <sys/ioctl.h>
45#include <sys/kinfo.h>
46#include <sys/tty.h>
8387d405
DG
47#include <sys/file.h>
48#include <sys/types.h>
15637ed4
RG
49#include <machine/vmparam.h>
50#include <fcntl.h>
51#include <nlist.h>
52#include <kvm.h>
53#include <ndbm.h>
54#include <limits.h>
55#include <paths.h>
56#include <stdio.h>
57#include <string.h>
8387d405 58#include <sys/mman.h>
15637ed4 59
15637ed4
RG
60#define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */
61#define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */
62#include <vm/vm.h> /* ??? kinfo_proc currently includes this*/
63#include <vm/vm_page.h>
64#include <vm/swap_pager.h>
65#include <sys/kinfo_proc.h>
15637ed4
RG
66
67/*
68 * files
69 */
70static const char *unixf, *memf, *kmemf, *swapf;
71static int unixx, mem, kmem, swap;
72static DBM *db;
73/*
74 * flags
75 */
76static int deadkernel;
77static int kvminit = 0;
78static int kvmfilesopen = 0;
79/*
80 * state
81 */
82static struct kinfo_proc *kvmprocbase, *kvmprocptr;
83static int kvmnprocs;
84/*
85 * u. buffer
86 */
87static union {
88 struct user user;
89 char upages[UPAGES][NBPG];
90} user;
91
15637ed4
RG
92struct swapblk {
93 long offset; /* offset in swap device */
94 long size; /* remaining size of block in swap device */
95};
15637ed4
RG
96/*
97 * random other stuff
98 */
15637ed4
RG
99static int dmmin, dmmax;
100static int pcbpf;
101static int argaddr0; /* XXX */
102static int argaddr1;
103static int swaddr;
104static int nswap;
105static char *tmp;
15637ed4 106static struct pde *PTD;
15637ed4
RG
107
108#define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp))
109#define MAXSYMSIZE 256
110
15637ed4
RG
111#ifndef pftoc
112#define pftoc(f) (f)
113#endif
114#ifndef iskva
115#define iskva(v) ((u_long)(v) & KERNBASE)
116#endif
117
118static struct nlist nl[] = {
119 { "_Usrptmap" },
120#define X_USRPTMAP 0
121 { "_usrpt" },
122#define X_USRPT 1
123 { "_nswap" },
124#define X_NSWAP 2
125 { "_dmmin" },
126#define X_DMMIN 3
127 { "_dmmax" },
128#define X_DMMAX 4
129 { "_vm_page_buckets" },
130#define X_VM_PAGE_BUCKETS 5
131 { "_vm_page_hash_mask" },
132#define X_VM_PAGE_HASH_MASK 6
133 { "_page_shift" },
134#define X_PAGE_SHIFT 7
8387d405
DG
135 { "_kstack" },
136#define X_KSTACK 8
137 { "_kernel_object" },
138#define X_KERNEL_OBJECT 9
139 { "_btext",},
140#define X_KERNEL_BTEXT 10
15637ed4
RG
141 /*
142 * everything here and down, only if a dead kernel
143 */
144 { "_Sysmap" },
8387d405 145#define X_SYSMAP 11
15637ed4
RG
146#define X_DEADKERNEL X_SYSMAP
147 { "_Syssize" },
8387d405 148#define X_SYSSIZE 12
15637ed4 149 { "_allproc" },
8387d405 150#define X_ALLPROC 13
15637ed4 151 { "_zombproc" },
8387d405 152#define X_ZOMBPROC 14
15637ed4 153 { "_nproc" },
8387d405
DG
154#define X_NPROC 15
155#define X_LAST 15
15637ed4
RG
156 { "_IdlePTD" },
157#define X_IdlePTD (X_LAST+1)
15637ed4
RG
158 { "" },
159};
160
62f52313
DG
161static off_t Vtophys();
162static void klseek(), seterr(), setsyserr(), vstodb();
15637ed4 163static int getkvars(), kvm_doprocs(), kvm_init();
62f52313 164static int findpage();
15637ed4
RG
165
166/*
167 * returns 0 if files were opened now,
168 * 1 if files were already opened,
169 * -1 if files could not be opened.
170 */
171kvm_openfiles(uf, mf, sf)
172 const char *uf, *mf, *sf;
173{
174 if (kvmfilesopen)
175 return (1);
176 unixx = mem = kmem = swap = -1;
177 unixf = (uf == NULL) ? _PATH_UNIX : uf;
178 memf = (mf == NULL) ? _PATH_MEM : mf;
179
180 if ((unixx = open(unixf, O_RDONLY, 0)) == -1) {
181 setsyserr("can't open %s", unixf);
182 goto failed;
183 }
184 if ((mem = open(memf, O_RDONLY, 0)) == -1) {
185 setsyserr("can't open %s", memf);
186 goto failed;
187 }
188 if (sf != NULL)
189 swapf = sf;
190 if (mf != NULL) {
191 deadkernel++;
192 kmemf = mf;
193 kmem = mem;
194 swap = -1;
195 } else {
196 kmemf = _PATH_KMEM;
197 if ((kmem = open(kmemf, O_RDONLY, 0)) == -1) {
198 setsyserr("can't open %s", kmemf);
199 goto failed;
200 }
201 swapf = (sf == NULL) ? _PATH_DRUM : sf;
202 /*
203 * live kernel - avoid looking up nlist entries
204 * past X_DEADKERNEL.
205 */
206 nl[X_DEADKERNEL].n_name = "";
207 }
208 if (swapf != NULL && ((swap = open(swapf, O_RDONLY, 0)) == -1)) {
209 seterr("can't open %s", swapf);
210 goto failed;
211 }
212 kvmfilesopen++;
213 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) /*XXX*/
214 return (-1);
215 return (0);
216failed:
217 kvm_close();
218 return (-1);
219}
220
221static
222kvm_init(uf, mf, sf)
223 char *uf, *mf, *sf;
224{
225 if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
226 return (-1);
227 if (getkvars() == -1)
228 return (-1);
229 kvminit = 1;
230
231 return (0);
232}
233
234kvm_close()
235{
236 if (unixx != -1) {
237 close(unixx);
238 unixx = -1;
239 }
240 if (kmem != -1) {
241 if (kmem != mem)
242 close(kmem);
243 /* otherwise kmem is a copy of mem, and will be closed below */
244 kmem = -1;
245 }
246 if (mem != -1) {
247 close(mem);
248 mem = -1;
249 }
250 if (swap != -1) {
251 close(swap);
252 swap = -1;
253 }
254 if (db != NULL) {
255 dbm_close(db);
256 db = NULL;
257 }
258 kvminit = 0;
259 kvmfilesopen = 0;
260 deadkernel = 0;
15637ed4
RG
261}
262
263kvm_nlist(nl)
264 struct nlist *nl;
265{
266 datum key, data;
267 char dbname[MAXPATHLEN];
268 char dbversion[_POSIX2_LINE_MAX];
269 char kversion[_POSIX2_LINE_MAX];
270 int dbversionlen;
271 char symbuf[MAXSYMSIZE];
272 struct nlist nbuf, *n;
273 int num, did;
274
275 if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
276 return (-1);
277 if (deadkernel)
278 goto hard2;
279 /*
280 * initialize key datum
281 */
282 key.dptr = symbuf;
283
284 if (db != NULL)
285 goto win; /* off to the races */
286 /*
287 * open database
288 */
289 sprintf(dbname, "%s/kvm_%s", _PATH_VARRUN, basename(unixf));
290 if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL)
291 goto hard2;
292 /*
293 * read version out of database
294 */
295 bcopy("VERSION", symbuf, sizeof ("VERSION")-1);
296 key.dsize = (sizeof ("VERSION") - 1);
297 data = dbm_fetch(db, key);
298 if (data.dptr == NULL)
299 goto hard1;
300 bcopy(data.dptr, dbversion, data.dsize);
301 dbversionlen = data.dsize;
302 /*
303 * read version string from kernel memory
304 */
305 bcopy("_version", symbuf, sizeof ("_version")-1);
306 key.dsize = (sizeof ("_version")-1);
307 data = dbm_fetch(db, key);
308 if (data.dptr == NULL)
309 goto hard1;
310 if (data.dsize != sizeof (struct nlist))
311 goto hard1;
312 bcopy(data.dptr, &nbuf, sizeof (struct nlist));
313 lseek(kmem, nbuf.n_value, 0);
314 if (read(kmem, kversion, dbversionlen) != dbversionlen)
315 goto hard1;
316 /*
317 * if they match, we win - otherwise do it the hard way
318 */
319 if (bcmp(dbversion, kversion, dbversionlen) != 0)
320 goto hard1;
321 /*
322 * getem from the database.
323 */
324win:
325 num = did = 0;
326 for (n = nl; n->n_name && n->n_name[0]; n++, num++) {
327 int len;
328 /*
329 * clear out fields from users buffer
330 */
331 n->n_type = 0;
332 n->n_other = 0;
333 n->n_desc = 0;
334 n->n_value = 0;
335 /*
336 * query db
337 */
338 if ((len = strlen(n->n_name)) > MAXSYMSIZE) {
339 seterr("symbol too large");
340 return (-1);
341 }
342 (void)strcpy(symbuf, n->n_name);
343 key.dsize = len;
344 data = dbm_fetch(db, key);
345 if (data.dptr == NULL || data.dsize != sizeof (struct nlist))
346 continue;
347 bcopy(data.dptr, &nbuf, sizeof (struct nlist));
348 n->n_value = nbuf.n_value;
349 n->n_type = nbuf.n_type;
350 n->n_desc = nbuf.n_desc;
351 n->n_other = nbuf.n_other;
352 did++;
353 }
354 return (num - did);
355hard1:
356 dbm_close(db);
357 db = NULL;
358hard2:
359 num = nlist(unixf, nl);
360 if (num == -1)
361 seterr("nlist (hard way) failed");
362 return (num);
363}
364
365kvm_getprocs(what, arg)
366 int what, arg;
367{
368 static int ocopysize = -1;
369
370 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
371 return (NULL);
372 if (!deadkernel) {
373 int ret, copysize;
374
375 if ((ret = getkerninfo(what, NULL, NULL, arg)) == -1) {
376 setsyserr("can't get estimate for kerninfo");
377 return (-1);
378 }
379 copysize = ret;
20cc2df0
DG
380 if ((copysize > ocopysize ||
381 kvmprocbase == (struct kinfo_proc *) NULL) &&
170dc86a
DG
382 (kvmprocbase = (struct kinfo_proc *)
383 realloc(kvmprocbase, copysize)) == NULL) {
15637ed4
RG
384 seterr("out of memory");
385 return (-1);
386 }
387 ocopysize = copysize;
388 if ((ret = getkerninfo(what, kvmprocbase, &copysize,
389 arg)) == -1) {
390 setsyserr("can't get proc list");
391 return (-1);
392 }
393 if (copysize % sizeof (struct kinfo_proc)) {
394 seterr("proc size mismatch (got %d total, kinfo_proc: %d)",
395 copysize, sizeof (struct kinfo_proc));
396 return (-1);
397 }
398 kvmnprocs = copysize / sizeof (struct kinfo_proc);
399 } else {
400 int nproc;
401
402 if (kvm_read((void *) nl[X_NPROC].n_value, &nproc,
403 sizeof (int)) != sizeof (int)) {
404 seterr("can't read nproc");
405 return (-1);
406 }
407 if ((kvmprocbase = (struct kinfo_proc *)
408 malloc(nproc * sizeof (struct kinfo_proc))) == NULL) {
409 seterr("out of memory (addr: %x nproc = %d)",
410 nl[X_NPROC].n_value, nproc);
411 return (-1);
412 }
413 kvmnprocs = kvm_doprocs(what, arg, kvmprocbase);
414 realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc));
415 }
416 kvmprocptr = kvmprocbase;
417
418 return (kvmnprocs);
419}
420
421/*
422 * XXX - should NOT give up so easily - especially since the kernel
423 * may be corrupt (it died). Should gather as much information as possible.
424 * Follows proc ptrs instead of reading table since table may go
425 * away soon.
426 */
427static
428kvm_doprocs(what, arg, buff)
429 int what, arg;
430 char *buff;
431{
432 struct proc *p, proc;
433 register char *bp = buff;
434 int i = 0;
435 int doingzomb = 0;
436 struct eproc eproc;
437 struct pgrp pgrp;
438 struct session sess;
439 struct tty tty;
15637ed4
RG
440
441 /* allproc */
442 if (kvm_read((void *) nl[X_ALLPROC].n_value, &p,
443 sizeof (struct proc *)) != sizeof (struct proc *)) {
444 seterr("can't read allproc");
445 return (-1);
446 }
447
448again:
449 for (; p; p = proc.p_nxt) {
450 if (kvm_read(p, &proc, sizeof (struct proc)) !=
451 sizeof (struct proc)) {
452 seterr("can't read proc at %x", p);
453 return (-1);
454 }
15637ed4
RG
455 if (kvm_read(proc.p_cred, &eproc.e_pcred,
456 sizeof (struct pcred)) == sizeof (struct pcred))
457 (void) kvm_read(eproc.e_pcred.pc_ucred, &eproc.e_ucred,
458 sizeof (struct ucred));
459 switch(ki_op(what)) {
460
461 case KINFO_PROC_PID:
462 if (proc.p_pid != (pid_t)arg)
463 continue;
464 break;
465
466
467 case KINFO_PROC_UID:
468 if (eproc.e_ucred.cr_uid != (uid_t)arg)
469 continue;
470 break;
471
472 case KINFO_PROC_RUID:
473 if (eproc.e_pcred.p_ruid != (uid_t)arg)
474 continue;
475 break;
476 }
15637ed4
RG
477 /*
478 * gather eproc
479 */
480 eproc.e_paddr = p;
481 if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) !=
482 sizeof (struct pgrp)) {
483 seterr("can't read pgrp at %x", proc.p_pgrp);
484 return (-1);
485 }
486 eproc.e_sess = pgrp.pg_session;
487 eproc.e_pgid = pgrp.pg_id;
488 eproc.e_jobc = pgrp.pg_jobc;
489 if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session))
490 != sizeof (struct session)) {
491 seterr("can't read session at %x", pgrp.pg_session);
492 return (-1);
493 }
494 if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) {
495 if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty))
496 != sizeof (struct tty)) {
497 seterr("can't read tty at %x", sess.s_ttyp);
498 return (-1);
499 }
500 eproc.e_tdev = tty.t_dev;
501 eproc.e_tsess = tty.t_session;
502 if (tty.t_pgrp != NULL) {
503 if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct
504 pgrp)) != sizeof (struct pgrp)) {
505 seterr("can't read tpgrp at &x",
506 tty.t_pgrp);
507 return (-1);
508 }
509 eproc.e_tpgid = pgrp.pg_id;
510 } else
511 eproc.e_tpgid = -1;
512 } else
513 eproc.e_tdev = NODEV;
514 if (proc.p_wmesg)
515 kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN);
15637ed4
RG
516 (void) kvm_read(proc.p_vmspace, &eproc.e_vm,
517 sizeof (struct vmspace));
518 eproc.e_xsize = eproc.e_xrssize =
519 eproc.e_xccount = eproc.e_xswrss = 0;
15637ed4
RG
520
521 switch(ki_op(what)) {
522
523 case KINFO_PROC_PGRP:
524 if (eproc.e_pgid != (pid_t)arg)
525 continue;
526 break;
527
528 case KINFO_PROC_TTY:
529 if ((proc.p_flag&SCTTY) == 0 ||
530 eproc.e_tdev != (dev_t)arg)
531 continue;
532 break;
533 }
534
535 i++;
536 bcopy(&proc, bp, sizeof (struct proc));
537 bp += sizeof (struct proc);
538 bcopy(&eproc, bp, sizeof (struct eproc));
539 bp+= sizeof (struct eproc);
540 }
541 if (!doingzomb) {
542 /* zombproc */
543 if (kvm_read((void *) nl[X_ZOMBPROC].n_value, &p,
544 sizeof (struct proc *)) != sizeof (struct proc *)) {
545 seterr("can't read zombproc");
546 return (-1);
547 }
548 doingzomb = 1;
549 goto again;
550 }
551
552 return (i);
553}
554
555struct proc *
556kvm_nextproc()
557{
558
559 if (!kvmprocbase && kvm_getprocs(0, 0) == -1)
560 return (NULL);
561 if (kvmprocptr >= (kvmprocbase + kvmnprocs)) {
8387d405 562#if 0
15637ed4 563 seterr("end of proc list");
8387d405 564#endif
15637ed4
RG
565 return (NULL);
566 }
567 return((struct proc *)(kvmprocptr++));
568}
569
570struct eproc *
571kvm_geteproc(p)
572 const struct proc *p;
573{
574 return ((struct eproc *)(((char *)p) + sizeof (struct proc)));
575}
576
577kvm_setproc()
578{
579 kvmprocptr = kvmprocbase;
580}
581
582kvm_freeprocs()
583{
584
585 if (kvmprocbase) {
586 free(kvmprocbase);
587 kvmprocbase = NULL;
588 }
589}
590
8387d405
DG
591proc_getmem(const struct proc *p, void *buffer, vm_offset_t size, vm_offset_t offset) {
592 int fd;
593 char fn[512+1];
594 sprintf(fn,"/proc/%d",p->p_pid);
62f52313 595 if (p->p_flag & SSYS)
8387d405
DG
596 return 0;
597 fd = open(fn,O_RDONLY);
62f52313 598 if (fd == -1) {
8387d405
DG
599 return 0;
600 }
601
62f52313 602 if (lseek(fd, offset, 0) == -1) {
8387d405
DG
603 close(fd);
604 return 0;
605 }
62f52313 606 if (read(fd, buffer, size) <= 0) {
8387d405
DG
607 close(fd);
608 return 0;
609 }
610 close(fd);
611 return 1;
612}
15637ed4 613
15637ed4
RG
614struct user *
615kvm_getu(p)
616 const struct proc *p;
617{
618 register struct kinfo_proc *kp = (struct kinfo_proc *)p;
619 register int i;
620 register char *up;
621 u_int vaddr;
8387d405 622 int arg_size;
15637ed4
RG
623
624 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1)
625 return (NULL);
626 if (p->p_stat == SZOMB) {
627 seterr("zombie process");
628 return (NULL);
629 }
630
62f52313
DG
631 if (!deadkernel) {
632 if (proc_getmem(p, user.upages, sizeof user.upages, USRSTACK)) {
633 kp->kp_eproc.e_vm.vm_rssize =
634 kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */
635 return &user.user;
636 }
8387d405
DG
637 }
638
62f52313
DG
639 argaddr0 = argaddr1 = 0;
640 /*
641 * Read u-area one page at a time for the benefit of post-mortems
642 */
643 up = (char *) p->p_addr;
644 for (i = 0; i < UPAGES; i++) {
645 klseek(kmem, (long)up, 0);
646 if (read(kmem, user.upages[i], CLBYTES) != CLBYTES) {
647 seterr("cant read page %x of u of pid %d from %s",
648 up, p->p_pid, kmemf);
649 return(NULL);
650 }
651 up += CLBYTES;
652 }
653
654 pcbpf = (int) btop(p->p_addr); /* what should this be really? */
655 /*
656 * Conjure up a physical address for the arguments.
657 */
658 kp->kp_eproc.e_vm.vm_rssize =
659 kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */
660
661 vaddr = (u_int)kp->kp_eproc.e_vm.vm_minsaddr;
662 arg_size = USRSTACK - vaddr;
663
664 if (kp->kp_eproc.e_vm.vm_pmap.pm_pdir) {
665 struct pde pde;
666
667 klseek(kmem,
668 (long)(&kp->kp_eproc.e_vm.vm_pmap.pm_pdir[pdei(vaddr)]), 0);
669
670 if (read(kmem, (char *)&pde, sizeof pde) == sizeof pde
671 && pde.pd_v) {
672
673 struct pte pte;
674
675 if (lseek(mem, (long)ctob(pde.pd_pfnum) +
676 (ptei(vaddr) * sizeof pte), 0) == -1)
677 seterr("kvm_getu: lseek");
678 if (read(mem, (char *)&pte, sizeof pte) == sizeof pte) {
679 if (pte.pg_v) {
680 argaddr1 = (pte.pg_pfnum << PGSHIFT) |
681 ((u_long)vaddr & (NBPG-1));
682 }
683 } else {
684 seterr("kvm_getu: read");
685 }
686 }
687 }
688
689 return(&user.user);
15637ed4 690}
15637ed4
RG
691
692char *
693kvm_getargs(p, up)
694 const struct proc *p;
695 const struct user *up;
696{
8387d405
DG
697 int arg_size, arg_offset;
698 static char cmdbuf[ARG_MAX];
699 char argc[ARG_MAX*3];
700 int *argv;
15637ed4 701 register char *cp;
15637ed4
RG
702 char c;
703 int nbad;
8387d405
DG
704 char *cmdbufp;
705 vm_offset_t vaddr;
706 char procfile[16];
707 int mmfd;
708#if 0
709 char *argc = NULL;
15637ed4 710#endif
15637ed4 711
8387d405
DG
712 *cmdbuf = 0;
713
714 vaddr = (u_int)((struct kinfo_proc *)p)->kp_eproc.e_vm.vm_minsaddr;
715 arg_size = USRSTACK - vaddr;
716
717 if (arg_size >= 3*ARG_MAX)
718 goto bad;
719
720#if 0
721 sprintf(procfile, "/proc/%d", p->p_pid);
722 if ((mmfd = open(procfile, O_RDONLY, 0)) == -1) {
723printf("failed to open %s\n",procfile);
724 goto bad;
725 }
726
727 if ((argc = mmap(0, arg_size, PROT_READ, MAP_FILE, mmfd, vaddr))
728 == (char *)-1) {
729printf("failed to mmap %s error=%s\n", procfile, strerror(errno));
730 goto bad;
731 }
15637ed4 732#endif
8387d405 733
62f52313
DG
734 if (!proc_getmem(p, argc, arg_size, vaddr)) {
735 if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) {
736 goto bad;
737 } else {
738 lseek(mem, (long)argaddr1, 0);
739 if (read(mem, argc, arg_size) != arg_size)
740 goto bad;
741 }
742 }
15637ed4 743
8387d405
DG
744 argv = (int *)argc;
745
746 arg_offset = argv[0] - vaddr;
747 if (arg_offset >= 3*ARG_MAX)
748 goto bad;
749
15637ed4 750 nbad = 0;
15637ed4 751
8387d405
DG
752 cmdbufp = cmdbuf;
753 for (cp = &argc[arg_offset]; cp < &argc[arg_size]; cp++, cmdbufp++) {
754 c = *cmdbufp = *cp;
15637ed4 755 if (c == 0) { /* convert null between arguments to space */
8387d405 756 *cmdbufp = ' ';
15637ed4
RG
757 if (*(cp+1) == 0) break; /* if null argument follows then no more args */
758 }
759 else if (c < ' ' || c > 0176) {
760 if (++nbad >= 5*(0+1)) { /* eflg -> 0 XXX */ /* limit number of bad chars to 5 */
8387d405 761 *cmdbufp++ = '?';
15637ed4
RG
762 break;
763 }
8387d405 764 *cmdbufp = '?';
15637ed4
RG
765 }
766 else if (0 == 0 && c == '=') { /* eflg -> 0 XXX */
8387d405
DG
767 while (*--cmdbufp != ' ')
768 if (cmdbufp <= cmdbuf)
15637ed4
RG
769 break;
770 break;
771 }
772 }
8387d405
DG
773 *cmdbufp = 0;
774
775 while (*--cmdbufp == ' ')
776 *cmdbufp = 0;
777
778 if (cmdbuf[0] == '-' || cmdbuf[0] == '?' || cmdbuf[0] <= ' ') {
779bad:
15637ed4
RG
780 (void) strcat(cmdbuf, " (");
781 (void) strncat(cmdbuf, p->p_comm, sizeof(p->p_comm));
782 (void) strcat(cmdbuf, ")");
783 }
8387d405
DG
784#if 0
785 if (argc && argc != (char *)-1)
786 munmap(argc, arg_size);
787 if (mmfd && mmfd != -1)
788 close (mmfd);
789#endif
15637ed4
RG
790 return (cmdbuf);
791}
792
62f52313 793
15637ed4
RG
794static
795getkvars()
796{
797 if (kvm_nlist(nl) == -1)
798 return (-1);
62f52313
DG
799 if (deadkernel) {
800 /* We must do the sys map first because klseek uses it */
801 long addr;
802
803 PTD = (struct pde *) malloc(NBPG);
804 if (PTD == NULL) {
805 seterr("out of space for PTD");
806 return (-1);
807 }
808 addr = (long) nl[X_IdlePTD].n_value;
809 (void) lseek(kmem, addr, 0);
810 read(kmem, (char *)&addr, sizeof(addr));
811 (void) lseek(kmem, (long)addr, 0);
812 if (read(kmem, (char *) PTD, NBPG) != NBPG) {
813 seterr("can't read PTD");
814 return (-1);
815 }
816 }
15637ed4
RG
817 if (kvm_read((void *) nl[X_NSWAP].n_value, &nswap, sizeof (long)) !=
818 sizeof (long)) {
819 seterr("can't read nswap");
820 return (-1);
821 }
822 if (kvm_read((void *) nl[X_DMMIN].n_value, &dmmin, sizeof (long)) !=
823 sizeof (long)) {
824 seterr("can't read dmmin");
825 return (-1);
826 }
827 if (kvm_read((void *) nl[X_DMMAX].n_value, &dmmax, sizeof (long)) !=
828 sizeof (long)) {
829 seterr("can't read dmmax");
830 return (-1);
831 }
832 return (0);
833}
834
835kvm_read(loc, buf, len)
836 void *loc;
837 void *buf;
838{
839 if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1)
840 return (-1);
841 if (iskva(loc)) {
62f52313 842 klseek(kmem, (off_t) loc, 0);
15637ed4
RG
843 if (read(kmem, buf, len) != len) {
844 seterr("error reading kmem at %x", loc);
845 return (-1);
846 }
847 } else {
848 lseek(mem, (off_t) loc, 0);
849 if (read(mem, buf, len) != len) {
850 seterr("error reading mem at %x", loc);
851 return (-1);
852 }
853 }
854 return (len);
855}
856
62f52313
DG
857static void
858klseek(fd, loc, off)
859 int fd;
860 off_t loc;
861 int off;
862{
863
864 if (deadkernel) {
865 if ((loc = Vtophys(loc)) == -1)
866 return;
867 }
868 (void) lseek(fd, (off_t)loc, off);
869}
870
871static off_t
872Vtophys(loc)
873 u_long loc;
874{
875 off_t newloc = (off_t) -1;
876 struct pde pde;
877 struct pte pte;
878 int p;
879
880 pde = PTD[loc >> PD_SHIFT];
881 if (pde.pd_v == 0) {
882 seterr("vtophys: page directory entry not valid");
883 return((off_t) -1);
884 }
885 p = btop(loc & PT_MASK);
886 newloc = pde.pd_pfnum + (p * sizeof(struct pte));
887 (void) lseek(kmem, (long)newloc, 0);
888 if (read(kmem, (char *)&pte, sizeof pte) != sizeof pte) {
889 seterr("vtophys: cannot obtain desired pte");
890 return((off_t) -1);
891 }
892 newloc = pte.pg_pfnum;
893 if (pte.pg_v == 0) {
894 seterr("vtophys: page table entry not valid");
895 return((off_t) -1);
896 }
897 newloc += (loc & PGOFSET);
898 return((off_t) newloc);
899}
900
901/*
902 * locate address of unwired or swapped page
903 */
904
905
906#define KREAD(off, addr, len) \
907 (kvm_read((void *)(off), (char *)(addr), (len)) == (len))
908
909#define atop(x) (((unsigned)(x)) >> page_shift)
910#define vm_page_hash(object, offset) \
911 (((unsigned)object+(unsigned)atop(offset))&vm_page_hash_mask)
912
913static int
914findpage(object, offset, maddr)
915long object;
916long offset;
917vm_offset_t *maddr;
918{
919static long vm_page_hash_mask;
920static long vm_page_buckets;
921static long page_shift;
922 queue_head_t bucket;
923 struct vm_page mem;
924 long addr, baddr;
925
926 if (vm_page_hash_mask == 0 && !KREAD(nl[X_VM_PAGE_HASH_MASK].n_value,
927 &vm_page_hash_mask, sizeof (long))) {
928 seterr("can't read vm_page_hash_mask");
929 return 0;
930 }
931 if (page_shift == 0 && !KREAD(nl[X_PAGE_SHIFT].n_value,
932 &page_shift, sizeof (long))) {
933 seterr("can't read page_shift");
934 return 0;
935 }
936 if (vm_page_buckets == 0 && !KREAD(nl[X_VM_PAGE_BUCKETS].n_value,
937 &vm_page_buckets, sizeof (long))) {
938 seterr("can't read vm_page_buckets");
939 return 0;
940 }
941
942 baddr = vm_page_buckets + vm_page_hash(object,offset) * sizeof(queue_head_t);
943 if (!KREAD(baddr, &bucket, sizeof (bucket))) {
944 seterr("can't read vm_page_bucket");
945 return 0;
946 }
947
948 addr = (long)bucket.next;
949 while (addr != baddr) {
950 if (!KREAD(addr, &mem, sizeof (mem))) {
951 seterr("can't read vm_page");
952 return 0;
953 }
954 if ((long)mem.object == object && mem.offset == offset) {
955 *maddr = (long)mem.phys_addr;
956 return 1;
957 }
958 addr = (long)mem.hashq.next;
959 }
960 return 0;
961}
962
15637ed4
RG
963#include <varargs.h>
964static char errbuf[_POSIX2_LINE_MAX];
965
966static void
967seterr(va_alist)
968 va_dcl
969{
970 char *fmt;
971 va_list ap;
972
973 va_start(ap);
974 fmt = va_arg(ap, char *);
975 (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap);
976#if DEBUG
977 (void) vfprintf(stderr, fmt, ap);
978#endif
979 va_end(ap);
980}
981
982static void
983setsyserr(va_alist)
984 va_dcl
985{
986 char *fmt, *cp;
987 va_list ap;
988 extern int errno;
989
990 va_start(ap);
991 fmt = va_arg(ap, char *);
992 (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap);
993 for (cp=errbuf; *cp; cp++)
994 ;
995 snprintf(cp, _POSIX2_LINE_MAX - (cp - errbuf), ": %s", strerror(errno));
8387d405
DG
996#if DEBUG
997 (void) fprintf(stderr, "%s\n", errbuf);
998#endif
15637ed4
RG
999 va_end(ap);
1000}
1001
1002char *
1003kvm_geterr()
1004{
1005 return (errbuf);
1006}