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