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