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