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 71 char * 72 kvm_geterr(kd) 73 kvm_t *kd; 74 { 75 return (kd->errbuf); 76 } 77 78 #if __STDC__ 79 #include <stdarg.h> 80 #else 81 #include <varargs.h> 82 #endif 83 84 /* 85 * Report an error using printf style arguments. "program" is kd->program 86 * on hard errors, and 0 on soft errors, so that under sun error emulation, 87 * only hard errors are printed out (otherwise, programs like gdb will 88 * generate tons of error messages when trying to access bogus pointers). 89 */ 90 void 91 #if __STDC__ 92 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 93 #else 94 _kvm_err(kd, program, fmt, va_alist) 95 kvm_t *kd; 96 char *program, *fmt; 97 va_dcl 98 #endif 99 { 100 va_list ap; 101 102 #ifdef __STDC__ 103 va_start(ap, fmt); 104 #else 105 va_start(ap); 106 #endif 107 if (program != NULL) { 108 (void)fprintf(stderr, "%s: ", program); 109 (void)vfprintf(stderr, fmt, ap); 110 (void)fputc('\n', stderr); 111 } else 112 (void)vsnprintf(kd->errbuf, 113 sizeof(kd->errbuf), (char *)fmt, ap); 114 115 va_end(ap); 116 } 117 118 void 119 #if __STDC__ 120 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 121 #else 122 _kvm_syserr(kd, program, fmt, va_alist) 123 kvm_t *kd; 124 char *program, *fmt; 125 va_dcl 126 #endif 127 { 128 va_list ap; 129 register int n; 130 131 #if __STDC__ 132 va_start(ap, fmt); 133 #else 134 va_start(ap); 135 #endif 136 if (program != NULL) { 137 (void)fprintf(stderr, "%s: ", program); 138 (void)vfprintf(stderr, fmt, ap); 139 (void)fprintf(stderr, ": %s\n", strerror(errno)); 140 } else { 141 register char *cp = kd->errbuf; 142 143 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 144 n = strlen(cp); 145 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 146 strerror(errno)); 147 } 148 va_end(ap); 149 } 150 151 void * 152 _kvm_malloc(kd, n) 153 register kvm_t *kd; 154 register size_t n; 155 { 156 void *p; 157 158 if ((p = malloc(n)) == NULL) 159 _kvm_err(kd, kd->program, strerror(errno)); 160 return (p); 161 } 162 163 static kvm_t * 164 _kvm_open(kd, uf, mf, sf, flag, errout) 165 register kvm_t *kd; 166 const char *uf; 167 const char *mf; 168 const char *sf; 169 int flag; 170 char *errout; 171 { 172 struct stat st; 173 174 kd->db = 0; 175 kd->pmfd = -1; 176 kd->vmfd = -1; 177 kd->swfd = -1; 178 kd->nlfd = -1; 179 kd->procbase = 0; 180 kd->nbpg = getpagesize(); 181 kd->swapspc = 0; 182 kd->argspc = 0; 183 kd->argv = 0; 184 kd->vmst = 0; 185 kd->vm_page_buckets = 0; 186 187 if (uf == 0) 188 uf = _PATH_UNIX; 189 else if (strlen(uf) >= MAXPATHLEN) { 190 _kvm_err(kd, kd->program, "exec file name too long"); 191 goto failed; 192 } 193 if (flag & ~O_RDWR) { 194 _kvm_err(kd, kd->program, "bad flags arg"); 195 goto failed; 196 } 197 if (mf == 0) 198 mf = _PATH_MEM; 199 if (sf == 0) 200 sf = _PATH_DRUM; 201 202 if ((kd->pmfd = open(mf, flag, 0)) < 0) { 203 _kvm_syserr(kd, kd->program, "%s", mf); 204 goto failed; 205 } 206 if (fstat(kd->pmfd, &st) < 0) { 207 _kvm_syserr(kd, kd->program, "%s", mf); 208 goto failed; 209 } 210 if (S_ISCHR(st.st_mode)) { 211 /* 212 * If this is a character special device, then check that 213 * it's /dev/mem. If so, open kmem too. (Maybe we should 214 * make it work for either /dev/mem or /dev/kmem -- in either 215 * case you're working with a live kernel.) 216 */ 217 if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */ 218 _kvm_err(kd, kd->program, 219 "%s: not physical memory device", mf); 220 goto failed; 221 } 222 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 223 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 224 goto failed; 225 } 226 if ((kd->swfd = open(sf, flag, 0)) < 0) { 227 _kvm_syserr(kd, kd->program, "%s", sf); 228 goto failed; 229 } 230 /* 231 * Open kvm nlist database. We go ahead and do this 232 * here so that we don't have to hold on to the vmunix 233 * path name. Since a kvm application will surely do 234 * a kvm_nlist(), this probably won't be a wasted effort. 235 * If the database cannot be opened, open the namelist 236 * argument so we revert to slow nlist() calls. 237 */ 238 if (kvm_dbopen(kd, uf) < 0 && 239 (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 240 _kvm_syserr(kd, kd->program, "%s", uf); 241 goto failed; 242 } 243 } else { 244 /* 245 * This is a crash dump. 246 * Initalize the virtual address translation machinery, 247 * but first setup the namelist fd. 248 */ 249 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 250 _kvm_syserr(kd, kd->program, "%s", uf); 251 goto failed; 252 } 253 if (_kvm_initvtop(kd) < 0) 254 goto failed; 255 } 256 return (kd); 257 failed: 258 /* 259 * Copy out the error if doing sane error semantics. 260 */ 261 if (errout != 0) 262 strcpy(errout, kd->errbuf); 263 (void)kvm_close(kd); 264 return (0); 265 } 266 267 kvm_t * 268 kvm_openfiles(uf, mf, sf, flag, errout) 269 const char *uf; 270 const char *mf; 271 const char *sf; 272 int flag; 273 char *errout; 274 { 275 register kvm_t *kd; 276 277 if ((kd = malloc(sizeof(*kd))) == NULL) { 278 (void)strcpy(errout, strerror(errno)); 279 return (0); 280 } 281 kd->program = 0; 282 return (_kvm_open(kd, uf, mf, sf, flag, errout)); 283 } 284 285 kvm_t * 286 kvm_open(uf, mf, sf, flag, program) 287 const char *uf; 288 const char *mf; 289 const char *sf; 290 int flag; 291 const char *program; 292 { 293 register kvm_t *kd; 294 295 if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) { 296 (void)fprintf(stderr, "%s: %s\n", strerror(errno)); 297 return (0); 298 } 299 kd->program = program; 300 return (_kvm_open(kd, uf, mf, sf, flag, NULL)); 301 } 302 303 int 304 kvm_close(kd) 305 kvm_t *kd; 306 { 307 register int error = 0; 308 309 if (kd->pmfd >= 0) 310 error |= close(kd->pmfd); 311 if (kd->vmfd >= 0) 312 error |= close(kd->vmfd); 313 if (kd->nlfd >= 0) 314 error |= close(kd->nlfd); 315 if (kd->swfd >= 0) 316 error |= close(kd->swfd); 317 if (kd->db != 0) 318 error |= (kd->db->close)(kd->db); 319 if (kd->vmst) 320 _kvm_freevtop(kd); 321 if (kd->procbase != 0) 322 free((void *)kd->procbase); 323 if (kd->swapspc != 0) 324 free((void *)kd->swapspc); 325 if (kd->argspc != 0) 326 free((void *)kd->argspc); 327 if (kd->argv != 0) 328 free((void *)kd->argv); 329 free((void *)kd); 330 331 return (0); 332 } 333 334 /* 335 * Set up state necessary to do queries on the kernel namelist 336 * data base. If the data base is out-of-data/incompatible with 337 * given executable, set up things so we revert to standard nlist call. 338 * Only called for live kernels. Return 0 on success, -1 on failure. 339 */ 340 static int 341 kvm_dbopen(kd, uf) 342 kvm_t *kd; 343 const char *uf; 344 { 345 char *cp; 346 DBT rec; 347 int dbversionlen; 348 struct nlist nitem; 349 char dbversion[_POSIX2_LINE_MAX]; 350 char kversion[_POSIX2_LINE_MAX]; 351 char dbname[MAXPATHLEN]; 352 353 if ((cp = rindex(uf, '/')) != 0) 354 uf = cp + 1; 355 356 (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); 357 kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); 358 if (kd->db == 0) 359 return (-1); 360 /* 361 * read version out of database 362 */ 363 rec.data = VRS_KEY; 364 rec.size = sizeof(VRS_KEY) - 1; 365 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 366 goto close; 367 if (rec.data == 0 || rec.size > sizeof(dbversion)) 368 goto close; 369 370 bcopy(rec.data, dbversion, rec.size); 371 dbversionlen = rec.size; 372 /* 373 * Read version string from kernel memory. 374 * Since we are dealing with a live kernel, we can call kvm_read() 375 * at this point. 376 */ 377 rec.data = VRS_SYM; 378 rec.size = sizeof(VRS_SYM) - 1; 379 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 380 goto close; 381 if (rec.data == 0 || rec.size != sizeof(struct nlist)) 382 goto close; 383 bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem)); 384 if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) != 385 dbversionlen) 386 goto close; 387 /* 388 * If they match, we win - otherwise clear out kd->db so 389 * we revert to slow nlist(). 390 */ 391 if (bcmp(dbversion, kversion, dbversionlen) == 0) 392 return (0); 393 close: 394 (void)(kd->db->close)(kd->db); 395 kd->db = 0; 396 397 return (-1); 398 } 399 400 int 401 kvm_nlist(kd, nl) 402 kvm_t *kd; 403 struct nlist *nl; 404 { 405 register struct nlist *p; 406 register int nvalid; 407 408 /* 409 * If we can't use the data base, revert to the 410 * slow library call. 411 */ 412 if (kd->db == 0) 413 return (__fdnlist(kd->nlfd, nl)); 414 415 /* 416 * We can use the kvm data base. Go through each nlist entry 417 * and look it up with a db query. 418 */ 419 nvalid = 0; 420 for (p = nl; p->n_name && p->n_name[0]; ++p) { 421 register int len; 422 DBT rec; 423 424 if ((len = strlen(p->n_name)) > 4096) { 425 /* sanity */ 426 _kvm_err(kd, kd->program, "symbol too large"); 427 return (-1); 428 } 429 rec.data = p->n_name; 430 rec.size = len; 431 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 432 continue; 433 if (rec.data == 0 || rec.size != sizeof(struct nlist)) 434 continue; 435 ++nvalid; 436 /* 437 * Avoid alignment issues. 438 */ 439 bcopy((char *)&((struct nlist *)rec.data)->n_type, 440 (char *)&p->n_type, 441 sizeof(p->n_type)); 442 bcopy((char *)&((struct nlist *)rec.data)->n_value, 443 (char *)&p->n_value, 444 sizeof(p->n_value)); 445 } 446 /* 447 * Return the number of entries that weren't found. 448 */ 449 return ((p - nl) - nvalid); 450 } 451 452 ssize_t 453 kvm_read(kd, kva, buf, len) 454 kvm_t *kd; 455 register u_long kva; 456 register void *buf; 457 register size_t len; 458 { 459 register int cc; 460 register void *cp; 461 462 if (ISALIVE(kd)) { 463 /* 464 * We're using /dev/kmem. Just read straight from the 465 * device and let the active kernel do the address translation. 466 */ 467 errno = 0; 468 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 469 _kvm_err(kd, 0, "invalid address (%x)", kva); 470 return (0); 471 } 472 cc = read(kd->vmfd, buf, len); 473 if (cc < 0) { 474 _kvm_syserr(kd, 0, "kvm_read"); 475 return (0); 476 } else if (cc < len) 477 _kvm_err(kd, kd->program, "short read"); 478 return (cc); 479 } else { 480 cp = buf; 481 while (len > 0) { 482 u_long pa; 483 484 cc = _kvm_kvatop(kd, kva, &pa); 485 if (cc == 0) 486 return (0); 487 if (cc > len) 488 cc = len; 489 errno = 0; 490 if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 491 _kvm_syserr(kd, 0, _PATH_MEM); 492 break; 493 } 494 cc = read(kd->pmfd, cp, cc); 495 if (cc < 0) { 496 _kvm_syserr(kd, kd->program, "kvm_read"); 497 break; 498 } 499 /* 500 * If kvm_kvatop returns a bogus value or our core 501 * file is truncated, we might wind up seeking beyond 502 * the end of the core file in which case the read will 503 * return 0 (EOF). 504 */ 505 if (cc == 0) 506 break; 507 (char *)cp += cc; 508 kva += cc; 509 len -= cc; 510 } 511 return ((char *)cp - (char *)buf); 512 } 513 /* NOTREACHED */ 514 } 515 516 ssize_t 517 kvm_write(kd, kva, buf, len) 518 kvm_t *kd; 519 register u_long kva; 520 register const void *buf; 521 register size_t len; 522 { 523 register int cc; 524 525 if (ISALIVE(kd)) { 526 /* 527 * Just like kvm_read, only we write. 528 */ 529 errno = 0; 530 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 531 _kvm_err(kd, 0, "invalid address (%x)", kva); 532 return (0); 533 } 534 cc = write(kd->vmfd, buf, len); 535 if (cc < 0) { 536 _kvm_syserr(kd, 0, "kvm_write"); 537 return (0); 538 } else if (cc < len) 539 _kvm_err(kd, kd->program, "short write"); 540 return (cc); 541 } else { 542 _kvm_err(kd, kd->program, 543 "kvm_write not implemented for dead kernels"); 544 return (0); 545 } 546 /* NOTREACHED */ 547 } 548