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