File:  [DragonFly] / src / lib / libkvm / kvm.c
Revision 1.3: download - view: text, annotated - select for diffs
Wed Nov 12 20:21:30 2003 UTC (11 years ago) by eirikn
Branches: MAIN
CVS tags: HEAD
 * Removed the __P macros from lib/

 * Small fixups by me in lib/libcr, there was some stale ')' after the __P( was
   removed from the line above.

Submitted-by: Craig Dooley <craig@xlnx-x.net>

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