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