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"); 335 return (-1); 336 } 337 kvmnprocs = copysize / sizeof (struct kinfo_proc); 338 } else { 339 int nproc; 340 341 if (kvm_read(nl[X_NPROC].n_value, &nproc, sizeof (int)) != 342 sizeof (int)) { 343 seterr("can't read nproc"); 344 return (-1); 345 } 346 if ((kvmprocbase = (struct kinfo_proc *) 347 malloc(nproc * sizeof (struct kinfo_proc))) == NULL) { 348 seterr("out of memory (addr: %x nproc = %d)", 349 nl[X_NPROC].n_value, nproc); 350 return (-1); 351 } 352 kvmnprocs = kvm_doprocs(what, arg, kvmprocbase); 353 realloc(kvmprocbase, kvmnprocs * sizeof (struct kinfo_proc)); 354 } 355 kvmprocptr = kvmprocbase; 356 357 return (kvmnprocs); 358 } 359 360 /* 361 * XXX - should NOT give up so easily - especially since the kernel 362 * may be corrupt (it died). Should gather as much information as possible. 363 * Follows proc ptrs instead of reading table since table may go 364 * away soon. 365 */ 366 static 367 kvm_doprocs(what, arg, buff) 368 int what, arg; 369 char *buff; 370 { 371 struct proc *p, proc; 372 register char *bp = buff; 373 int i = 0; 374 int doingzomb = 0; 375 struct eproc eproc; 376 struct pgrp pgrp; 377 struct session sess; 378 struct tty tty; 379 struct text text; 380 381 /* allproc */ 382 if (kvm_read(nl[X_ALLPROC].n_value, &p, 383 sizeof (struct proc *)) != sizeof (struct proc *)) { 384 seterr("can't read allproc"); 385 return (-1); 386 } 387 388 again: 389 for (; p; p = proc.p_nxt) { 390 if (kvm_read(p, &proc, sizeof (struct proc)) != 391 sizeof (struct proc)) { 392 seterr("can't read proc at %x", p); 393 return (-1); 394 } 395 switch(ki_op(what)) { 396 397 case KINFO_PROC_PID: 398 if (proc.p_pid != (pid_t)arg) 399 continue; 400 break; 401 402 403 case KINFO_PROC_UID: 404 if (proc.p_uid != (uid_t)arg) 405 continue; 406 break; 407 408 case KINFO_PROC_RUID: 409 if (proc.p_ruid != (uid_t)arg) 410 continue; 411 break; 412 } 413 /* 414 * gather eproc 415 */ 416 eproc.e_paddr = p; 417 if (kvm_read(proc.p_pgrp, &pgrp, sizeof (struct pgrp)) != 418 sizeof (struct pgrp)) { 419 seterr("can't read pgrp at %x", proc.p_pgrp); 420 return (-1); 421 } 422 eproc.e_sess = pgrp.pg_session; 423 eproc.e_pgid = pgrp.pg_id; 424 eproc.e_jobc = pgrp.pg_jobc; 425 if (kvm_read(pgrp.pg_session, &sess, sizeof (struct session)) 426 != sizeof (struct session)) { 427 seterr("can't read session at %x", pgrp.pg_session); 428 return (-1); 429 } 430 if ((proc.p_flag&SCTTY) && sess.s_ttyp != NULL) { 431 if (kvm_read(sess.s_ttyp, &tty, sizeof (struct tty)) 432 != sizeof (struct tty)) { 433 seterr("can't read tty at %x", sess.s_ttyp); 434 return (-1); 435 } 436 eproc.e_tdev = tty.t_dev; 437 eproc.e_tsess = tty.t_session; 438 if (tty.t_pgrp != NULL) { 439 if (kvm_read(tty.t_pgrp, &pgrp, sizeof (struct 440 pgrp)) != sizeof (struct pgrp)) { 441 seterr("can't read tpgrp at &x", 442 tty.t_pgrp); 443 return (-1); 444 } 445 eproc.e_tpgid = pgrp.pg_id; 446 } else 447 eproc.e_tpgid = -1; 448 } else 449 eproc.e_tdev = NODEV; 450 if (proc.p_wmesg) 451 kvm_read(proc.p_wmesg, eproc.e_wmesg, WMESGLEN); 452 if (proc.p_textp) { 453 kvm_read(proc.p_textp, &text, sizeof (text)); 454 eproc.e_xsize = text.x_size; 455 eproc.e_xrssize = text.x_rssize; 456 eproc.e_xccount = text.x_ccount; 457 eproc.e_xswrss = text.x_swrss; 458 } else { 459 eproc.e_xsize = eproc.e_xrssize = 460 eproc.e_xccount = eproc.e_xswrss = 0; 461 } 462 463 switch(ki_op(what)) { 464 465 case KINFO_PROC_PGRP: 466 if (eproc.e_pgid != (pid_t)arg) 467 continue; 468 break; 469 470 case KINFO_PROC_TTY: 471 if ((proc.p_flag&SCTTY) == 0 || 472 eproc.e_tdev != (dev_t)arg) 473 continue; 474 break; 475 } 476 477 i++; 478 bcopy(&proc, bp, sizeof (struct proc)); 479 bp += sizeof (struct proc); 480 bcopy(&eproc, bp, sizeof (struct eproc)); 481 bp+= sizeof (struct eproc); 482 } 483 if (!doingzomb) { 484 /* zombproc */ 485 if (kvm_read(nl[X_ZOMBPROC].n_value, &p, 486 sizeof (struct proc *)) != sizeof (struct proc *)) { 487 seterr("can't read zombproc"); 488 return (-1); 489 } 490 doingzomb = 1; 491 goto again; 492 } 493 494 return (i); 495 } 496 497 498 struct proc * 499 kvm_nextproc() 500 { 501 502 if (!kvmprocbase && kvm_getprocs(0, 0) == -1) 503 return (NULL); 504 if (kvmprocptr >= (kvmprocbase + kvmnprocs)) { 505 seterr("end of proc list"); 506 return (NULL); 507 } 508 return((struct proc *)(kvmprocptr++)); 509 } 510 511 struct eproc * 512 kvm_geteproc(p) 513 struct proc *p; 514 { 515 return ((struct eproc *)(((char *)p) + sizeof (struct proc))); 516 } 517 518 kvm_setproc() 519 { 520 521 kvmprocptr = kvmprocbase; 522 } 523 524 kvm_freeprocs() 525 { 526 527 if (kvmprocbase) { 528 free(kvmprocbase); 529 kvmprocbase = NULL; 530 } 531 } 532 533 struct user * 534 kvm_getu(p) 535 struct proc *p; 536 { 537 struct pte *pteaddr, apte; 538 struct pte arguutl[UPAGES+(CLSIZE*2)]; 539 register int i; 540 int ncl; 541 542 if (kvminit == 0 && kvm_init(NULL, NULL, NULL, 0) == -1) 543 return (NULL); 544 if (p->p_stat == SZOMB) { 545 seterr("zombie process"); 546 return (NULL); 547 } 548 if ((p->p_flag & SLOAD) == 0) { 549 if (swap < 0) { 550 seterr("no swap"); 551 return (NULL); 552 } 553 (void) lseek(swap, (long)dtob(p->p_swaddr), 0); 554 if (read(swap, (char *)&user.user, sizeof (struct user)) != 555 sizeof (struct user)) { 556 seterr("can't read u for pid %d from %s\n", 557 p->p_pid, swapf); 558 return (NULL); 559 } 560 pcbpf = 0; 561 argaddr0 = 0; 562 argaddr1 = 0; 563 return (&user.user); 564 } 565 pteaddr = &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1]; 566 klseek(kmem, (long)pteaddr, 0); 567 if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { 568 seterr("can't read indir pte to get u for pid %d from %s", 569 p->p_pid, kmemf); 570 return (NULL); 571 } 572 lseek(mem, 573 (long)ctob(apte.pg_pfnum+1) - (UPAGES+(CLSIZE*2)) * sizeof (struct pte), 574 0); 575 if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) { 576 seterr("can't read page table for u of pid %d from %s", 577 p->p_pid, memf); 578 return (NULL); 579 } 580 if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum) 581 argaddr0 = ctob(arguutl[0].pg_pfnum); 582 else 583 argaddr0 = 0; 584 if (arguutl[CLSIZE*1].pg_fod == 0 && arguutl[CLSIZE*1].pg_pfnum) 585 argaddr1 = ctob(arguutl[CLSIZE*1].pg_pfnum); 586 else 587 argaddr1 = 0; 588 pcbpf = arguutl[CLSIZE*2].pg_pfnum; 589 ncl = (sizeof (struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); 590 while (--ncl >= 0) { 591 i = ncl * CLSIZE; 592 lseek(mem, (long)ctob(arguutl[(CLSIZE*2)+i].pg_pfnum), 0); 593 if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) { 594 seterr("can't read page %d of u of pid %d from %s", 595 arguutl[CLSIZE+i].pg_pfnum, p->p_pid, memf); 596 return(NULL); 597 } 598 } 599 return (&user.user); 600 } 601 602 char * 603 kvm_getargs(p, up) 604 struct proc *p; 605 struct user *up; 606 { 607 char cmdbuf[CLSIZE*NBPG*2]; 608 union { 609 char argc[CLSIZE*NBPG*2]; 610 int argi[CLSIZE*NBPG*2/sizeof (int)]; 611 } argspac; 612 register char *cp; 613 register int *ip; 614 char c; 615 int nbad; 616 struct dblock db; 617 char *file; 618 619 if (p->p_stat == SZOMB) 620 return ("<defunct>"); 621 if (p->p_flag & SWEXIT) 622 return ("<exiting>"); 623 if (up == NULL || p->p_pid == 0 || p->p_pid == 2) 624 goto retucomm; 625 if ((p->p_flag & SLOAD) == 0 || argaddr1 == 0) { 626 if (swap < 0) 627 goto retucomm; 628 vstodb(0, CLSIZE, &up->u_smap, &db, 1); 629 (void) lseek(swap, (long)dtob(db.db_base), 0); 630 if (read(swap, (char *)&argspac.argc[NBPG*CLSIZE], 631 NBPG*CLSIZE) != NBPG*CLSIZE) 632 goto bad; 633 vstodb(1, CLSIZE, &up->u_smap, &db, 1); 634 (void) lseek(swap, (long)dtob(db.db_base), 0); 635 if (read(swap, (char *)&argspac.argc[0], 636 NBPG*CLSIZE) != NBPG*CLSIZE) 637 goto bad; 638 file = swapf; 639 } else { 640 if (argaddr0) { 641 lseek(mem, (long)argaddr0, 0); 642 if (read(mem, (char *)&argspac, NBPG*CLSIZE) 643 != NBPG*CLSIZE) 644 goto bad; 645 } else 646 bzero(&argspac, NBPG*CLSIZE); 647 lseek(mem, (long)argaddr1, 0); 648 if (read(mem, &argspac.argc[NBPG*CLSIZE], NBPG*CLSIZE) 649 != NBPG*CLSIZE) 650 goto bad; 651 file = memf; 652 } 653 ip = &argspac.argi[CLSIZE*NBPG*2/sizeof (int)]; 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; 662 for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG*2]; cp++) { 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; 683 (void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG*2] - cp); 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 } 727 } 728 usrpt = (struct pte *)nl[X_USRPT].n_value; 729 Usrptmap = (struct pte *)nl[X_USRPTMAP].n_value; 730 if (kvm_read((long)nl[X_NSWAP].n_value, &nswap, sizeof (long)) != 731 sizeof (long)) { 732 seterr("can't read nswap"); 733 return (-1); 734 } 735 if (kvm_read((long)nl[X_DMMIN].n_value, &dmmin, sizeof (long)) != 736 sizeof (long)) { 737 seterr("can't read dmmin"); 738 return (-1); 739 } 740 if (kvm_read((long)nl[X_DMMAX].n_value, &dmmax, sizeof (long)) != 741 sizeof (long)) { 742 seterr("can't read dmmax"); 743 return (-1); 744 } 745 return (0); 746 } 747 748 kvm_read(loc, buf, len) 749 unsigned long loc; 750 char *buf; 751 { 752 if (kvmfilesopen == 0 && kvm_openfiles(NULL, NULL, NULL) == -1) 753 return (-1); 754 if (loc & KERNBASE) { 755 klseek(kmem, loc, 0); 756 if (read(kmem, buf, len) != len) { 757 seterr("error reading kmem at %x\n", loc); 758 return (-1); 759 } 760 } else { 761 lseek(mem, loc, 0); 762 if (read(mem, buf, len) != len) { 763 seterr("error reading mem at %x\n", loc); 764 return (-1); 765 } 766 } 767 return (len); 768 } 769 770 static 771 klseek(fd, loc, off) 772 int fd; 773 off_t loc; 774 int off; 775 { 776 777 if (deadkernel) { 778 off_t vtophys(); 779 780 if ((loc = vtophys(loc)) == -1) 781 return; 782 } 783 (void) lseek(fd, (off_t)loc, off); 784 } 785 786 /* 787 * Given a base/size pair in virtual swap area, 788 * return a physical base/size pair which is the 789 * (largest) initial, physically contiguous block. 790 */ 791 static 792 vstodb(vsbase, vssize, dmp, dbp, rev) 793 register int vsbase; 794 int vssize; 795 struct dmap *dmp; 796 register struct dblock *dbp; 797 { 798 register int blk = dmmin; 799 register swblk_t *ip = dmp->dm_map; 800 801 vsbase = ctod(vsbase); 802 vssize = ctod(vssize); 803 if (vsbase < 0 || vsbase + vssize > dmp->dm_size) 804 /*panic("vstodb")*/; 805 while (vsbase >= blk) { 806 vsbase -= blk; 807 if (blk < dmmax) 808 blk *= 2; 809 ip++; 810 } 811 if (*ip <= 0 || *ip + blk > nswap) 812 /*panic("vstodb")*/; 813 dbp->db_size = MIN(vssize, blk - vsbase); 814 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); 815 } 816 817 /* 818 * This routine was stolen from adb to simulate memory management 819 * on the VAX. 820 */ 821 static off_t 822 vtophys(loc) 823 long loc; 824 { 825 register p; 826 off_t newloc; 827 828 newloc = loc & ~KERNBASE; 829 p = btop(newloc); 830 if ((loc & KERNBASE) == 0) { 831 seterr("vtophys: translating non-kernel address"); 832 return((off_t) -1); 833 } 834 if (p >= Syssize) { 835 seterr("vtophys: page out of bound (%d>=%d)", p, Syssize); 836 return((off_t) -1); 837 } 838 if (Sysmap[p].pg_v == 0 && 839 (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) { 840 seterr("vtophys: page not valid"); 841 return((off_t) -1); 842 } 843 loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET)); 844 return(loc); 845 } 846 847 #include <varargs.h> 848 static char errbuf[LINE_MAX]; 849 850 static 851 seterr(va_alist) 852 va_dcl 853 { 854 char *fmt; 855 va_list ap; 856 857 va_start(ap); 858 fmt = va_arg(ap, char *); 859 (void) vsprintf(errbuf, fmt, ap); 860 va_end(ap); 861 } 862 863 static 864 setsyserr(va_alist) 865 va_dcl 866 { 867 char *fmt, *cp; 868 va_list ap; 869 extern errno; 870 871 va_start(ap); 872 fmt = va_arg(ap, char *); 873 (void) vsprintf(errbuf, fmt, ap); 874 for (cp=errbuf; *cp; cp++) 875 ; 876 sprintf(cp, ": %s", strerror(errno)); 877 va_end(ap); 878 } 879 880 char * 881 kvm_geterr() 882 { 883 884 return (errbuf); 885 } 886