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