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