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 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #if defined(LIBC_SCCS) && !defined(lint) 38 #if 0 39 static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 40 #endif 41 #endif /* LIBC_SCCS and not lint */ 42 43 #include <sys/param.h> 44 #include <sys/user.h> 45 #include <sys/proc.h> 46 #include <sys/ioctl.h> 47 #include <sys/stat.h> 48 #include <sys/sysctl.h> 49 #include <sys/linker.h> 50 51 #include <vm/vm.h> 52 #include <vm/vm_param.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 #include <stdarg.h> 80 81 /* 82 * Report an error using printf style arguments. "program" is kd->program 83 * on hard errors, and 0 on soft errors, so that under sun error emulation, 84 * only hard errors are printed out (otherwise, programs like gdb will 85 * generate tons of error messages when trying to access bogus pointers). 86 */ 87 void 88 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 89 { 90 va_list ap; 91 92 va_start(ap, fmt); 93 if (program != NULL) { 94 (void)fprintf(stderr, "%s: ", program); 95 (void)vfprintf(stderr, fmt, ap); 96 (void)fputc('\n', stderr); 97 } else 98 (void)vsnprintf(kd->errbuf, 99 sizeof(kd->errbuf), (char *)fmt, ap); 100 101 va_end(ap); 102 } 103 104 void 105 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 106 { 107 va_list ap; 108 int n; 109 110 va_start(ap, fmt); 111 if (program != NULL) { 112 (void)fprintf(stderr, "%s: ", program); 113 (void)vfprintf(stderr, fmt, ap); 114 (void)fprintf(stderr, ": %s\n", strerror(errno)); 115 } else { 116 char *cp = kd->errbuf; 117 118 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 119 n = strlen(cp); 120 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 121 strerror(errno)); 122 } 123 va_end(ap); 124 } 125 126 void * 127 _kvm_malloc(kd, n) 128 kvm_t *kd; 129 size_t n; 130 { 131 void *p; 132 133 if ((p = calloc(n, sizeof(char))) == NULL) 134 _kvm_err(kd, kd->program, "can't allocate %u bytes: %s", 135 n, strerror(errno)); 136 return (p); 137 } 138 139 static kvm_t * 140 _kvm_open(kd, uf, mf, flag, errout) 141 kvm_t *kd; 142 const char *uf; 143 const char *mf; 144 int flag; 145 char *errout; 146 { 147 struct stat st; 148 149 kd->vmfd = -1; 150 kd->pmfd = -1; 151 kd->nlfd = -1; 152 kd->vmst = 0; 153 kd->procbase = 0; 154 kd->argspc = 0; 155 kd->argv = 0; 156 157 if (uf == 0) 158 uf = getbootfile(); 159 else if (strlen(uf) >= MAXPATHLEN) { 160 _kvm_err(kd, kd->program, "exec file name too long"); 161 goto failed; 162 } 163 if (flag & ~O_RDWR) { 164 _kvm_err(kd, kd->program, "bad flags arg"); 165 goto failed; 166 } 167 if (mf == 0) 168 mf = _PATH_MEM; 169 170 if ((kd->pmfd = open(mf, flag, 0)) < 0) { 171 _kvm_syserr(kd, kd->program, "%s", mf); 172 goto failed; 173 } 174 if (fstat(kd->pmfd, &st) < 0) { 175 _kvm_syserr(kd, kd->program, "%s", mf); 176 goto failed; 177 } 178 if (S_ISREG(st.st_mode) && st.st_size <= 0) { 179 errno = EINVAL; 180 _kvm_syserr(kd, kd->program, "empty file"); 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 return (kd); 197 } else if (strcmp(mf, _PATH_MEM) == 0) { 198 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 199 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 200 goto failed; 201 } 202 if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) { 203 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 204 goto failed; 205 } 206 return (kd); 207 } 208 } 209 /* 210 * This is a crash dump. 211 * Initialize the virtual address translation machinery, 212 * but first setup the namelist fd. 213 */ 214 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 215 _kvm_syserr(kd, kd->program, "%s", uf); 216 goto failed; 217 } 218 if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) { 219 _kvm_syserr(kd, kd->program, "%s", uf); 220 goto failed; 221 } 222 if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0) 223 kd->rawdump = 1; 224 if (_kvm_initvtop(kd) < 0) 225 goto failed; 226 return (kd); 227 failed: 228 /* 229 * Copy out the error if doing sane error semantics. 230 */ 231 if (errout != 0) 232 strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 233 (void)kvm_close(kd); 234 return (0); 235 } 236 237 kvm_t * 238 kvm_openfiles(uf, mf, sf, flag, errout) 239 const char *uf; 240 const char *mf; 241 const char *sf __unused; 242 int flag; 243 char *errout; 244 { 245 kvm_t *kd; 246 247 if ((kd = calloc(1, sizeof(*kd))) == NULL) { 248 (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 249 return (0); 250 } 251 kd->program = 0; 252 return (_kvm_open(kd, uf, mf, flag, errout)); 253 } 254 255 kvm_t * 256 kvm_open(uf, mf, sf, flag, errstr) 257 const char *uf; 258 const char *mf; 259 const char *sf __unused; 260 int flag; 261 const char *errstr; 262 { 263 kvm_t *kd; 264 265 if ((kd = calloc(1, sizeof(*kd))) == NULL) { 266 if (errstr != NULL) 267 (void)fprintf(stderr, "%s: %s\n", 268 errstr, strerror(errno)); 269 return (0); 270 } 271 kd->program = errstr; 272 return (_kvm_open(kd, uf, mf, flag, NULL)); 273 } 274 275 int 276 kvm_close(kd) 277 kvm_t *kd; 278 { 279 int error = 0; 280 281 if (kd->pmfd >= 0) 282 error |= close(kd->pmfd); 283 if (kd->vmfd >= 0) 284 error |= close(kd->vmfd); 285 if (kd->nlfd >= 0) 286 error |= close(kd->nlfd); 287 if (kd->vmst) 288 _kvm_freevtop(kd); 289 if (kd->procbase != 0) 290 free((void *)kd->procbase); 291 if (kd->argbuf != 0) 292 free((void *) kd->argbuf); 293 if (kd->argspc != 0) 294 free((void *) kd->argspc); 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 int error; 311 312 /* 313 * If we can't use the kld symbol lookup, revert to the 314 * slow library call. 315 */ 316 if (!ISALIVE(kd)) 317 return (__fdnlist(kd->nlfd, nl)); 318 319 /* 320 * We can use the kld lookup syscall. Go through each nlist entry 321 * and look it up with a kldsym(2) syscall. 322 */ 323 nvalid = 0; 324 for (p = nl; p->n_name && p->n_name[0]; ++p) { 325 lookup.version = sizeof(lookup); 326 lookup.symname = p->n_name; 327 lookup.symvalue = 0; 328 lookup.symsize = 0; 329 330 if (lookup.symname[0] == '_') 331 lookup.symname++; 332 333 if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 334 p->n_type = N_TEXT; 335 p->n_other = 0; 336 p->n_desc = 0; 337 p->n_value = lookup.symvalue; 338 ++nvalid; 339 /* lookup.symsize */ 340 } 341 } 342 /* 343 * Return the number of entries that weren't found. If they exist, 344 * also fill internal error buffer. 345 */ 346 error = ((p - nl) - nvalid); 347 if (error) 348 _kvm_syserr(kd, kd->program, "kvm_nlist"); 349 return (error); 350 } 351 352 ssize_t 353 kvm_read(kd, kva, buf, len) 354 kvm_t *kd; 355 u_long kva; 356 void *buf; 357 size_t len; 358 { 359 int cc; 360 char *cp; 361 362 if (ISALIVE(kd)) { 363 /* 364 * We're using /dev/kmem. Just read straight from the 365 * device and let the active kernel do the address translation. 366 */ 367 errno = 0; 368 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 369 _kvm_err(kd, 0, "invalid address (%x)", kva); 370 return (-1); 371 } 372 cc = read(kd->vmfd, buf, len); 373 if (cc < 0) { 374 _kvm_syserr(kd, 0, "kvm_read"); 375 return (-1); 376 } else if (cc < len) 377 _kvm_err(kd, kd->program, "short read"); 378 return (cc); 379 } else { 380 cp = buf; 381 while (len > 0) { 382 off_t pa; 383 384 cc = _kvm_kvatop(kd, kva, &pa); 385 if (cc == 0) 386 return (-1); 387 if (cc > len) 388 cc = len; 389 errno = 0; 390 if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 391 _kvm_syserr(kd, 0, _PATH_MEM); 392 break; 393 } 394 cc = read(kd->pmfd, cp, cc); 395 if (cc < 0) { 396 _kvm_syserr(kd, kd->program, "kvm_read"); 397 break; 398 } 399 /* 400 * If kvm_kvatop returns a bogus value or our core 401 * file is truncated, we might wind up seeking beyond 402 * the end of the core file in which case the read will 403 * return 0 (EOF). 404 */ 405 if (cc == 0) 406 break; 407 cp += cc; 408 kva += cc; 409 len -= cc; 410 } 411 return (cp - (char *)buf); 412 } 413 /* NOTREACHED */ 414 } 415 416 ssize_t 417 kvm_write(kd, kva, buf, len) 418 kvm_t *kd; 419 u_long kva; 420 const void *buf; 421 size_t len; 422 { 423 int cc; 424 425 if (ISALIVE(kd)) { 426 /* 427 * Just like kvm_read, only we write. 428 */ 429 errno = 0; 430 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 431 _kvm_err(kd, 0, "invalid address (%x)", kva); 432 return (-1); 433 } 434 cc = write(kd->vmfd, buf, len); 435 if (cc < 0) { 436 _kvm_syserr(kd, 0, "kvm_write"); 437 return (-1); 438 } else if (cc < len) 439 _kvm_err(kd, kd->program, "short write"); 440 return (cc); 441 } else { 442 _kvm_err(kd, kd->program, 443 "kvm_write not implemented for dead kernels"); 444 return (-1); 445 } 446 /* NOTREACHED */ 447 } 448