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