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 * $DragonFly: src/lib/libkvm/kvm.c,v 1.3 2003/11/12 20:21:30 eirikn Exp $ 40 */ 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 #include <sys/linker.h> 49 50 #include <vm/vm.h> 51 #include <vm/vm_param.h> 52 #include <vm/swap_pager.h> 53 54 #include <machine/vmparam.h> 55 56 #include <ctype.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 /* from src/lib/libc/gen/nlist.c */ 70 int __fdnlist (int, struct nlist *); 71 72 char * 73 kvm_geterr(kd) 74 kvm_t *kd; 75 { 76 return (kd->errbuf); 77 } 78 79 #if __STDC__ 80 #include <stdarg.h> 81 #else 82 #include <varargs.h> 83 #endif 84 85 /* 86 * Report an error using printf style arguments. "program" is kd->program 87 * on hard errors, and 0 on soft errors, so that under sun error emulation, 88 * only hard errors are printed out (otherwise, programs like gdb will 89 * generate tons of error messages when trying to access bogus pointers). 90 */ 91 void 92 #if __STDC__ 93 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 94 #else 95 _kvm_err(kd, program, fmt, va_alist) 96 kvm_t *kd; 97 char *program, *fmt; 98 va_dcl 99 #endif 100 { 101 va_list ap; 102 103 #ifdef __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)fputc('\n', stderr); 112 } else 113 (void)vsnprintf(kd->errbuf, 114 sizeof(kd->errbuf), (char *)fmt, ap); 115 116 va_end(ap); 117 } 118 119 void 120 #if __STDC__ 121 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 122 #else 123 _kvm_syserr(kd, program, fmt, va_alist) 124 kvm_t *kd; 125 char *program, *fmt; 126 va_dcl 127 #endif 128 { 129 va_list ap; 130 register int n; 131 132 #if __STDC__ 133 va_start(ap, fmt); 134 #else 135 va_start(ap); 136 #endif 137 if (program != NULL) { 138 (void)fprintf(stderr, "%s: ", program); 139 (void)vfprintf(stderr, fmt, ap); 140 (void)fprintf(stderr, ": %s\n", strerror(errno)); 141 } else { 142 register char *cp = kd->errbuf; 143 144 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 145 n = strlen(cp); 146 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 147 strerror(errno)); 148 } 149 va_end(ap); 150 } 151 152 void * 153 _kvm_malloc(kd, n) 154 register kvm_t *kd; 155 register size_t n; 156 { 157 void *p; 158 159 if ((p = calloc(n, sizeof(char))) == NULL) 160 _kvm_err(kd, kd->program, "can't allocate %u bytes: %s", 161 n, strerror(errno)); 162 return (p); 163 } 164 165 static kvm_t * 166 _kvm_open(kd, uf, mf, flag, errout) 167 register kvm_t *kd; 168 const char *uf; 169 const char *mf; 170 int flag; 171 char *errout; 172 { 173 struct stat st; 174 175 kd->vmfd = -1; 176 kd->pmfd = -1; 177 kd->nlfd = -1; 178 kd->vmst = 0; 179 kd->procbase = 0; 180 kd->argspc = 0; 181 kd->argv = 0; 182 183 if (uf == 0) 184 uf = getbootfile(); 185 else if (strlen(uf) >= MAXPATHLEN) { 186 _kvm_err(kd, kd->program, "exec file name too long"); 187 goto failed; 188 } 189 if (flag & ~O_RDWR) { 190 _kvm_err(kd, kd->program, "bad flags arg"); 191 goto failed; 192 } 193 if (mf == 0) 194 mf = _PATH_MEM; 195 196 if ((kd->pmfd = open(mf, flag, 0)) < 0) { 197 _kvm_syserr(kd, kd->program, "%s", mf); 198 goto failed; 199 } 200 if (fstat(kd->pmfd, &st) < 0) { 201 _kvm_syserr(kd, kd->program, "%s", mf); 202 goto failed; 203 } 204 if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) { 205 _kvm_syserr(kd, kd->program, "%s", mf); 206 goto failed; 207 } 208 if (S_ISCHR(st.st_mode)) { 209 /* 210 * If this is a character special device, then check that 211 * it's /dev/mem. If so, open kmem too. (Maybe we should 212 * make it work for either /dev/mem or /dev/kmem -- in either 213 * case you're working with a live kernel.) 214 */ 215 if (strcmp(mf, _PATH_DEVNULL) == 0) { 216 kd->vmfd = open(_PATH_DEVNULL, O_RDONLY); 217 } else if (strcmp(mf, _PATH_MEM) != 0) { 218 _kvm_err(kd, kd->program, 219 "%s: not physical memory device", mf); 220 goto failed; 221 } else { 222 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 223 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 224 goto failed; 225 } 226 if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) { 227 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 228 goto failed; 229 } 230 } 231 } else { 232 /* 233 * This is a crash dump. 234 * Initialize the virtual address translation machinery, 235 * but first setup the namelist fd. 236 */ 237 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 238 _kvm_syserr(kd, kd->program, "%s", uf); 239 goto failed; 240 } 241 if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) { 242 _kvm_syserr(kd, kd->program, "%s", uf); 243 goto failed; 244 } 245 if (_kvm_initvtop(kd) < 0) 246 goto failed; 247 } 248 return (kd); 249 failed: 250 /* 251 * Copy out the error if doing sane error semantics. 252 */ 253 if (errout != 0) 254 strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 255 (void)kvm_close(kd); 256 return (0); 257 } 258 259 kvm_t * 260 kvm_openfiles(uf, mf, sf, flag, errout) 261 const char *uf; 262 const char *mf; 263 const char *sf; 264 int flag; 265 char *errout; 266 { 267 register kvm_t *kd; 268 269 if ((kd = malloc(sizeof(*kd))) == NULL) { 270 (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 271 return (0); 272 } 273 memset(kd, 0, sizeof(*kd)); 274 kd->program = 0; 275 return (_kvm_open(kd, uf, mf, flag, errout)); 276 } 277 278 kvm_t * 279 kvm_open(uf, mf, sf, flag, errstr) 280 const char *uf; 281 const char *mf; 282 const char *sf; 283 int flag; 284 const char *errstr; 285 { 286 register kvm_t *kd; 287 288 if ((kd = malloc(sizeof(*kd))) == NULL) { 289 if (errstr != NULL) 290 (void)fprintf(stderr, "%s: %s\n", 291 errstr, strerror(errno)); 292 return (0); 293 } 294 memset(kd, 0, sizeof(*kd)); 295 kd->program = errstr; 296 return (_kvm_open(kd, uf, mf, flag, NULL)); 297 } 298 299 int 300 kvm_close(kd) 301 kvm_t *kd; 302 { 303 register int error = 0; 304 305 if (kd->pmfd >= 0) 306 error |= close(kd->pmfd); 307 if (kd->vmfd >= 0) 308 error |= close(kd->vmfd); 309 if (kd->nlfd >= 0) 310 error |= close(kd->nlfd); 311 if (kd->vmst) 312 _kvm_freevtop(kd); 313 if (kd->procbase != 0) 314 free((void *)kd->procbase); 315 if (kd->argv != 0) 316 free((void *)kd->argv); 317 free((void *)kd); 318 319 return (0); 320 } 321 322 int 323 kvm_nlist(kd, nl) 324 kvm_t *kd; 325 struct nlist *nl; 326 { 327 register struct nlist *p; 328 register int nvalid; 329 struct kld_sym_lookup lookup; 330 331 /* 332 * If we can't use the kld symbol lookup, revert to the 333 * slow library call. 334 */ 335 if (!ISALIVE(kd)) 336 return (__fdnlist(kd->nlfd, nl)); 337 338 /* 339 * We can use the kld lookup syscall. Go through each nlist entry 340 * and look it up with a kldsym(2) syscall. 341 */ 342 nvalid = 0; 343 for (p = nl; p->n_name && p->n_name[0]; ++p) { 344 lookup.version = sizeof(lookup); 345 lookup.symname = p->n_name; 346 lookup.symvalue = 0; 347 lookup.symsize = 0; 348 349 if (lookup.symname[0] == '_') 350 lookup.symname++; 351 352 if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 353 p->n_type = N_TEXT; 354 p->n_other = 0; 355 p->n_desc = 0; 356 p->n_value = lookup.symvalue; 357 ++nvalid; 358 /* lookup.symsize */ 359 } 360 } 361 /* 362 * Return the number of entries that weren't found. 363 */ 364 return ((p - nl) - nvalid); 365 } 366 367 ssize_t 368 kvm_read(kd, kva, buf, len) 369 kvm_t *kd; 370 register u_long kva; 371 register void *buf; 372 register size_t len; 373 { 374 register int cc; 375 register void *cp; 376 377 if (ISALIVE(kd)) { 378 /* 379 * We're using /dev/kmem. Just read straight from the 380 * device and let the active kernel do the address translation. 381 */ 382 errno = 0; 383 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 384 _kvm_err(kd, 0, "invalid address (%x)", kva); 385 return (-1); 386 } 387 cc = read(kd->vmfd, buf, len); 388 if (cc < 0) { 389 _kvm_syserr(kd, 0, "kvm_read"); 390 return (-1); 391 } else if (cc < len) 392 _kvm_err(kd, kd->program, "short read"); 393 return (cc); 394 } else { 395 cp = buf; 396 while (len > 0) { 397 u_long pa; 398 399 cc = _kvm_kvatop(kd, kva, &pa); 400 if (cc == 0) 401 return (-1); 402 if (cc > len) 403 cc = len; 404 errno = 0; 405 if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 406 _kvm_syserr(kd, 0, _PATH_MEM); 407 break; 408 } 409 cc = read(kd->pmfd, cp, cc); 410 if (cc < 0) { 411 _kvm_syserr(kd, kd->program, "kvm_read"); 412 break; 413 } 414 /* 415 * If kvm_kvatop returns a bogus value or our core 416 * file is truncated, we might wind up seeking beyond 417 * the end of the core file in which case the read will 418 * return 0 (EOF). 419 */ 420 if (cc == 0) 421 break; 422 (char *)cp += cc; 423 kva += cc; 424 len -= cc; 425 } 426 return ((char *)cp - (char *)buf); 427 } 428 /* NOTREACHED */ 429 } 430 431 ssize_t 432 kvm_write(kd, kva, buf, len) 433 kvm_t *kd; 434 register u_long kva; 435 register const void *buf; 436 register size_t len; 437 { 438 register int cc; 439 440 if (ISALIVE(kd)) { 441 /* 442 * Just like kvm_read, only we write. 443 */ 444 errno = 0; 445 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 446 _kvm_err(kd, 0, "invalid address (%x)", kva); 447 return (-1); 448 } 449 cc = write(kd->vmfd, buf, len); 450 if (cc < 0) { 451 _kvm_syserr(kd, 0, "kvm_write"); 452 return (-1); 453 } else if (cc < len) 454 _kvm_err(kd, kd->program, "short write"); 455 return (cc); 456 } else { 457 _kvm_err(kd, kd->program, 458 "kvm_write not implemented for dead kernels"); 459 return (-1); 460 } 461 /* NOTREACHED */ 462 } 463