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> 31 #include <kvm.h> 32 #include <ctype.h> 33 #include <cencode.h> 34 #include <nlist.h> 35 #include <pwd.h> 36 #include <strings.h> 37 #include <ndbm.h> 38 #include <limits.h> 39 #include <paths.h> 40 #include <stdio.h> 41 42 /* 43 * files 44 */ 45 static char *unixf, *memf, *kmemf, *swapf; 46 static int unixx, mem, kmem, swap; 47 static DBM *db; 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; 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; 74 static int argaddr0; /* XXX */ 75 static int argaddr1; 76 static int nswap; 77 static char *tmp; 78 79 #define basename(cp) ((tmp=rindex((cp), '/')) ? tmp+1 : (cp)) 80 #define MAXSYMSIZE 256 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 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 */ 117 kvm_openfiles(uf, mf, sf) 118 char *uf, *mf, *sf; 119 { 120 if (kvmfilesopen) 121 return (1); 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 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 178 kvm_close() 179 { 180 if (unixx != -1) { 181 close(unixx); 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) { 191 close(mem); 192 mem = -1; 193 } 194 if (swap != -1) { 195 close(swap); 196 swap = -1; 197 } 198 if (db != NULL) { 199 dbm_close(db); 200 db = NULL; 201 } 202 kvminit = 0; 203 kvmfilesopen = 0; 204 deadkernel = 0; 205 if (Sysmap) { 206 free(Sysmap); 207 Sysmap = NULL; 208 } 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; 227 /* 228 * initialize key datum 229 */ 230 key.dptr = symbuf; 231 symbuf[0] = KVMDB_NLIST; 232 233 if (db != NULL) 234 goto win; /* off to the races */ 235 /* 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 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 /* 278 * clear out fields from users buffer 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: 308 return (nlist(unixf, nl)); /* XXX seterr if -1 */ 309 } 310 311 kvm_getprocs(what, arg) 312 { 313 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) 314 return (NULL); 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)) { 334 seterr("proc size mismatch (kinfo_proc: %d)", 335 sizeof (struct kinfo_proc)); 336 return (-1); 337 } 338 kvmnprocs = copysize / sizeof (struct kinfo_proc); 339 } else { 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) { 349 seterr("out of memory (addr: %x nproc = %d)", 350 nl[X_NPROC].n_value, nproc); 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; 539 struct pte arguutl[UPAGES+(CLSIZE*2)]; 540 register int i; 541 int ncl; 542 543 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) 544 return (NULL); 545 if (p->p_stat == SZOMB) { 546 seterr("zombie process"); 547 return (NULL); 548 } 549 if ((p->p_flag & SLOAD) == 0) { 550 if (swap < 0) { 551 seterr("no swap"); 552 return (NULL); 553 } 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; 562 argaddr0 = 0; 563 argaddr1 = 0; 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, 574 (long)ctob(apte.pg_pfnum+1) - (UPAGES+(CLSIZE*2)) * sizeof (struct pte), 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) 582 argaddr0 = ctob(arguutl[0].pg_pfnum); 583 else 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; 590 ncl = (sizeof (struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); 591 while (--ncl >= 0) { 592 i = ncl * CLSIZE; 593 lseek(mem, (long)ctob(arguutl[(CLSIZE*2)+i].pg_pfnum), 0); 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 { 608 char cmdbuf[CLSIZE*NBPG*2]; 609 union { 610 char argc[CLSIZE*NBPG*2]; 611 int argi[CLSIZE*NBPG*2/sizeof (int)]; 612 } argspac; 613 register char *cp; 614 register int *ip; 615 char c; 616 int nbad; 617 struct dblock db; 618 char *file; 619 620 if (up == NULL || p->p_pid == 0 || p->p_pid == 2) 621 goto retucomm; 622 if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) { 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); 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) 634 goto bad; 635 file = swapf; 636 } else { 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) 647 goto bad; 648 file = memf; 649 } 650 ip = &argspac.argi[CLSIZE*NBPG*2/sizeof (int)]; 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; 659 for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG*2]; cp++) { 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; 680 (void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG*2] - cp); 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 { 749 if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) 750 return (-1); 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; 770 off_t loc; 771 int off; 772 { 773 774 if (deadkernel) { 775 off_t vtophys(); 776 777 if ((loc = vtophys(loc)) == -1) 778 return; 779 } 780 (void) lseek(fd, (off_t)loc, off); 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 } 883