Commit | Line | Data |
---|---|---|
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) | |
36 | static char sccsid[] = "@(#)kvm.c 5.18 (Berkeley) 5/7/91"; | |
37 | #endif /* LIBC_SCCS and not lint */ | |
38 | ||
8387d405 DG |
39 | #define DEBUG 0 |
40 | #define PROCFS 1 | |
15637ed4 RG |
41 | |
42 | #include <sys/param.h> | |
43 | #include <sys/user.h> | |
44 | #include <sys/proc.h> | |
45 | #include <sys/ioctl.h> | |
46 | #include <sys/kinfo.h> | |
47 | #include <sys/tty.h> | |
8387d405 DG |
48 | #include <sys/file.h> |
49 | #include <sys/types.h> | |
15637ed4 RG |
50 | #include <machine/vmparam.h> |
51 | #include <fcntl.h> | |
52 | #include <nlist.h> | |
53 | #include <kvm.h> | |
54 | #include <ndbm.h> | |
55 | #include <limits.h> | |
56 | #include <paths.h> | |
57 | #include <stdio.h> | |
58 | #include <string.h> | |
8387d405 | 59 | #include <sys/mman.h> |
15637ed4 | 60 | |
15637ed4 RG |
61 | #define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */ |
62 | #define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ | |
63 | #include <vm/vm.h> /* ??? kinfo_proc currently includes this*/ | |
64 | #include <vm/vm_page.h> | |
65 | #include <vm/swap_pager.h> | |
66 | #include <sys/kinfo_proc.h> | |
15637ed4 RG |
67 | |
68 | /* | |
69 | * files | |
70 | */ | |
71 | static const char *unixf, *memf, *kmemf, *swapf; | |
72 | static int unixx, mem, kmem, swap; | |
73 | static DBM *db; | |
74 | /* | |
75 | * flags | |
76 | */ | |
77 | static int deadkernel; | |
78 | static int kvminit = 0; | |
79 | static int kvmfilesopen = 0; | |
80 | /* | |
81 | * state | |
82 | */ | |
83 | static struct kinfo_proc *kvmprocbase, *kvmprocptr; | |
84 | static int kvmnprocs; | |
85 | /* | |
86 | * u. buffer | |
87 | */ | |
88 | static union { | |
89 | struct user user; | |
90 | char upages[UPAGES][NBPG]; | |
91 | } user; | |
92 | ||
15637ed4 RG |
93 | struct swapblk { |
94 | long offset; /* offset in swap device */ | |
95 | long size; /* remaining size of block in swap device */ | |
96 | }; | |
15637ed4 RG |
97 | /* |
98 | * random other stuff | |
99 | */ | |
15637ed4 RG |
100 | static int dmmin, dmmax; |
101 | static int pcbpf; | |
102 | static int argaddr0; /* XXX */ | |
103 | static int argaddr1; | |
104 | static int swaddr; | |
105 | static int nswap; | |
106 | static char *tmp; | |
15637ed4 | 107 | static struct pde *PTD; |
15637ed4 RG |
108 | |
109 | #define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp)) | |
110 | #define MAXSYMSIZE 256 | |
111 | ||
15637ed4 RG |
112 | #ifndef pftoc |
113 | #define pftoc(f) (f) | |
114 | #endif | |
115 | #ifndef iskva | |
116 | #define iskva(v) ((u_long)(v) & KERNBASE) | |
117 | #endif | |
118 | ||
119 | static struct nlist nl[] = { | |
120 | { "_Usrptmap" }, | |
121 | #define X_USRPTMAP 0 | |
122 | { "_usrpt" }, | |
123 | #define X_USRPT 1 | |
124 | { "_nswap" }, | |
125 | #define X_NSWAP 2 | |
126 | { "_dmmin" }, | |
127 | #define X_DMMIN 3 | |
128 | { "_dmmax" }, | |
129 | #define X_DMMAX 4 | |
130 | { "_vm_page_buckets" }, | |
131 | #define X_VM_PAGE_BUCKETS 5 | |
132 | { "_vm_page_hash_mask" }, | |
133 | #define X_VM_PAGE_HASH_MASK 6 | |
134 | { "_page_shift" }, | |
135 | #define X_PAGE_SHIFT 7 | |
8387d405 DG |
136 | { "_kstack" }, |
137 | #define X_KSTACK 8 | |
138 | { "_kernel_object" }, | |
139 | #define X_KERNEL_OBJECT 9 | |
140 | { "_btext",}, | |
141 | #define X_KERNEL_BTEXT 10 | |
15637ed4 RG |
142 | /* |
143 | * everything here and down, only if a dead kernel | |
144 | */ | |
145 | { "_Sysmap" }, | |
8387d405 | 146 | #define X_SYSMAP 11 |
15637ed4 RG |
147 | #define X_DEADKERNEL X_SYSMAP |
148 | { "_Syssize" }, | |
8387d405 | 149 | #define X_SYSSIZE 12 |
15637ed4 | 150 | { "_allproc" }, |
8387d405 | 151 | #define X_ALLPROC 13 |
15637ed4 | 152 | { "_zombproc" }, |
8387d405 | 153 | #define X_ZOMBPROC 14 |
15637ed4 | 154 | { "_nproc" }, |
8387d405 DG |
155 | #define X_NPROC 15 |
156 | #define X_LAST 15 | |
15637ed4 RG |
157 | { "_IdlePTD" }, |
158 | #define X_IdlePTD (X_LAST+1) | |
15637ed4 RG |
159 | { "" }, |
160 | }; | |
161 | ||
c6500831 | 162 | static void seterr(), setsyserr(), vstodb(); |
15637ed4 | 163 | static int getkvars(), kvm_doprocs(), kvm_init(); |
15637ed4 RG |
164 | |
165 | /* | |
166 | * returns 0 if files were opened now, | |
167 | * 1 if files were already opened, | |
168 | * -1 if files could not be opened. | |
169 | */ | |
170 | kvm_openfiles(uf, mf, sf) | |
171 | const char *uf, *mf, *sf; | |
172 | { | |
173 | if (kvmfilesopen) | |
174 | return (1); | |
175 | unixx = mem = kmem = swap = -1; | |
176 | unixf = (uf == NULL) ? _PATH_UNIX : uf; | |
177 | memf = (mf == NULL) ? _PATH_MEM : mf; | |
178 | ||
179 | if ((unixx = open(unixf, O_RDONLY, 0)) == -1) { | |
180 | setsyserr("can't open %s", unixf); | |
181 | goto failed; | |
182 | } | |
183 | if ((mem = open(memf, O_RDONLY, 0)) == -1) { | |
184 | setsyserr("can't open %s", memf); | |
185 | goto failed; | |
186 | } | |
187 | if (sf != NULL) | |
188 | swapf = sf; | |
189 | if (mf != NULL) { | |
190 | deadkernel++; | |
191 | kmemf = mf; | |
192 | kmem = mem; | |
193 | swap = -1; | |
194 | } else { | |
195 | kmemf = _PATH_KMEM; | |
196 | if ((kmem = open(kmemf, O_RDONLY, 0)) == -1) { | |
197 | setsyserr("can't open %s", kmemf); | |
198 | goto failed; | |
199 | } | |
200 | swapf = (sf == NULL) ? _PATH_DRUM : sf; | |
201 | /* | |
202 | * live kernel - avoid looking up nlist entries | |
203 | * past X_DEADKERNEL. | |
204 | */ | |
205 | nl[X_DEADKERNEL].n_name = ""; | |
206 | } | |
207 | if (swapf != NULL && ((swap = open(swapf, O_RDONLY, 0)) == -1)) { | |
208 | seterr("can't open %s", swapf); | |
209 | goto failed; | |
210 | } | |
211 | kvmfilesopen++; | |
212 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) /*XXX*/ | |
213 | return (-1); | |
214 | return (0); | |
215 | failed: | |
216 | kvm_close(); | |
217 | return (-1); | |
218 | } | |
219 | ||
220 | static | |
221 | kvm_init(uf, mf, sf) | |
222 | char *uf, *mf, *sf; | |
223 | { | |
224 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
225 | return (-1); | |
226 | if (getkvars() == -1) | |
227 | return (-1); | |
228 | kvminit = 1; | |
229 | ||
230 | return (0); | |
231 | } | |
232 | ||
233 | kvm_close() | |
234 | { | |
235 | if (unixx != -1) { | |
236 | close(unixx); | |
237 | unixx = -1; | |
238 | } | |
239 | if (kmem != -1) { | |
240 | if (kmem != mem) | |
241 | close(kmem); | |
242 | /* otherwise kmem is a copy of mem, and will be closed below */ | |
243 | kmem = -1; | |
244 | } | |
245 | if (mem != -1) { | |
246 | close(mem); | |
247 | mem = -1; | |
248 | } | |
249 | if (swap != -1) { | |
250 | close(swap); | |
251 | swap = -1; | |
252 | } | |
253 | if (db != NULL) { | |
254 | dbm_close(db); | |
255 | db = NULL; | |
256 | } | |
257 | kvminit = 0; | |
258 | kvmfilesopen = 0; | |
259 | deadkernel = 0; | |
15637ed4 RG |
260 | } |
261 | ||
262 | kvm_nlist(nl) | |
263 | struct nlist *nl; | |
264 | { | |
265 | datum key, data; | |
266 | char dbname[MAXPATHLEN]; | |
267 | char dbversion[_POSIX2_LINE_MAX]; | |
268 | char kversion[_POSIX2_LINE_MAX]; | |
269 | int dbversionlen; | |
270 | char symbuf[MAXSYMSIZE]; | |
271 | struct nlist nbuf, *n; | |
272 | int num, did; | |
273 | ||
274 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
275 | return (-1); | |
276 | if (deadkernel) | |
277 | goto hard2; | |
278 | /* | |
279 | * initialize key datum | |
280 | */ | |
281 | key.dptr = symbuf; | |
282 | ||
283 | if (db != NULL) | |
284 | goto win; /* off to the races */ | |
285 | /* | |
286 | * open database | |
287 | */ | |
288 | sprintf(dbname, "%s/kvm_%s", _PATH_VARRUN, basename(unixf)); | |
289 | if ((db = dbm_open(dbname, O_RDONLY, 0)) == NULL) | |
290 | goto hard2; | |
291 | /* | |
292 | * read version out of database | |
293 | */ | |
294 | bcopy("VERSION", symbuf, sizeof ("VERSION")-1); | |
295 | key.dsize = (sizeof ("VERSION") - 1); | |
296 | data = dbm_fetch(db, key); | |
297 | if (data.dptr == NULL) | |
298 | goto hard1; | |
299 | bcopy(data.dptr, dbversion, data.dsize); | |
300 | dbversionlen = data.dsize; | |
301 | /* | |
302 | * read version string from kernel memory | |
303 | */ | |
304 | bcopy("_version", symbuf, sizeof ("_version")-1); | |
305 | key.dsize = (sizeof ("_version")-1); | |
306 | data = dbm_fetch(db, key); | |
307 | if (data.dptr == NULL) | |
308 | goto hard1; | |
309 | if (data.dsize != sizeof (struct nlist)) | |
310 | goto hard1; | |
311 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
312 | lseek(kmem, nbuf.n_value, 0); | |
313 | if (read(kmem, kversion, dbversionlen) != dbversionlen) | |
314 | goto hard1; | |
315 | /* | |
316 | * if they match, we win - otherwise do it the hard way | |
317 | */ | |
318 | if (bcmp(dbversion, kversion, dbversionlen) != 0) | |
319 | goto hard1; | |
320 | /* | |
321 | * getem from the database. | |
322 | */ | |
323 | win: | |
324 | num = did = 0; | |
325 | for (n = nl; n->n_name && n->n_name[0]; n++, num++) { | |
326 | int len; | |
327 | /* | |
328 | * clear out fields from users buffer | |
329 | */ | |
330 | n->n_type = 0; | |
331 | n->n_other = 0; | |
332 | n->n_desc = 0; | |
333 | n->n_value = 0; | |
334 | /* | |
335 | * query db | |
336 | */ | |
337 | if ((len = strlen(n->n_name)) > MAXSYMSIZE) { | |
338 | seterr("symbol too large"); | |
339 | return (-1); | |
340 | } | |
341 | (void)strcpy(symbuf, n->n_name); | |
342 | key.dsize = len; | |
343 | data = dbm_fetch(db, key); | |
344 | if (data.dptr == NULL || data.dsize != sizeof (struct nlist)) | |
345 | continue; | |
346 | bcopy(data.dptr, &nbuf, sizeof (struct nlist)); | |
347 | n->n_value = nbuf.n_value; | |
348 | n->n_type = nbuf.n_type; | |
349 | n->n_desc = nbuf.n_desc; | |
350 | n->n_other = nbuf.n_other; | |
351 | did++; | |
352 | } | |
353 | return (num - did); | |
354 | hard1: | |
355 | dbm_close(db); | |
356 | db = NULL; | |
357 | hard2: | |
358 | num = nlist(unixf, nl); | |
359 | if (num == -1) | |
360 | seterr("nlist (hard way) failed"); | |
361 | return (num); | |
362 | } | |
363 | ||
364 | kvm_getprocs(what, arg) | |
365 | int what, arg; | |
366 | { | |
367 | static int ocopysize = -1; | |
368 | ||
369 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) | |
370 | return (NULL); | |
371 | if (!deadkernel) { | |
372 | int ret, copysize; | |
373 | ||
374 | if ((ret = getkerninfo(what, NULL, NULL, arg)) == -1) { | |
375 | setsyserr("can't get estimate for kerninfo"); | |
376 | return (-1); | |
377 | } | |
378 | copysize = ret; | |
379 | if (copysize > ocopysize && | |
170dc86a DG |
380 | (kvmprocbase = (struct kinfo_proc *) |
381 | realloc(kvmprocbase, copysize)) == NULL) { | |
15637ed4 RG |
382 | seterr("out of memory"); |
383 | return (-1); | |
384 | } | |
385 | ocopysize = copysize; | |
386 | if ((ret = getkerninfo(what, kvmprocbase, ©size, | |
387 | arg)) == -1) { | |
388 | setsyserr("can't get proc list"); | |
389 | return (-1); | |
390 | } | |
391 | if (copysize % sizeof (struct kinfo_proc)) { | |
392 | seterr("proc size mismatch (got %d total, kinfo_proc: %d)", | |
393 | copysize, sizeof (struct kinfo_proc)); | |
394 | return (-1); | |
395 | } | |
396 | kvmnprocs = copysize / sizeof (struct kinfo_proc); | |
397 | } else { | |
398 | int nproc; | |
399 | ||
400 | if (kvm_read((void *) nl[X_NPROC].n_value, &nproc, | |
401 | sizeof (int)) != sizeof (int)) { | |
402 | seterr("can't read nproc"); | |
403 | return (-1); | |
404 | } | |
405 | if ((kvmprocbase = (struct kinfo_proc *) | |
406 | malloc(nproc * sizeof (struct kinfo_proc))) == NULL) { | |
407 | seterr("out of memory (addr: %x nproc = %d)", | |
408 | nl[X_NPROC].n_value, nproc); | |
409 | return (-1); | |
410 | } | |
411 | kvmnprocs = kvm_doprocs(what, arg, kvmprocbase); | |
412 | realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc)); | |
413 | } | |
414 | kvmprocptr = kvmprocbase; | |
415 | ||
416 | return (kvmnprocs); | |
417 | } | |
418 | ||
419 | /* | |
420 | * XXX - should NOT give up so easily - especially since the kernel | |
421 | * may be corrupt (it died). Should gather as much information as possible. | |
422 | * Follows proc ptrs instead of reading table since table may go | |
423 | * away soon. | |
424 | */ | |
425 | static | |
426 | kvm_doprocs(what, arg, buff) | |
427 | int what, arg; | |
428 | char *buff; | |
429 | { | |
430 | struct proc *p, proc; | |
431 | register char *bp = buff; | |
432 | int i = 0; | |
433 | int doingzomb = 0; | |
434 | struct eproc eproc; | |
435 | struct pgrp pgrp; | |
436 | struct session sess; | |
437 | struct tty tty; | |
15637ed4 RG |
438 | |
439 | /* allproc */ | |
440 | if (kvm_read((void *) nl[X_ALLPROC].n_value, &p, | |
441 | sizeof (struct proc *)) != sizeof (struct proc *)) { | |
442 | seterr("can't read allproc"); | |
443 | return (-1); | |
444 | } | |
445 | ||
446 | again: | |
447 | for (; p; p = proc.p_nxt) { | |
448 | if (kvm_read(p, &proc, sizeof (struct proc)) != | |
449 | sizeof (struct proc)) { | |
450 | seterr("can't read proc at %x", p); | |
451 | return (-1); | |
452 | } | |
15637ed4 RG |
453 | if (kvm_read(proc.p_cred, &eproc.e_pcred, |
454 | sizeof (struct pcred)) == sizeof (struct pcred)) | |
455 | (void) kvm_read(eproc.e_pcred.pc_ucred, &eproc.e_ucred, | |
456 | sizeof (struct ucred)); | |
457 | switch(ki_op(what)) { | |
458 | ||
459 | case KINFO_PROC_PID: | |
460 | if (proc.p_pid != (pid_t)arg) | |
461 | continue; | |
462 | break; | |
463 | ||
464 | ||
465 | case KINFO_PROC_UID: | |
466 | if (eproc.e_ucred.cr_uid != (uid_t)arg) | |
467 | continue; | |
468 | break; | |
469 | ||
470 | case KINFO_PROC_RUID: | |
471 | if (eproc.e_pcred.p_ruid != (uid_t)arg) | |
472 | continue; | |
473 | break; | |
474 | } | |
15637ed4 RG |
475 | /* |
476 | * gather eproc | |
477 | */ | |
478 | eproc.e_paddr = p; | |
479 | if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) != | |
480 | sizeof (struct pgrp)) { | |
481 | seterr("can't read pgrp at %x", proc.p_pgrp); | |
482 | return (-1); | |
483 | } | |
484 | eproc.e_sess = pgrp.pg_session; | |
485 | eproc.e_pgid = pgrp.pg_id; | |
486 | eproc.e_jobc = pgrp.pg_jobc; | |
487 | if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session)) | |
488 | != sizeof (struct session)) { | |
489 | seterr("can't read session at %x", pgrp.pg_session); | |
490 | return (-1); | |
491 | } | |
492 | if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) { | |
493 | if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty)) | |
494 | != sizeof (struct tty)) { | |
495 | seterr("can't read tty at %x", sess.s_ttyp); | |
496 | return (-1); | |
497 | } | |
498 | eproc.e_tdev = tty.t_dev; | |
499 | eproc.e_tsess = tty.t_session; | |
500 | if (tty.t_pgrp != NULL) { | |
501 | if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct | |
502 | pgrp)) != sizeof (struct pgrp)) { | |
503 | seterr("can't read tpgrp at &x", | |
504 | tty.t_pgrp); | |
505 | return (-1); | |
506 | } | |
507 | eproc.e_tpgid = pgrp.pg_id; | |
508 | } else | |
509 | eproc.e_tpgid = -1; | |
510 | } else | |
511 | eproc.e_tdev = NODEV; | |
512 | if (proc.p_wmesg) | |
513 | kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN); | |
15637ed4 RG |
514 | (void) kvm_read(proc.p_vmspace, &eproc.e_vm, |
515 | sizeof (struct vmspace)); | |
516 | eproc.e_xsize = eproc.e_xrssize = | |
517 | eproc.e_xccount = eproc.e_xswrss = 0; | |
15637ed4 RG |
518 | |
519 | switch(ki_op(what)) { | |
520 | ||
521 | case KINFO_PROC_PGRP: | |
522 | if (eproc.e_pgid != (pid_t)arg) | |
523 | continue; | |
524 | break; | |
525 | ||
526 | case KINFO_PROC_TTY: | |
527 | if ((proc.p_flag&SCTTY) == 0 || | |
528 | eproc.e_tdev != (dev_t)arg) | |
529 | continue; | |
530 | break; | |
531 | } | |
532 | ||
533 | i++; | |
534 | bcopy(&proc, bp, sizeof (struct proc)); | |
535 | bp += sizeof (struct proc); | |
536 | bcopy(&eproc, bp, sizeof (struct eproc)); | |
537 | bp+= sizeof (struct eproc); | |
538 | } | |
539 | if (!doingzomb) { | |
540 | /* zombproc */ | |
541 | if (kvm_read((void *) nl[X_ZOMBPROC].n_value, &p, | |
542 | sizeof (struct proc *)) != sizeof (struct proc *)) { | |
543 | seterr("can't read zombproc"); | |
544 | return (-1); | |
545 | } | |
546 | doingzomb = 1; | |
547 | goto again; | |
548 | } | |
549 | ||
550 | return (i); | |
551 | } | |
552 | ||
553 | struct proc * | |
554 | kvm_nextproc() | |
555 | { | |
556 | ||
557 | if (!kvmprocbase && kvm_getprocs(0, 0) == -1) | |
558 | return (NULL); | |
559 | if (kvmprocptr >= (kvmprocbase + kvmnprocs)) { | |
8387d405 | 560 | #if 0 |
15637ed4 | 561 | seterr("end of proc list"); |
8387d405 | 562 | #endif |
15637ed4 RG |
563 | return (NULL); |
564 | } | |
565 | return((struct proc *)(kvmprocptr++)); | |
566 | } | |
567 | ||
568 | struct eproc * | |
569 | kvm_geteproc(p) | |
570 | const struct proc *p; | |
571 | { | |
572 | return ((struct eproc *)(((char *)p) + sizeof (struct proc))); | |
573 | } | |
574 | ||
575 | kvm_setproc() | |
576 | { | |
577 | kvmprocptr = kvmprocbase; | |
578 | } | |
579 | ||
580 | kvm_freeprocs() | |
581 | { | |
582 | ||
583 | if (kvmprocbase) { | |
584 | free(kvmprocbase); | |
585 | kvmprocbase = NULL; | |
586 | } | |
587 | } | |
588 | ||
8387d405 DG |
589 | proc_getmem(const struct proc *p, void *buffer, vm_offset_t size, vm_offset_t offset) { |
590 | int fd; | |
591 | char fn[512+1]; | |
592 | sprintf(fn,"/proc/%d",p->p_pid); | |
593 | if( p->p_flag & SSYS) | |
594 | return 0; | |
595 | fd = open(fn,O_RDONLY); | |
596 | if( fd == -1) { | |
597 | return 0; | |
598 | } | |
599 | ||
600 | if( lseek(fd, offset, 0) == -1) { | |
601 | close(fd); | |
602 | return 0; | |
603 | } | |
604 | if( read(fd, buffer, size) <= 0) { | |
605 | close(fd); | |
606 | return 0; | |
607 | } | |
608 | close(fd); | |
609 | return 1; | |
610 | } | |
15637ed4 | 611 | |
15637ed4 RG |
612 | struct user * |
613 | kvm_getu(p) | |
614 | const struct proc *p; | |
615 | { | |
616 | register struct kinfo_proc *kp = (struct kinfo_proc *)p; | |
617 | register int i; | |
618 | register char *up; | |
619 | u_int vaddr; | |
620 | struct swapblk swb; | |
8387d405 | 621 | int arg_size; |
15637ed4 RG |
622 | |
623 | if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) | |
624 | return (NULL); | |
625 | if (p->p_stat == SZOMB) { | |
626 | seterr("zombie process"); | |
627 | return (NULL); | |
628 | } | |
629 | ||
c6500831 | 630 | if (proc_getmem(p, user.upages, sizeof user.upages, USRSTACK)) { |
8387d405 DG |
631 | kp->kp_eproc.e_vm.vm_rssize = |
632 | kp->kp_eproc.e_vm.vm_pmap.pm_stats.resident_count; /* XXX */ | |
633 | return &user.user; | |
634 | } | |
635 | ||
c6500831 | 636 | return (NULL); |
15637ed4 | 637 | } |
15637ed4 RG |
638 | |
639 | char * | |
640 | kvm_getargs(p, up) | |
641 | const struct proc *p; | |
642 | const struct user *up; | |
643 | { | |
8387d405 DG |
644 | int arg_size, arg_offset; |
645 | static char cmdbuf[ARG_MAX]; | |
646 | char argc[ARG_MAX*3]; | |
647 | int *argv; | |
15637ed4 | 648 | register char *cp; |
15637ed4 RG |
649 | char c; |
650 | int nbad; | |
8387d405 DG |
651 | char *cmdbufp; |
652 | vm_offset_t vaddr; | |
653 | char procfile[16]; | |
654 | int mmfd; | |
655 | #if 0 | |
656 | char *argc = NULL; | |
15637ed4 | 657 | #endif |
15637ed4 | 658 | |
8387d405 DG |
659 | *cmdbuf = 0; |
660 | ||
661 | vaddr = (u_int)((struct kinfo_proc *)p)->kp_eproc.e_vm.vm_minsaddr; | |
662 | arg_size = USRSTACK - vaddr; | |
663 | ||
664 | if (arg_size >= 3*ARG_MAX) | |
665 | goto bad; | |
666 | ||
667 | #if 0 | |
668 | sprintf(procfile, "/proc/%d", p->p_pid); | |
669 | if ((mmfd = open(procfile, O_RDONLY, 0)) == -1) { | |
670 | printf("failed to open %s\n",procfile); | |
671 | goto bad; | |
672 | } | |
673 | ||
674 | if ((argc = mmap(0, arg_size, PROT_READ, MAP_FILE, mmfd, vaddr)) | |
675 | == (char *)-1) { | |
676 | printf("failed to mmap %s error=%s\n", procfile, strerror(errno)); | |
677 | goto bad; | |
678 | } | |
15637ed4 | 679 | #endif |
8387d405 | 680 | |
c6500831 DG |
681 | if (!proc_getmem(p, argc, arg_size, vaddr)) |
682 | goto bad; | |
15637ed4 | 683 | |
8387d405 DG |
684 | argv = (int *)argc; |
685 | ||
686 | arg_offset = argv[0] - vaddr; | |
687 | if (arg_offset >= 3*ARG_MAX) | |
688 | goto bad; | |
689 | ||
15637ed4 | 690 | nbad = 0; |
15637ed4 | 691 | |
8387d405 DG |
692 | cmdbufp = cmdbuf; |
693 | for (cp = &argc[arg_offset]; cp < &argc[arg_size]; cp++, cmdbufp++) { | |
694 | c = *cmdbufp = *cp; | |
15637ed4 | 695 | if (c == 0) { /* convert null between arguments to space */ |
8387d405 | 696 | *cmdbufp = ' '; |
15637ed4 RG |
697 | if (*(cp+1) == 0) break; /* if null argument follows then no more args */ |
698 | } | |
699 | else if (c < ' ' || c > 0176) { | |
700 | if (++nbad >= 5*(0+1)) { /* eflg -> 0 XXX */ /* limit number of bad chars to 5 */ | |
8387d405 | 701 | *cmdbufp++ = '?'; |
15637ed4 RG |
702 | break; |
703 | } | |
8387d405 | 704 | *cmdbufp = '?'; |
15637ed4 RG |
705 | } |
706 | else if (0 == 0 && c == '=') { /* eflg -> 0 XXX */ | |
8387d405 DG |
707 | while (*--cmdbufp != ' ') |
708 | if (cmdbufp <= cmdbuf) | |
15637ed4 RG |
709 | break; |
710 | break; | |
711 | } | |
712 | } | |
8387d405 DG |
713 | *cmdbufp = 0; |
714 | ||
715 | while (*--cmdbufp == ' ') | |
716 | *cmdbufp = 0; | |
717 | ||
718 | if (cmdbuf[0] == '-' || cmdbuf[0] == '?' || cmdbuf[0] <= ' ') { | |
719 | bad: | |
15637ed4 RG |
720 | (void) strcat(cmdbuf, " ("); |
721 | (void) strncat(cmdbuf, p->p_comm, sizeof(p->p_comm)); | |
722 | (void) strcat(cmdbuf, ")"); | |
723 | } | |
8387d405 DG |
724 | #if 0 |
725 | if (argc && argc != (char *)-1) | |
726 | munmap(argc, arg_size); | |
727 | if (mmfd && mmfd != -1) | |
728 | close (mmfd); | |
729 | #endif | |
15637ed4 RG |
730 | return (cmdbuf); |
731 | } | |
732 | ||
15637ed4 RG |
733 | static |
734 | getkvars() | |
735 | { | |
736 | if (kvm_nlist(nl) == -1) | |
737 | return (-1); | |
15637ed4 RG |
738 | if (kvm_read((void *) nl[X_NSWAP].n_value, &nswap, sizeof (long)) != |
739 | sizeof (long)) { | |
740 | seterr("can't read nswap"); | |
741 | return (-1); | |
742 | } | |
743 | if (kvm_read((void *) nl[X_DMMIN].n_value, &dmmin, sizeof (long)) != | |
744 | sizeof (long)) { | |
745 | seterr("can't read dmmin"); | |
746 | return (-1); | |
747 | } | |
748 | if (kvm_read((void *) nl[X_DMMAX].n_value, &dmmax, sizeof (long)) != | |
749 | sizeof (long)) { | |
750 | seterr("can't read dmmax"); | |
751 | return (-1); | |
752 | } | |
753 | return (0); | |
754 | } | |
755 | ||
756 | kvm_read(loc, buf, len) | |
757 | void *loc; | |
758 | void *buf; | |
759 | { | |
760 | if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) | |
761 | return (-1); | |
762 | if (iskva(loc)) { | |
c6500831 | 763 | lseek(kmem, (off_t) loc, 0); |
15637ed4 RG |
764 | if (read(kmem, buf, len) != len) { |
765 | seterr("error reading kmem at %x", loc); | |
766 | return (-1); | |
767 | } | |
768 | } else { | |
769 | lseek(mem, (off_t) loc, 0); | |
770 | if (read(mem, buf, len) != len) { | |
771 | seterr("error reading mem at %x", loc); | |
772 | return (-1); | |
773 | } | |
774 | } | |
775 | return (len); | |
776 | } | |
777 | ||
15637ed4 RG |
778 | #include <varargs.h> |
779 | static char errbuf[_POSIX2_LINE_MAX]; | |
780 | ||
781 | static void | |
782 | seterr(va_alist) | |
783 | va_dcl | |
784 | { | |
785 | char *fmt; | |
786 | va_list ap; | |
787 | ||
788 | va_start(ap); | |
789 | fmt = va_arg(ap, char *); | |
790 | (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap); | |
791 | #if DEBUG | |
792 | (void) vfprintf(stderr, fmt, ap); | |
793 | #endif | |
794 | va_end(ap); | |
795 | } | |
796 | ||
797 | static void | |
798 | setsyserr(va_alist) | |
799 | va_dcl | |
800 | { | |
801 | char *fmt, *cp; | |
802 | va_list ap; | |
803 | extern int errno; | |
804 | ||
805 | va_start(ap); | |
806 | fmt = va_arg(ap, char *); | |
807 | (void) vsnprintf(errbuf, _POSIX2_LINE_MAX, fmt, ap); | |
808 | for (cp=errbuf; *cp; cp++) | |
809 | ; | |
810 | snprintf(cp, _POSIX2_LINE_MAX - (cp - errbuf), ": %s", strerror(errno)); | |
8387d405 DG |
811 | #if DEBUG |
812 | (void) fprintf(stderr, "%s\n", errbuf); | |
813 | #endif | |
15637ed4 RG |
814 | va_end(ap); |
815 | } | |
816 | ||
817 | char * | |
818 | kvm_geterr() | |
819 | { | |
820 | return (errbuf); | |
821 | } |