Commit | Line | Data |
---|---|---|
41a4fbbe MT |
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 is permitted | |
6 | * provided that all copyright information, including this notice, | |
7 | * is retained in all such forms, and that any documentation, | |
8 | * advertising or other materials related to such distribution and | |
9 | * use acknowledge that the software was | |
10 | * developed by the University of California, Berkeley. The name | |
11 | * of the University may not be used to endorse or promote products | |
12 | * derived from this software without specific prior written permission. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
17 | */ | |
18 | ||
19 | ||
20 | #include <machine/pte.h> | |
21 | #include <sys/param.h> | |
22 | #include <sys/user.h> | |
23 | #include <sys/proc.h> | |
24 | #include <sys/file.h> | |
25 | #include <sys/text.h> | |
26 | #include <sys/stat.h> | |
27 | #include <sys/time.h> | |
28 | #include <sys/vmmac.h> | |
29 | #include <sys/ioctl.h> | |
30 | #include <sys/tty.h> | |
0e005c87 | 31 | #include <kvm.h> |
41a4fbbe | 32 | #include <ctype.h> |
0e005c87 | 33 | #include <cencode.h> |
41a4fbbe MT |
34 | #include <nlist.h> |
35 | #include <pwd.h> | |
36 | #include <strings.h> | |
37 | #include <ndbm.h> | |
38 | #include <limits.h> | |
39 | #include <paths.h> | |
0e005c87 | 40 | #include <stdio.h> |
41a4fbbe MT |
41 | |
42 | /* | |
43 | * files | |
44 | */ | |
45 | static char *unixf, *memf, *kmemf, *swapf; | |
46 | static int unixx, mem, kmem, swap; | |
0e005c87 | 47 | static DBM *db; |
41a4fbbe MT |
48 | /* |
49 | * flags | |
50 | */ | |
51 | static int deadkernel; | |
52 | static int kvminit = 0; | |
53 | static int kvmfilesopen = 0; | |
54 | /* | |
55 | * state | |
56 | */ | |
57 | static struct kinfo_proc *kvmprocbase, *kvmprocptr; | |
58 | static int kvmnprocs; | |
41a4fbbe MT |
59 | /* |
60 | * u. buffer | |
61 | */ | |
62 | static union { | |
63 | struct user user; | |
64 | char upages[UPAGES][NBPG]; | |
65 | } user; | |
66 | /* | |
67 | * random other stuff | |
68 | */ | |
69 | static struct pte *Usrptmap, *usrpt; | |
70 | static int dmmin, dmmax; | |
71 | static struct pte *Sysmap; | |
72 | static int Syssize; | |
73 | static int pcbpf; | |
0e005c87 MT |
74 | static int argaddr0; /* XXX */ |
75 | static int argaddr1; | |
41a4fbbe | 76 | static int nswap; |
0e005c87 | 77 | static char *tmp; |
41a4fbbe | 78 | |
0e005c87 | 79 | #define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp)) |
41a4fbbe | 80 | #define MAXSYMSIZE 256 |
41a4fbbe MT |
81 | |
82 | static struct nlist nl[] = { | |
83 | { "_Usrptmap" }, | |
84 | #define X_USRPTMAP 0 | |
85 | { "_usrpt" }, | |
86 | #define X_USRPT 1 | |
87 | { "_nswap" }, | |
88 | #define X_NSWAP 2 | |
89 | { "_dmmin" }, | |
90 | #define X_DMMIN 3 | |
91 | { "_dmmax" }, | |
92 | #define X_DMMAX 4 | |
93 | /* | |
94 | * everything here and down, only if a dead kernel | |
95 | */ | |
96 | { "_Sysmap" }, | |
97 | #define X_SYSMAP 5 | |
98 | #define X_DEADKERNEL X_SYSMAP | |
99 | { "_Syssize" }, | |
100 | #define X_SYSSIZE 6 | |
101 | { "_allproc" }, | |
102 | #define X_ALLPROC 7 | |
103 | { "_zombproc" }, | |
104 | #define X_ZOMBPROC 8 | |
105 | { "_nproc" }, | |
106 | #define X_NPROC 9 | |
107 | { "" }, | |
108 | }; | |
109 | ||
110 | static char *savestr(); | |
111 | ||
0e005c87 MT |
112 | /* |
113 | * returns 0 if files were opened now, | |
114 | * 1 if files were already opened, | |
115 | * -1 if files could not be opened. | |
116 | */ | |
41a4fbbe | 117 | kvm_openfiles(uf, mf, sf) |
0e005c87 MT |
118 | char *uf, *mf, *sf; |
119 | { | |
120 | if (kvmfilesopen) | |
121 | return (1); | |
41a4fbbe MT |
122 | unixx = mem = kmem = swap = -1; |
123 | unixf = (uf == NULL) ? _PATH_UNIX : uf; | |
124 | memf = (mf == NULL) ? _PATH_MEM : mf; | |
125 | ||
126 | if ((unixx = open(unixf, O_RDONLY, 0)) == -1) { | |
127 | setsyserr("can't open %s", unixf); | |
128 | goto failed; | |
129 | } | |
130 | if ((mem = open(memf, O_RDONLY, 0)) == -1) { | |
131 | setsyserr("can't open %s", memf); | |
132 | goto failed; | |
133 | } | |
134 | if (sf != NULL) | |
135 | swapf = sf; | |
136 | if (mf != NULL) { | |
137 | deadkernel++; | |
138 | kmemf = mf; | |
139 | kmem = mem; | |
140 | swap = -1; | |
141 | } else { | |
142 | kmemf = _PATH_KMEM; | |
143 | if ((kmem = open(kmemf, O_RDONLY, 0)) == -1) { | |
144 | setsyserr("can't open %s", kmemf); | |
145 | goto failed; | |
146 | } | |
147 | swapf = (sf == NULL) ? _PATH_DRUM : sf; | |
148 | /* | |
149 | * live kernel - avoid looking up nlist entries | |
150 | * past X_DEADKERNEL. | |
151 | */ | |
152 | nl[X_DEADKERNEL].n_name = ""; | |
153 | } | |
154 | if (swapf != NULL && ((swap = open(swapf, O_RDONLY, 0)) == -1)) { | |
155 | seterr("can't open %s", swapf); | |
156 | goto failed; | |
157 | } | |
158 | kvmfilesopen++; | |
159 | return (0); | |
160 | failed: | |
161 | kvm_close(); | |
162 | return (-1); | |
163 | } | |
164 | ||
0e005c87 MT |
165 | static |
166 | kvm_init(uf, mf, sf) | |
167 | char *uf, *mf, *sf; | |
168 | { | |
169 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
170 | return (-1); | |
171 | if (getkvars() == -1) | |
172 | return (-1); | |
173 | kvminit = 1; | |
174 | ||
175 | return (0); | |
176 | } | |
177 | ||
41a4fbbe MT |
178 | kvm_close() |
179 | { | |
0e005c87 | 180 | if (unixx != -1) { |
41a4fbbe | 181 | close(unixx); |
0e005c87 MT |
182 | unixx = -1; |
183 | } | |
184 | if (kmem != -1) { | |
185 | if (kmem != mem) | |
186 | close(kmem); | |
187 | /* otherwise kmem is a copy of mem, and will be closed below */ | |
188 | kmem = -1; | |
189 | } | |
190 | if (mem != -1) { | |
41a4fbbe | 191 | close(mem); |
0e005c87 MT |
192 | mem = -1; |
193 | } | |
194 | if (swap != -1) { | |
41a4fbbe | 195 | close(swap); |
0e005c87 MT |
196 | swap = -1; |
197 | } | |
198 | if (db != NULL) { | |
41a4fbbe | 199 | dbm_close(db); |
0e005c87 MT |
200 | db = NULL; |
201 | } | |
41a4fbbe MT |
202 | kvminit = 0; |
203 | kvmfilesopen = 0; | |
0e005c87 MT |
204 | deadkernel = 0; |
205 | if (Sysmap) { | |
206 | free(Sysmap); | |
207 | Sysmap = NULL; | |
208 | } | |
41a4fbbe MT |
209 | } |
210 | ||
211 | kvm_nlist(nl) | |
212 | struct nlist *nl; | |
213 | { | |
214 | datum key, data; | |
215 | char dbname[MAXPATHLEN]; | |
216 | char dbversion[LINE_MAX]; | |
217 | char kversion[LINE_MAX]; | |
218 | int dbversionlen; | |
219 | char symbuf[MAXSYMSIZE+1]; | |
220 | struct nlist nbuf, *n; | |
221 | int num, did; | |
222 | ||
223 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
224 | return (-1); | |
225 | if (deadkernel) | |
226 | goto hard2; | |
41a4fbbe | 227 | /* |
0e005c87 | 228 | * initialize key datum |
41a4fbbe MT |
229 | */ |
230 | key.dptr = symbuf; | |
231 | symbuf[0] = KVMDB_NLIST; | |
0e005c87 MT |
232 | |
233 | if (db != NULL) | |
234 | goto win; /* off to the races */ | |
41a4fbbe | 235 | /* |
0e005c87 MT |
236 | * open database |
237 | */ | |
238 | sprintf(dbname, "%s/kvm_%s", KVMDBDIR, basename(unixf)); | |
239 | if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL) | |
240 | goto hard2; | |
241 | /* | |
242 | * read version out of database | |
41a4fbbe MT |
243 | */ |
244 | bcopy("VERSION", symbuf+1, sizeof ("VERSION")-1); | |
245 | key.dsize = (sizeof ("VERSION") - 1) + 1; | |
246 | data = dbm_fetch(db, key); | |
247 | if (data.dptr == NULL) | |
248 | goto hard1; | |
249 | bcopy(data.dptr, dbversion, data.dsize); | |
250 | dbversionlen = data.dsize; | |
251 | /* | |
252 | * read version string from kernel memory | |
253 | */ | |
254 | bcopy("_version", symbuf+1, sizeof ("_version")-1); | |
255 | key.dsize = (sizeof ("_version")-1) + 1; | |
256 | data = dbm_fetch(db, key); | |
257 | if (data.dptr == NULL) | |
258 | goto hard1; | |
259 | if (data.dsize != sizeof (struct nlist)) | |
260 | goto hard1; | |
261 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
262 | lseek(kmem, nbuf.n_value, 0); | |
263 | if (read(kmem, kversion, dbversionlen) != dbversionlen) | |
264 | goto hard1; | |
265 | /* | |
266 | * if they match, we win - otherwise do it the hard way | |
267 | */ | |
268 | if (bcmp(dbversion, kversion, dbversionlen) != 0) | |
269 | goto hard1; | |
270 | /* | |
271 | * getem from the database. | |
272 | */ | |
273 | win: | |
274 | num = did = 0; | |
275 | for (n = nl; n->n_name && n->n_name[0]; n++, num++) { | |
276 | int len; | |
277 | /* | |
0e005c87 | 278 | * clear out fields from users buffer |
41a4fbbe MT |
279 | */ |
280 | n->n_type = 0; | |
281 | n->n_other = 0; | |
282 | n->n_desc = 0; | |
283 | n->n_value = 0; | |
284 | /* | |
285 | * query db | |
286 | */ | |
287 | if ((len = strlen(n->n_name)) > MAXSYMSIZE) { | |
288 | seterr("kvm_nlist: symbol too large"); | |
289 | return (-1); | |
290 | } | |
291 | strcpy(symbuf+1, n->n_name); | |
292 | key.dsize = len + 1; | |
293 | data = dbm_fetch(db, key); | |
294 | if (data.dptr == NULL || data.dsize != sizeof (struct nlist)) | |
295 | continue; | |
296 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
297 | n->n_value = nbuf.n_value; | |
298 | n->n_type = nbuf.n_type; | |
299 | n->n_desc = nbuf.n_desc; | |
300 | n->n_other = nbuf.n_other; | |
301 | did++; | |
302 | } | |
303 | return (num - did); | |
304 | hard1: | |
305 | dbm_close(db); | |
306 | db = NULL; | |
307 | hard2: | |
0e005c87 | 308 | return (nlist(unixf, nl)); /* XXX seterr if -1 */ |
41a4fbbe MT |
309 | } |
310 | ||
311 | kvm_getprocs(what, arg) | |
312 | { | |
0e005c87 MT |
313 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) |
314 | return (NULL); | |
41a4fbbe MT |
315 | if (!deadkernel) { |
316 | int ret, copysize; | |
317 | ||
318 | if ((ret = getkerninfo(what, NULL, NULL, arg)) == -1) { | |
319 | setsyserr("can't get estimate for kerninfo"); | |
320 | return (-1); | |
321 | } | |
322 | copysize = ret; | |
323 | if ((kvmprocbase = (struct kinfo_proc *)malloc(copysize)) | |
324 | == NULL) { | |
325 | seterr("out of memory"); | |
326 | return (-1); | |
327 | } | |
328 | if ((ret = getkerninfo(what, kvmprocbase, ©size, | |
329 | arg)) == -1) { | |
330 | setsyserr("can't get proc list"); | |
331 | return (-1); | |
332 | } | |
333 | if (copysize % sizeof (struct kinfo_proc)) { | |
3ba498c1 MT |
334 | seterr("proc size mismatch (kinfo_proc: %d)", |
335 | sizeof (struct kinfo_proc)); | |
41a4fbbe MT |
336 | return (-1); |
337 | } | |
338 | kvmnprocs = copysize / sizeof (struct kinfo_proc); | |
339 | } else { | |
41a4fbbe MT |
340 | int nproc; |
341 | ||
342 | if (kvm_read(nl[X_NPROC].n_value, &nproc, sizeof (int)) != | |
343 | sizeof (int)) { | |
344 | seterr("can't read nproc"); | |
345 | return (-1); | |
346 | } | |
347 | if ((kvmprocbase = (struct kinfo_proc *) | |
348 | malloc(nproc * sizeof (struct kinfo_proc))) == NULL) { | |
0e005c87 MT |
349 | seterr("out of memory (addr: %x nproc = %d)", |
350 | nl[X_NPROC].n_value, nproc); | |
41a4fbbe MT |
351 | return (-1); |
352 | } | |
353 | kvmnprocs = kvm_doprocs(what, arg, kvmprocbase); | |
354 | realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc)); | |
355 | } | |
356 | kvmprocptr = kvmprocbase; | |
357 | ||
358 | return (kvmnprocs); | |
359 | } | |
360 | ||
361 | /* | |
362 | * XXX - should NOT give up so easily - especially since the kernel | |
363 | * may be corrupt (it died). Should gather as much information as possible. | |
364 | * Follows proc ptrs instead of reading table since table may go | |
365 | * away soon. | |
366 | */ | |
367 | static | |
368 | kvm_doprocs(what, arg, buff) | |
369 | int what, arg; | |
370 | char *buff; | |
371 | { | |
372 | struct proc *p, proc; | |
373 | register char *bp = buff; | |
374 | int i = 0; | |
375 | int doingzomb = 0; | |
376 | struct eproc eproc; | |
377 | struct pgrp pgrp; | |
378 | struct session sess; | |
379 | struct tty tty; | |
380 | struct text text; | |
381 | ||
382 | /* allproc */ | |
383 | if (kvm_read(nl[X_ALLPROC].n_value, &p, | |
384 | sizeof (struct proc *)) != sizeof (struct proc *)) { | |
385 | seterr("can't read allproc"); | |
386 | return (-1); | |
387 | } | |
388 | ||
389 | again: | |
390 | for (; p; p = proc.p_nxt) { | |
391 | if (kvm_read(p, &proc, sizeof (struct proc)) != | |
392 | sizeof (struct proc)) { | |
393 | seterr("can't read proc at %x", p); | |
394 | return (-1); | |
395 | } | |
396 | switch(ki_op(what)) { | |
397 | ||
398 | case KINFO_PROC_PID: | |
399 | if (proc.p_pid != (pid_t)arg) | |
400 | continue; | |
401 | break; | |
402 | ||
403 | ||
404 | case KINFO_PROC_UID: | |
405 | if (proc.p_uid != (uid_t)arg) | |
406 | continue; | |
407 | break; | |
408 | ||
409 | case KINFO_PROC_RUID: | |
410 | if (proc.p_ruid != (uid_t)arg) | |
411 | continue; | |
412 | break; | |
413 | } | |
414 | /* | |
415 | * gather eproc | |
416 | */ | |
417 | eproc.e_paddr = p; | |
418 | if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) != | |
419 | sizeof (struct pgrp)) { | |
420 | seterr("can't read pgrp at %x", proc.p_pgrp); | |
421 | return (-1); | |
422 | } | |
423 | eproc.e_sess = pgrp.pg_session; | |
424 | eproc.e_pgid = pgrp.pg_id; | |
425 | eproc.e_jobc = pgrp.pg_jobc; | |
426 | if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session)) | |
427 | != sizeof (struct session)) { | |
428 | seterr("can't read session at %x", pgrp.pg_session); | |
429 | return (-1); | |
430 | } | |
431 | if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) { | |
432 | if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty)) | |
433 | != sizeof (struct tty)) { | |
434 | seterr("can't read tty at %x", sess.s_ttyp); | |
435 | return (-1); | |
436 | } | |
437 | eproc.e_tdev = tty.t_dev; | |
438 | eproc.e_tsess = tty.t_session; | |
439 | if (tty.t_pgrp != NULL) { | |
440 | if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct | |
441 | pgrp)) != sizeof (struct pgrp)) { | |
442 | seterr("can't read tpgrp at &x", | |
443 | tty.t_pgrp); | |
444 | return (-1); | |
445 | } | |
446 | eproc.e_tpgid = pgrp.pg_id; | |
447 | } else | |
448 | eproc.e_tpgid = -1; | |
449 | } else | |
450 | eproc.e_tdev = NODEV; | |
451 | if (proc.p_wmesg) | |
452 | kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN); | |
453 | if (proc.p_textp) { | |
454 | kvm_read(proc.p_textp, &text, sizeof (text)); | |
455 | eproc.e_xsize = text.x_size; | |
456 | eproc.e_xrssize = text.x_rssize; | |
457 | eproc.e_xccount = text.x_ccount; | |
458 | eproc.e_xswrss = text.x_swrss; | |
459 | } else { | |
460 | eproc.e_xsize = eproc.e_xrssize = | |
461 | eproc.e_xccount = eproc.e_xswrss = 0; | |
462 | } | |
463 | ||
464 | switch(ki_op(what)) { | |
465 | ||
466 | case KINFO_PROC_PGRP: | |
467 | if (eproc.e_pgid != (pid_t)arg) | |
468 | continue; | |
469 | break; | |
470 | ||
471 | case KINFO_PROC_TTY: | |
472 | if ((proc.p_flag&SCTTY) == 0 || | |
473 | eproc.e_tdev != (dev_t)arg) | |
474 | continue; | |
475 | break; | |
476 | } | |
477 | ||
478 | i++; | |
479 | bcopy(&proc, bp, sizeof (struct proc)); | |
480 | bp += sizeof (struct proc); | |
481 | bcopy(&eproc, bp, sizeof (struct eproc)); | |
482 | bp+= sizeof (struct eproc); | |
483 | } | |
484 | if (!doingzomb) { | |
485 | /* zombproc */ | |
486 | if (kvm_read(nl[X_ZOMBPROC].n_value, &p, | |
487 | sizeof (struct proc *)) != sizeof (struct proc *)) { | |
488 | seterr("can't read zombproc"); | |
489 | return (-1); | |
490 | } | |
491 | doingzomb = 1; | |
492 | goto again; | |
493 | } | |
494 | ||
495 | return (i); | |
496 | } | |
497 | ||
498 | ||
499 | struct proc * | |
500 | kvm_nextproc() | |
501 | { | |
502 | ||
503 | if (!kvmprocbase && kvm_getprocs(0, 0) == -1) | |
504 | return (NULL); | |
505 | if (kvmprocptr >= (kvmprocbase + kvmnprocs)) { | |
506 | seterr("end of proc list"); | |
507 | return (NULL); | |
508 | } | |
509 | return((struct proc *)(kvmprocptr++)); | |
510 | } | |
511 | ||
512 | struct eproc * | |
513 | kvm_geteproc(p) | |
514 | struct proc *p; | |
515 | { | |
516 | return ((struct eproc *)(((char *)p) + sizeof (struct proc))); | |
517 | } | |
518 | ||
519 | kvm_setproc() | |
520 | { | |
521 | ||
522 | kvmprocptr = kvmprocbase; | |
523 | } | |
524 | ||
525 | kvm_freeprocs() | |
526 | { | |
527 | ||
528 | if (kvmprocbase) { | |
529 | free(kvmprocbase); | |
530 | kvmprocbase = NULL; | |
531 | } | |
532 | } | |
533 | ||
534 | struct user * | |
535 | kvm_getu(p) | |
536 | struct proc *p; | |
537 | { | |
538 | struct pte *pteaddr, apte; | |
0e005c87 | 539 | struct pte arguutl[UPAGES+(CLSIZE*2)]; |
41a4fbbe MT |
540 | register int i; |
541 | int ncl; | |
542 | ||
543 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) | |
544 | return (NULL); | |
0e005c87 MT |
545 | if (p->p_stat == SZOMB) { |
546 | seterr("zombie process"); | |
41a4fbbe | 547 | return (NULL); |
0e005c87 | 548 | } |
41a4fbbe | 549 | if ((p->p_flag & SLOAD) == 0) { |
0e005c87 MT |
550 | if (swap < 0) { |
551 | seterr("no swap"); | |
41a4fbbe | 552 | return (NULL); |
0e005c87 | 553 | } |
41a4fbbe MT |
554 | (void) lseek(swap, (long)dtob(p->p_swaddr), 0); |
555 | if (read(swap, (char *)&user.user, sizeof (struct user)) != | |
556 | sizeof (struct user)) { | |
557 | seterr("can't read u for pid %d from %s\n", | |
558 | p->p_pid, swapf); | |
559 | return (NULL); | |
560 | } | |
561 | pcbpf = 0; | |
0e005c87 MT |
562 | argaddr0 = 0; |
563 | argaddr1 = 0; | |
41a4fbbe MT |
564 | return (&user.user); |
565 | } | |
566 | pteaddr = &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1]; | |
567 | klseek(kmem, (long)pteaddr, 0); | |
568 | if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { | |
569 | seterr("can't read indir pte to get u for pid %d from %s", | |
570 | p->p_pid, kmemf); | |
571 | return (NULL); | |
572 | } | |
573 | lseek(mem, | |
0e005c87 | 574 | (long)ctob(apte.pg_pfnum+1) - (UPAGES+(CLSIZE*2)) * sizeof (struct pte), |
41a4fbbe MT |
575 | 0); |
576 | if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) { | |
577 | seterr("can't read page table for u of pid %d from %s", | |
578 | p->p_pid, memf); | |
579 | return (NULL); | |
580 | } | |
581 | if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum) | |
0e005c87 | 582 | argaddr0 = ctob(arguutl[0].pg_pfnum); |
41a4fbbe | 583 | else |
0e005c87 MT |
584 | argaddr0 = 0; |
585 | if (arguutl[CLSIZE*1].pg_fod == 0 && arguutl[CLSIZE*1].pg_pfnum) | |
586 | argaddr1 = ctob(arguutl[CLSIZE*1].pg_pfnum); | |
587 | else | |
588 | argaddr1 = 0; | |
589 | pcbpf = arguutl[CLSIZE*2].pg_pfnum; | |
41a4fbbe MT |
590 | ncl = (sizeof (struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); |
591 | while (--ncl >= 0) { | |
592 | i = ncl * CLSIZE; | |
0e005c87 | 593 | lseek(mem, (long)ctob(arguutl[(CLSIZE*2)+i].pg_pfnum), 0); |
41a4fbbe MT |
594 | if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) { |
595 | seterr("can't read page %d of u of pid %d from %s", | |
596 | arguutl[CLSIZE+i].pg_pfnum, p->p_pid, memf); | |
597 | return(NULL); | |
598 | } | |
599 | } | |
600 | return (&user.user); | |
601 | } | |
602 | ||
603 | char * | |
604 | kvm_getargs(p, up) | |
605 | struct proc *p; | |
606 | struct user *up; | |
607 | { | |
0e005c87 | 608 | char cmdbuf[CLSIZE*NBPG*2]; |
41a4fbbe | 609 | union { |
0e005c87 MT |
610 | char argc[CLSIZE*NBPG*2]; |
611 | int argi[CLSIZE*NBPG*2/sizeof (int)]; | |
41a4fbbe MT |
612 | } argspac; |
613 | register char *cp; | |
614 | register int *ip; | |
615 | char c; | |
616 | int nbad; | |
617 | struct dblock db; | |
618 | char *file; | |
619 | ||
0e005c87 | 620 | if (up == NULL || p->p_pid == 0 || p->p_pid == 2) |
41a4fbbe | 621 | goto retucomm; |
0e005c87 | 622 | if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) { |
41a4fbbe MT |
623 | if (swap < 0) |
624 | goto retucomm; | |
625 | vstodb(0, CLSIZE, &up->u_smap, &db, 1); | |
626 | (void) lseek(swap, (long)dtob(db.db_base), 0); | |
0e005c87 MT |
627 | if (read(swap, (char *)&argspac.argc[NBPG*CLSIZE], |
628 | NBPG*CLSIZE) != NBPG*CLSIZE) | |
629 | goto bad; | |
630 | vstodb(1, CLSIZE, &up->u_smap, &db, 1); | |
631 | (void) lseek(swap, (long)dtob(db.db_base), 0); | |
632 | if (read(swap, (char *)&argspac.argc[0], | |
633 | NBPG*CLSIZE) != NBPG*CLSIZE) | |
41a4fbbe MT |
634 | goto bad; |
635 | file = swapf; | |
636 | } else { | |
0e005c87 MT |
637 | if (argaddr0) { |
638 | lseek(mem, (long)argaddr0, 0); | |
639 | if (read(mem, (char *)&argspac, NBPG*CLSIZE) | |
640 | != NBPG*CLSIZE) | |
641 | goto bad; | |
642 | } else | |
643 | bzero(&argspac, NBPG*CLSIZE); | |
644 | lseek(mem, (long)argaddr1, 0); | |
645 | if (read(mem, &argspac.argc[NBPG*CLSIZE], NBPG*CLSIZE) | |
646 | != NBPG*CLSIZE) | |
41a4fbbe MT |
647 | goto bad; |
648 | file = memf; | |
649 | } | |
0e005c87 | 650 | ip = &argspac.argi[CLSIZE*NBPG*2/sizeof (int)]; |
41a4fbbe MT |
651 | ip -= 2; /* last arg word and .long 0 */ |
652 | while (*--ip) { | |
653 | if (ip == argspac.argi) | |
654 | goto retucomm; | |
655 | } | |
656 | *(char *)ip = ' '; | |
657 | ip++; | |
658 | nbad = 0; | |
0e005c87 | 659 | for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG*2]; cp++) { |
41a4fbbe MT |
660 | c = *cp & 0177; |
661 | if (c == 0) | |
662 | *cp = ' '; | |
663 | else if (c < ' ' || c > 0176) { | |
664 | if (++nbad >= 5*(0+1)) { /* eflg -> 0 XXX */ | |
665 | *cp++ = ' '; | |
666 | break; | |
667 | } | |
668 | *cp = '?'; | |
669 | } else if (0 == 0 && c == '=') { /* eflg -> 0 XXX */ | |
670 | while (*--cp != ' ') | |
671 | if (cp <= (char *)ip) | |
672 | break; | |
673 | break; | |
674 | } | |
675 | } | |
676 | *cp = 0; | |
677 | while (*--cp == ' ') | |
678 | *cp = 0; | |
679 | cp = (char *)ip; | |
0e005c87 | 680 | (void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG*2] - cp); |
41a4fbbe MT |
681 | if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') { |
682 | (void) strcat(cmdbuf, " ("); | |
683 | (void) strncat(cmdbuf, p->p_comm, sizeof(p->p_comm)); | |
684 | (void) strcat(cmdbuf, ")"); | |
685 | } | |
686 | return (cmdbuf); | |
687 | ||
688 | bad: | |
689 | seterr("error locating command name for pid %d from %s\n", | |
690 | p->p_pid, file); | |
691 | retucomm: | |
692 | (void) strcpy(cmdbuf, " ("); | |
693 | (void) strncat(cmdbuf, p->p_comm, sizeof (p->p_comm)); | |
694 | (void) strcat(cmdbuf, ")"); | |
695 | return (cmdbuf); | |
696 | } | |
697 | ||
698 | ||
699 | static | |
700 | getkvars() | |
701 | { | |
702 | ||
703 | if (kvm_nlist(nl) == -1) | |
704 | return (-1); | |
705 | if (deadkernel) { | |
706 | /* We must do the sys map first because klseek uses it */ | |
707 | long addr; | |
708 | ||
709 | Syssize = nl[X_SYSSIZE].n_value; | |
710 | Sysmap = (struct pte *) | |
711 | calloc((unsigned) Syssize, sizeof (struct pte)); | |
712 | if (Sysmap == NULL) { | |
713 | seterr("out of space for Sysmap"); | |
714 | return (-1); | |
715 | } | |
716 | addr = (long) nl[X_SYSMAP].n_value; | |
717 | addr &= ~KERNBASE; | |
718 | (void) lseek(kmem, addr, 0); | |
719 | if (read(kmem, (char *) Sysmap, Syssize * sizeof (struct pte)) | |
720 | != Syssize * sizeof (struct pte)) { | |
721 | seterr("can't read Sysmap"); | |
722 | return (-1); | |
723 | } | |
724 | } | |
725 | usrpt = (struct pte *)nl[X_USRPT].n_value; | |
726 | Usrptmap = (struct pte *)nl[X_USRPTMAP].n_value; | |
727 | if (kvm_read((long)nl[X_NSWAP].n_value, &nswap, sizeof (long)) != | |
728 | sizeof (long)) { | |
729 | seterr("can't read nswap"); | |
730 | return (-1); | |
731 | } | |
732 | if (kvm_read((long)nl[X_DMMIN].n_value, &dmmin, sizeof (long)) != | |
733 | sizeof (long)) { | |
734 | seterr("can't read dmmin"); | |
735 | return (-1); | |
736 | } | |
737 | if (kvm_read((long)nl[X_DMMAX].n_value, &dmmax, sizeof (long)) != | |
738 | sizeof (long)) { | |
739 | seterr("can't read dmmax"); | |
740 | return (-1); | |
741 | } | |
742 | return (0); | |
743 | } | |
744 | ||
745 | kvm_read(loc, buf, len) | |
746 | unsigned long loc; | |
747 | char *buf; | |
748 | { | |
0e005c87 MT |
749 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) |
750 | return (-1); | |
41a4fbbe MT |
751 | if (loc & KERNBASE) { |
752 | klseek(kmem, loc, 0); | |
753 | if (read(kmem, buf, len) != len) { | |
754 | seterr("error reading kmem at %x\n", loc); | |
755 | return (-1); | |
756 | } | |
757 | } else { | |
758 | lseek(mem, loc, 0); | |
759 | if (read(mem, buf, len) != len) { | |
760 | seterr("error reading mem at %x\n", loc); | |
761 | return (-1); | |
762 | } | |
763 | } | |
764 | return (len); | |
765 | } | |
766 | ||
767 | static | |
768 | klseek(fd, loc, off) | |
769 | int fd; | |
0e005c87 | 770 | off_t loc; |
41a4fbbe MT |
771 | int off; |
772 | { | |
0e005c87 | 773 | |
41a4fbbe | 774 | if (deadkernel) { |
0e005c87 MT |
775 | off_t vtophys(); |
776 | ||
41a4fbbe MT |
777 | if ((loc = vtophys(loc)) == -1) |
778 | return; | |
779 | } | |
0e005c87 | 780 | (void) lseek(fd, (off_t)loc, off); |
41a4fbbe MT |
781 | } |
782 | ||
783 | /* | |
784 | * Given a base/size pair in virtual swap area, | |
785 | * return a physical base/size pair which is the | |
786 | * (largest) initial, physically contiguous block. | |
787 | */ | |
788 | static | |
789 | vstodb(vsbase, vssize, dmp, dbp, rev) | |
790 | register int vsbase; | |
791 | int vssize; | |
792 | struct dmap *dmp; | |
793 | register struct dblock *dbp; | |
794 | { | |
795 | register int blk = dmmin; | |
796 | register swblk_t *ip = dmp->dm_map; | |
797 | ||
798 | vsbase = ctod(vsbase); | |
799 | vssize = ctod(vssize); | |
800 | if (vsbase < 0 || vsbase + vssize > dmp->dm_size) | |
801 | /*panic("vstodb")*/; | |
802 | while (vsbase >= blk) { | |
803 | vsbase -= blk; | |
804 | if (blk < dmmax) | |
805 | blk *= 2; | |
806 | ip++; | |
807 | } | |
808 | if (*ip <= 0 || *ip + blk > nswap) | |
809 | /*panic("vstodb")*/; | |
810 | dbp->db_size = MIN(vssize, blk - vsbase); | |
811 | dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); | |
812 | } | |
813 | ||
814 | /* | |
815 | * This routine was stolen from adb to simulate memory management | |
816 | * on the VAX. | |
817 | */ | |
818 | static off_t | |
819 | vtophys(loc) | |
820 | long loc; | |
821 | { | |
822 | register p; | |
823 | off_t newloc; | |
824 | ||
825 | newloc = loc & ~KERNBASE; | |
826 | p = btop(newloc); | |
827 | if ((loc & KERNBASE) == 0) { | |
828 | seterr("vtophys: translating non-kernel address"); | |
829 | return((off_t) -1); | |
830 | } | |
831 | if (p >= Syssize) { | |
832 | seterr("vtophys: page out of bound (%d>=%d)", p, Syssize); | |
833 | return((off_t) -1); | |
834 | } | |
835 | if (Sysmap[p].pg_v == 0 && | |
836 | (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) { | |
837 | seterr("vtophys: page not valid"); | |
838 | return((off_t) -1); | |
839 | } | |
840 | loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET)); | |
841 | return(loc); | |
842 | } | |
843 | ||
844 | #include <varargs.h> | |
845 | static char errbuf[LINE_MAX]; | |
846 | ||
847 | static | |
848 | seterr(va_alist) | |
849 | va_dcl | |
850 | { | |
851 | char *fmt; | |
852 | va_list ap; | |
853 | ||
854 | va_start(ap); | |
855 | fmt = va_arg(ap, char *); | |
856 | (void) vsprintf(errbuf, fmt, ap); | |
857 | va_end(ap); | |
858 | } | |
859 | ||
860 | static | |
861 | setsyserr(va_alist) | |
862 | va_dcl | |
863 | { | |
864 | char *fmt, *cp; | |
865 | va_list ap; | |
866 | extern errno; | |
867 | ||
868 | va_start(ap); | |
869 | fmt = va_arg(ap, char *); | |
870 | (void) vsprintf(errbuf, fmt, ap); | |
871 | for (cp=errbuf; *cp; cp++) | |
872 | ; | |
873 | sprintf(cp, ": %s", strerror(errno)); | |
874 | va_end(ap); | |
875 | } | |
876 | ||
877 | char * | |
878 | kvm_geterr() | |
879 | { | |
880 | ||
881 | return (errbuf); | |
882 | } |