1 /*- 2 * Copyright (c) 1989, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software developed by the Computer Systems 6 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7 * BG 91-66 and contributed to Berkeley. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #if defined(LIBC_SCCS) && !defined(lint) 39 static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 40 #endif /* LIBC_SCCS and not lint */ 41 42 #include <sys/param.h> 43 #include <sys/user.h> 44 #include <sys/proc.h> 45 #include <sys/ioctl.h> 46 #include <sys/stat.h> 47 #include <sys/sysctl.h> 48 49 #include <vm/vm.h> 50 #include <vm/vm_param.h> 51 #include <vm/swap_pager.h> 52 53 #include <machine/vmparam.h> 54 55 #include <ctype.h> 56 #include <db.h> 57 #include <fcntl.h> 58 #include <kvm.h> 59 #include <limits.h> 60 #include <nlist.h> 61 #include <paths.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include "kvm_private.h" 68 69 static int kvm_dbopen __P((kvm_t *, const char *)); 70 static kvm_t *_kvm_open __P((kvm_t *, const char *, const char *, 71 const char *, int, char *)); 72 73 char * 74 kvm_geterr(kd) 75 kvm_t *kd; 76 { 77 return (kd->errbuf); 78 } 79 80 #if __STDC__ 81 #include <stdarg.h> 82 #else 83 #include <varargs.h> 84 #endif 85 86 /* 87 * Report an error using printf style arguments. "program" is kd->program 88 * on hard errors, and 0 on soft errors, so that under sun error emulation, 89 * only hard errors are printed out (otherwise, programs like gdb will 90 * generate tons of error messages when trying to access bogus pointers). 91 */ 92 void 93 #if __STDC__ 94 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 95 #else 96 _kvm_err(kd, program, fmt, va_alist) 97 kvm_t *kd; 98 char *program, *fmt; 99 va_dcl 100 #endif 101 { 102 va_list ap; 103 104 #ifdef __STDC__ 105 va_start(ap, fmt); 106 #else 107 va_start(ap); 108 #endif 109 if (program != NULL) { 110 (void)fprintf(stderr, "%s: ", program); 111 (void)vfprintf(stderr, fmt, ap); 112 (void)fputc('\n', stderr); 113 } else 114 (void)vsnprintf(kd->errbuf, 115 sizeof(kd->errbuf), (char *)fmt, ap); 116 117 va_end(ap); 118 } 119 120 void 121 #if __STDC__ 122 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 123 #else 124 _kvm_syserr(kd, program, fmt, va_alist) 125 kvm_t *kd; 126 char *program, *fmt; 127 va_dcl 128 #endif 129 { 130 va_list ap; 131 register int n; 132 133 #if __STDC__ 134 va_start(ap, fmt); 135 #else 136 va_start(ap); 137 #endif 138 if (program != NULL) { 139 (void)fprintf(stderr, "%s: ", program); 140 (void)vfprintf(stderr, fmt, ap); 141 (void)fprintf(stderr, ": %s\n", strerror(errno)); 142 } else { 143 register char *cp = kd->errbuf; 144 145 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 146 n = strlen(cp); 147 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 148 strerror(errno)); 149 } 150 va_end(ap); 151 } 152 153 void * 154 _kvm_malloc(kd, n) 155 register kvm_t *kd; 156 register size_t n; 157 { 158 void *p; 159 160 if ((p = malloc(n)) == NULL) 161 _kvm_err(kd, kd->program, strerror(errno)); 162 return (p); 163 } 164 165 static kvm_t * 166 _kvm_open(kd, uf, mf, sf, flag, errout) 167 register kvm_t *kd; 168 const char *uf; 169 const char *mf; 170 const char *sf; 171 int flag; 172 char *errout; 173 { 174 struct stat st; 175 176 kd->db = 0; 177 kd->pmfd = -1; 178 kd->vmfd = -1; 179 kd->swfd = -1; 180 kd->nlfd = -1; 181 kd->procbase = 0; 182 kd->nbpg = getpagesize(); 183 kd->swapspc = 0; 184 kd->argspc = 0; 185 kd->argbuf = 0; 186 kd->argv = 0; 187 kd->vmst = 0; 188 kd->vm_page_buckets = 0; 189 190 if (uf == 0) 191 uf = _PATH_UNIX; 192 else if (strlen(uf) >= MAXPATHLEN) { 193 _kvm_err(kd, kd->program, "exec file name too long"); 194 goto failed; 195 } 196 if (flag & ~O_RDWR) { 197 _kvm_err(kd, kd->program, "bad flags arg"); 198 goto failed; 199 } 200 if (mf == 0) 201 mf = _PATH_MEM; 202 if (sf == 0) 203 sf = _PATH_DRUM; 204 205 if ((kd->pmfd = open(mf, flag, 0)) < 0) { 206 _kvm_syserr(kd, kd->program, "%s", mf); 207 goto failed; 208 } 209 if (fstat(kd->pmfd, &st) < 0) { 210 _kvm_syserr(kd, kd->program, "%s", mf); 211 goto failed; 212 } 213 if (S_ISCHR(st.st_mode)) { 214 /* 215 * If this is a character special device, then check that 216 * it's /dev/mem. If so, open kmem too. (Maybe we should 217 * make it work for either /dev/mem or /dev/kmem -- in either 218 * case you're working with a live kernel.) 219 */ 220 if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */ 221 _kvm_err(kd, kd->program, 222 "%s: not physical memory device", mf); 223 goto failed; 224 } 225 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 226 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 227 goto failed; 228 } 229 if ((kd->swfd = open(sf, flag, 0)) < 0) { 230 _kvm_syserr(kd, kd->program, "%s", sf); 231 goto failed; 232 } 233 /* 234 * Open kvm nlist database. We go ahead and do this 235 * here so that we don't have to hold on to the vmunix 236 * path name. Since a kvm application will surely do 237 * a kvm_nlist(), this probably won't be a wasted effort. 238 * If the database cannot be opened, open the namelist 239 * argument so we revert to slow nlist() calls. 240 */ 241 if (kvm_dbopen(kd, uf) < 0 && 242 (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 243 _kvm_syserr(kd, kd->program, "%s", uf); 244 goto failed; 245 } 246 } else { 247 /* 248 * This is a crash dump. 249 * Initalize the virtual address translation machinery, 250 * but first setup the namelist fd. 251 */ 252 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 253 _kvm_syserr(kd, kd->program, "%s", uf); 254 goto failed; 255 } 256 if (_kvm_initvtop(kd) < 0) 257 goto failed; 258 } 259 return (kd); 260 failed: 261 /* 262 * Copy out the error if doing sane error semantics. 263 */ 264 if (errout != 0) 265 strcpy(errout, kd->errbuf); 266 (void)kvm_close(kd); 267 return (0); 268 } 269 270 kvm_t * 271 kvm_openfiles(uf, mf, sf, flag, errout) 272 const char *uf; 273 const char *mf; 274 const char *sf; 275 int flag; 276 char *errout; 277 { 278 register kvm_t *kd; 279 280 if ((kd = malloc(sizeof(*kd))) == NULL) { 281 (void)strcpy(errout, strerror(errno)); 282 return (0); 283 } 284 kd->program = 0; 285 return (_kvm_open(kd, uf, mf, sf, flag, errout)); 286 } 287 288 kvm_t * 289 kvm_open(uf, mf, sf, flag, program) 290 const char *uf; 291 const char *mf; 292 const char *sf; 293 int flag; 294 const char *program; 295 { 296 register kvm_t *kd; 297 298 if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) { 299 (void)fprintf(stderr, "%s: %s\n", strerror(errno)); 300 return (0); 301 } 302 kd->program = program; 303 return (_kvm_open(kd, uf, mf, sf, flag, NULL)); 304 } 305 306 int 307 kvm_close(kd) 308 kvm_t *kd; 309 { 310 register int error = 0; 311 312 if (kd->pmfd >= 0) 313 error |= close(kd->pmfd); 314 if (kd->vmfd >= 0) 315 error |= close(kd->vmfd); 316 if (kd->nlfd >= 0) 317 error |= close(kd->nlfd); 318 if (kd->swfd >= 0) 319 error |= close(kd->swfd); 320 if (kd->db != 0) 321 error |= (kd->db->close)(kd->db); 322 if (kd->vmst) 323 _kvm_freevtop(kd); 324 if (kd->procbase != 0) 325 free((void *)kd->procbase); 326 if (kd->swapspc != 0) 327 free((void *)kd->swapspc); 328 if (kd->argspc != 0) 329 free((void *)kd->argspc); 330 if (kd->argbuf != 0) 331 free((void *)kd->argbuf); 332 if (kd->argv != 0) 333 free((void *)kd->argv); 334 free((void *)kd); 335 336 return (0); 337 } 338 339 /* 340 * Set up state necessary to do queries on the kernel namelist 341 * data base. If the data base is out-of-data/incompatible with 342 * given executable, set up things so we revert to standard nlist call. 343 * Only called for live kernels. Return 0 on success, -1 on failure. 344 */ 345 static int 346 kvm_dbopen(kd, uf) 347 kvm_t *kd; 348 const char *uf; 349 { 350 char *cp; 351 DBT rec; 352 int dbversionlen; 353 struct nlist nitem; 354 char dbversion[_POSIX2_LINE_MAX]; 355 char kversion[_POSIX2_LINE_MAX]; 356 char dbname[MAXPATHLEN]; 357 358 if ((cp = rindex(uf, '/')) != 0) 359 uf = cp + 1; 360 361 (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); 362 kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); 363 if (kd->db == 0) 364 return (-1); 365 /* 366 * read version out of database 367 */ 368 rec.data = VRS_KEY; 369 rec.size = sizeof(VRS_KEY) - 1; 370 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 371 goto close; 372 if (rec.data == 0 || rec.size > sizeof(dbversion)) 373 goto close; 374 375 bcopy(rec.data, dbversion, rec.size); 376 dbversionlen = rec.size; 377 /* 378 * Read version string from kernel memory. 379 * Since we are dealing with a live kernel, we can call kvm_read() 380 * at this point. 381 */ 382 rec.data = VRS_SYM; 383 rec.size = sizeof(VRS_SYM) - 1; 384 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 385 goto close; 386 if (rec.data == 0 || rec.size != sizeof(struct nlist)) 387 goto close; 388 bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem)); 389 if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) != 390 dbversionlen) 391 goto close; 392 /* 393 * If they match, we win - otherwise clear out kd->db so 394 * we revert to slow nlist(). 395 */ 396 if (bcmp(dbversion, kversion, dbversionlen) == 0) 397 return (0); 398 close: 399 (void)(kd->db->close)(kd->db); 400 kd->db = 0; 401 402 return (-1); 403 } 404 405 int 406 kvm_nlist(kd, nl) 407 kvm_t *kd; 408 struct nlist *nl; 409 { 410 register struct nlist *p; 411 register int nvalid; 412 413 /* 414 * If we can't use the data base, revert to the 415 * slow library call. 416 */ 417 if (kd->db == 0) 418 return (__fdnlist(kd->nlfd, nl)); 419 420 /* 421 * We can use the kvm data base. Go through each nlist entry 422 * and look it up with a db query. 423 */ 424 nvalid = 0; 425 for (p = nl; p->n_name && p->n_name[0]; ++p) { 426 register int len; 427 DBT rec; 428 429 if ((len = strlen(p->n_name)) > 4096) { 430 /* sanity */ 431 _kvm_err(kd, kd->program, "symbol too large"); 432 return (-1); 433 } 434 rec.data = p->n_name; 435 rec.size = len; 436 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 437 continue; 438 if (rec.data == 0 || rec.size != sizeof(struct nlist)) 439 continue; 440 ++nvalid; 441 /* 442 * Avoid alignment issues. 443 */ 444 bcopy((char *)&((struct nlist *)rec.data)->n_type, 445 (char *)&p->n_type, 446 sizeof(p->n_type)); 447 bcopy((char *)&((struct nlist *)rec.data)->n_value, 448 (char *)&p->n_value, 449 sizeof(p->n_value)); 450 } 451 /* 452 * Return the number of entries that weren't found. 453 */ 454 return ((p - nl) - nvalid); 455 } 456 457 ssize_t 458 kvm_read(kd, kva, buf, len) 459 kvm_t *kd; 460 register u_long kva; 461 register void *buf; 462 register size_t len; 463 { 464 register int cc; 465 register void *cp; 466 467 if (ISALIVE(kd)) { 468 /* 469 * We're using /dev/kmem. Just read straight from the 470 * device and let the active kernel do the address translation. 471 */ 472 errno = 0; 473 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 474 _kvm_err(kd, 0, "invalid address (%x)", kva); 475 return (0); 476 } 477 cc = read(kd->vmfd, buf, len); 478 if (cc < 0) { 479 _kvm_syserr(kd, 0, "kvm_read"); 480 return (0); 481 } else if (cc < len) 482 _kvm_err(kd, kd->program, "short read"); 483 return (cc); 484 } else { 485 cp = buf; 486 while (len > 0) { 487 u_long pa; 488 489 cc = _kvm_kvatop(kd, kva, &pa); 490 if (cc == 0) 491 return (0); 492 if (cc > len) 493 cc = len; 494 errno = 0; 495 if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 496 _kvm_syserr(kd, 0, _PATH_MEM); 497 break; 498 } 499 cc = read(kd->pmfd, cp, cc); 500 if (cc < 0) { 501 _kvm_syserr(kd, kd->program, "kvm_read"); 502 break; 503 } 504 /* 505 * If kvm_kvatop returns a bogus value or our core 506 * file is truncated, we might wind up seeking beyond 507 * the end of the core file in which case the read will 508 * return 0 (EOF). 509 */ 510 if (cc == 0) 511 break; 512 cp = (char *)cp + cc; 513 kva += cc; 514 len -= cc; 515 } 516 return ((char *)cp - (char *)buf); 517 } 518 /* NOTREACHED */ 519 } 520 521 ssize_t 522 kvm_write(kd, kva, buf, len) 523 kvm_t *kd; 524 register u_long kva; 525 register const void *buf; 526 register size_t len; 527 { 528 register int cc; 529 530 if (ISALIVE(kd)) { 531 /* 532 * Just like kvm_read, only we write. 533 */ 534 errno = 0; 535 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 536 _kvm_err(kd, 0, "invalid address (%x)", kva); 537 return (0); 538 } 539 cc = write(kd->vmfd, buf, len); 540 if (cc < 0) { 541 _kvm_syserr(kd, 0, "kvm_write"); 542 return (0); 543 } else if (cc < len) 544 _kvm_err(kd, kd->program, "short write"); 545 return (cc); 546 } else { 547 _kvm_err(kd, kd->program, 548 "kvm_write not implemented for dead kernels"); 549 return (0); 550 } 551 /* NOTREACHED */ 552 } 553