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 * @(#)kvm.c 8.2 (Berkeley) 2/13/94 38 * $FreeBSD: src/lib/libkvm/kvm.c,v 1.12.2.3 2002/09/13 14:53:43 nectar Exp $ 39 */ 40 41 #include <sys/user.h> /* MUST BE FIRST */ 42 #include <sys/param.h> 43 #include <sys/proc.h> 44 #include <sys/ioctl.h> 45 #include <sys/stat.h> 46 #include <sys/sysctl.h> 47 #include <sys/linker.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 <fcntl.h> 57 #include <kvm.h> 58 #include <limits.h> 59 #include <nlist.h> 60 #include <paths.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <stdarg.h> 65 #include <unistd.h> 66 67 #include "kvm_private.h" 68 69 /* from src/lib/libc/gen/nlist.c */ 70 int __fdnlist (int, struct nlist *); 71 72 char * 73 kvm_geterr(kvm_t *kd) 74 { 75 return (kd->errbuf); 76 } 77 78 /* 79 * Report an error using printf style arguments. "program" is kd->program 80 * on hard errors, and 0 on soft errors, so that under sun error emulation, 81 * only hard errors are printed out (otherwise, programs like gdb will 82 * generate tons of error messages when trying to access bogus pointers). 83 */ 84 void 85 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 86 { 87 va_list ap; 88 89 va_start(ap, fmt); 90 if (program != NULL) { 91 (void)fprintf(stderr, "%s: ", program); 92 (void)vfprintf(stderr, fmt, ap); 93 (void)fputc('\n', stderr); 94 } else 95 (void)vsnprintf(kd->errbuf, 96 sizeof(kd->errbuf), (char *)fmt, ap); 97 98 va_end(ap); 99 } 100 101 void 102 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 103 { 104 va_list ap; 105 int n; 106 107 va_start(ap, fmt); 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 char *cp = kd->errbuf; 114 115 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 116 n = strlen(cp); 117 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 118 strerror(errno)); 119 } 120 va_end(ap); 121 } 122 123 void * 124 _kvm_malloc(kvm_t *kd, size_t n) 125 { 126 void *p; 127 128 if ((p = calloc(n, sizeof(char))) == NULL) 129 _kvm_err(kd, kd->program, "can't allocate %zd bytes: %s", 130 n, strerror(errno)); 131 return (p); 132 } 133 134 static int 135 is_proc_mem(const char *p) 136 { 137 static char proc[] = "/proc/"; 138 static char mem[] = "/mem"; 139 if (strncmp(proc, p, sizeof(proc) - 1)) 140 return 0; 141 p += sizeof(proc) - 1; 142 for (; p != '\0'; ++p) 143 if (!isdigit(*p)) 144 break; 145 if (!isdigit(*(p - 1))) 146 return 0; 147 return !strncmp(p, mem, sizeof(mem) - 1); 148 } 149 150 static kvm_t * 151 _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) 152 { 153 struct stat st; 154 155 kd->vmfd = -1; 156 kd->pmfd = -1; 157 kd->nlfd = -1; 158 kd->vmst = 0; 159 kd->procbase = NULL; 160 kd->procend = NULL; 161 kd->argspc = 0; 162 kd->argv = 0; 163 kd->flags = 0; 164 165 if (uf == NULL) 166 uf = getbootfile(); 167 else if (strlen(uf) >= MAXPATHLEN) { 168 _kvm_err(kd, kd->program, "exec file name too long"); 169 goto failed; 170 } 171 if (flag & ~O_RDWR) { 172 _kvm_err(kd, kd->program, "bad flags arg"); 173 goto failed; 174 } 175 if (mf == NULL) 176 mf = _PATH_MEM; 177 178 if ((kd->pmfd = open(mf, flag, 0)) < 0) { 179 _kvm_syserr(kd, kd->program, "%s", mf); 180 goto failed; 181 } 182 if (fstat(kd->pmfd, &st) < 0) { 183 _kvm_syserr(kd, kd->program, "%s", mf); 184 goto failed; 185 } 186 if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) { 187 _kvm_syserr(kd, kd->program, "%s", mf); 188 goto failed; 189 } 190 if (S_ISCHR(st.st_mode)) { 191 /* 192 * If this is a character special device, then check that 193 * it's /dev/mem. If so, open kmem too. (Maybe we should 194 * make it work for either /dev/mem or /dev/kmem -- in either 195 * case you're working with a live kernel.) 196 */ 197 if (strcmp(mf, _PATH_DEVNULL) == 0) { 198 kd->vmfd = open(_PATH_DEVNULL, O_RDONLY); 199 } else { 200 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 201 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 202 goto failed; 203 } 204 if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) { 205 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 206 goto failed; 207 } 208 } 209 kd->flags |= KVMF_HOST; 210 } else { 211 /* 212 * Crash dump or vkernel /proc/$pid/mem file: 213 * can't use kldsym, we are going to need ->nlfd 214 */ 215 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 216 _kvm_syserr(kd, kd->program, "%s", uf); 217 goto failed; 218 } 219 if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) { 220 _kvm_syserr(kd, kd->program, "%s", uf); 221 goto failed; 222 } 223 if(is_proc_mem(mf)) { 224 /* 225 * It's /proc/$pid/mem, so we rely on the host 226 * kernel to do address translation for us. 227 */ 228 kd->vmfd = kd->pmfd; 229 kd->pmfd = -1; 230 kd->flags |= KVMF_VKERN; 231 } else { 232 if (st.st_size <= 0) { 233 errno = EINVAL; 234 _kvm_syserr(kd, kd->program, "empty file"); 235 goto failed; 236 } 237 238 /* 239 * This is a crash dump. 240 * Initialize the virtual address translation machinery, 241 * but first setup the namelist fd. 242 */ 243 if (_kvm_initvtop(kd) < 0) 244 goto failed; 245 } 246 } 247 return (kd); 248 failed: 249 /* 250 * Copy out the error if doing sane error semantics. 251 */ 252 if (errout != NULL) 253 strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 254 (void)kvm_close(kd); 255 return (0); 256 } 257 258 kvm_t * 259 kvm_openfiles(const char *uf, const char *mf, const char *sf, int flag, 260 char *errout) 261 { 262 kvm_t *kd; 263 264 if ((kd = malloc(sizeof(*kd))) == NULL) { 265 (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 266 return (0); 267 } 268 memset(kd, 0, sizeof(*kd)); 269 kd->program = 0; 270 return (_kvm_open(kd, uf, mf, flag, errout)); 271 } 272 273 kvm_t * 274 kvm_open(const char *uf, const char *mf, const char *sf, int flag, 275 const char *errstr) 276 { 277 kvm_t *kd; 278 279 if ((kd = malloc(sizeof(*kd))) == NULL) { 280 if (errstr != NULL) 281 (void)fprintf(stderr, "%s: %s\n", 282 errstr, strerror(errno)); 283 return (0); 284 } 285 memset(kd, 0, sizeof(*kd)); 286 kd->program = errstr; 287 return (_kvm_open(kd, uf, mf, flag, NULL)); 288 } 289 290 int 291 kvm_close(kvm_t *kd) 292 { 293 int error = 0; 294 295 if (kd->pmfd >= 0) 296 error |= close(kd->pmfd); 297 if (kd->vmfd >= 0) 298 error |= close(kd->vmfd); 299 if (kd->nlfd >= 0) 300 error |= close(kd->nlfd); 301 if (kd->vmst) 302 _kvm_freevtop(kd); 303 if (kd->procbase != NULL) 304 free(kd->procbase); 305 if (kd->argv != 0) 306 free((void *)kd->argv); 307 free((void *)kd); 308 309 return (0); 310 } 311 312 int 313 kvm_nlist(kvm_t *kd, struct nlist *nl) 314 { 315 struct nlist *p; 316 int nvalid; 317 struct kld_sym_lookup lookup; 318 int error; 319 320 /* 321 * If we can't use the kld symbol lookup, revert to the 322 * slow library call. 323 */ 324 if (!kvm_ishost(kd)) 325 return (__fdnlist(kd->nlfd, nl)); 326 327 /* 328 * We can use the kld lookup syscall. Go through each nlist entry 329 * and look it up with a kldsym(2) syscall. 330 */ 331 nvalid = 0; 332 for (p = nl; p->n_name && p->n_name[0]; ++p) { 333 lookup.version = sizeof(lookup); 334 lookup.symname = p->n_name; 335 lookup.symvalue = 0; 336 lookup.symsize = 0; 337 338 if (lookup.symname[0] == '_') 339 lookup.symname++; 340 341 if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 342 p->n_type = N_TEXT; 343 p->n_other = 0; 344 p->n_desc = 0; 345 p->n_value = lookup.symvalue; 346 ++nvalid; 347 /* lookup.symsize */ 348 } 349 } 350 /* 351 * Return the number of entries that weren't found. If they exist, 352 * also fill internal error buffer. 353 */ 354 error = ((p - nl) - nvalid); 355 if (error) 356 _kvm_syserr(kd, kd->program, "kvm_nlist"); 357 return (error); 358 } 359 360 ssize_t 361 kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) 362 { 363 int cc; 364 void *cp; 365 366 if (kvm_notrans(kd)) { 367 /* 368 * We're using /dev/kmem. Just read straight from the 369 * device and let the active kernel do the address translation. 370 */ 371 errno = 0; 372 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 373 _kvm_err(kd, 0, "invalid address (%lx)", kva); 374 return (-1); 375 } 376 377 /* 378 * Try to pre-fault the user memory to reduce instances of 379 * races within the kernel. XXX workaround for kernel bug 380 * where kernel does a sanity check, but user faults during 381 * the copy can block and race against another kernel entity 382 * unmapping the memory in question. 383 */ 384 bzero(buf, len); 385 cc = read(kd->vmfd, buf, len); 386 if (cc < 0) { 387 _kvm_syserr(kd, 0, "kvm_read"); 388 return (-1); 389 } else if (cc < len) 390 _kvm_err(kd, kd->program, "short read"); 391 return (cc); 392 } else { 393 cp = buf; 394 while (len > 0) { 395 off_t pa; 396 397 cc = _kvm_kvatop(kd, kva, &pa); 398 if (cc == 0) 399 return (-1); 400 if (cc > len) 401 cc = len; 402 errno = 0; 403 if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 404 _kvm_syserr(kd, 0, _PATH_MEM); 405 break; 406 } 407 bzero(cp, cc); 408 cc = read(kd->pmfd, cp, cc); 409 if (cc < 0) { 410 _kvm_syserr(kd, kd->program, "kvm_read"); 411 break; 412 } 413 /* 414 * If kvm_kvatop returns a bogus value or our core 415 * file is truncated, we might wind up seeking beyond 416 * the end of the core file in which case the read will 417 * return 0 (EOF). 418 */ 419 if (cc == 0) 420 break; 421 cp = (char *)cp + cc; 422 kva += cc; 423 len -= cc; 424 } 425 return ((char *)cp - (char *)buf); 426 } 427 /* NOTREACHED */ 428 } 429 430 char * 431 kvm_readstr(kvm_t *kd, u_long kva, char *buf, size_t *lenp) 432 { 433 size_t len, cc, pos; 434 char ch; 435 int asize = -1; 436 437 if (buf == NULL) { 438 asize = len = 16; 439 buf = malloc(len); 440 if (buf == NULL) { 441 _kvm_syserr(kd, kd->program, "kvm_readstr"); 442 return NULL; 443 } 444 } else { 445 len = *lenp; 446 } 447 448 if (kvm_notrans(kd)) { 449 /* 450 * We're using /dev/kmem. Just read straight from the 451 * device and let the active kernel do the address translation. 452 */ 453 errno = 0; 454 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 455 _kvm_err(kd, 0, "invalid address (%lx)", kva); 456 return NULL; 457 } 458 459 for (pos = 0, ch = -1; ch != 0; pos++) { 460 cc = read(kd->vmfd, &ch, 1); 461 if ((ssize_t)cc < 0) { 462 _kvm_syserr(kd, 0, "kvm_readstr"); 463 return NULL; 464 } else if (cc < 1) 465 _kvm_err(kd, kd->program, "short read"); 466 if (pos == asize) { 467 buf = realloc(buf, asize *= 2); 468 if (buf == NULL) { 469 _kvm_syserr(kd, kd->program, "kvm_readstr"); 470 return NULL; 471 } 472 len = asize; 473 } 474 if (pos < len) 475 buf[pos] = ch; 476 } 477 478 if (lenp != NULL) 479 *lenp = pos; 480 if (pos > len) 481 return NULL; 482 else 483 return buf; 484 } else { 485 size_t left = 0; 486 for (pos = 0, ch = -1; ch != 0; pos++, left--, kva++) { 487 if (left == 0) { 488 off_t pa; 489 490 left = _kvm_kvatop(kd, kva, &pa); 491 if (left == 0) 492 return NULL; 493 errno = 0; 494 if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 495 _kvm_syserr(kd, 0, _PATH_MEM); 496 return NULL; 497 } 498 } 499 cc = read(kd->pmfd, &ch, 1); 500 if ((ssize_t)cc < 0) { 501 _kvm_syserr(kd, 0, "kvm_readstr"); 502 return NULL; 503 } else if (cc < 1) 504 _kvm_err(kd, kd->program, "short read"); 505 if (pos == asize) { 506 buf = realloc(buf, asize *= 2); 507 if (buf == NULL) { 508 _kvm_syserr(kd, kd->program, "kvm_readstr"); 509 return NULL; 510 } 511 len = asize; 512 } 513 if (pos < len) 514 buf[pos] = ch; 515 } 516 517 if (lenp != NULL) 518 *lenp = pos; 519 if (pos > len) 520 return NULL; 521 else 522 return buf; 523 } 524 /* NOTREACHED */ 525 } 526 527 ssize_t 528 kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) 529 { 530 int cc; 531 532 if (kvm_notrans(kd)) { 533 /* 534 * Just like kvm_read, only we write. 535 */ 536 errno = 0; 537 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 538 _kvm_err(kd, 0, "invalid address (%lx)", kva); 539 return (-1); 540 } 541 cc = write(kd->vmfd, buf, len); 542 if (cc < 0) { 543 _kvm_syserr(kd, 0, "kvm_write"); 544 return (-1); 545 } else if (cc < len) 546 _kvm_err(kd, kd->program, "short write"); 547 return (cc); 548 } else { 549 _kvm_err(kd, kd->program, 550 "kvm_write not implemented for dead kernels"); 551 return (-1); 552 } 553 /* NOTREACHED */ 554 } 555