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