158f0484fSRodney W. Grimes /*- 258f0484fSRodney W. Grimes * Copyright (c) 1989, 1992, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * This code is derived from software developed by the Computer Systems 658f0484fSRodney W. Grimes * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 758f0484fSRodney W. Grimes * BG 91-66 and contributed to Berkeley. 858f0484fSRodney W. Grimes * 958f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 1058f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1158f0484fSRodney W. Grimes * are met: 1258f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1358f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1458f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1558f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1658f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1758f0484fSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 1858f0484fSRodney W. Grimes * must display the following acknowledgement: 1958f0484fSRodney W. Grimes * This product includes software developed by the University of 2058f0484fSRodney W. Grimes * California, Berkeley and its contributors. 2158f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 2258f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 2358f0484fSRodney W. Grimes * without specific prior written permission. 2458f0484fSRodney W. Grimes * 2558f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2658f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2758f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2858f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2958f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3058f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3158f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3258f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3358f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3458f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3558f0484fSRodney W. Grimes * SUCH DAMAGE. 3658f0484fSRodney W. Grimes */ 3758f0484fSRodney W. Grimes 3858f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3958f0484fSRodney W. Grimes static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 4058f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 4158f0484fSRodney W. Grimes 4258f0484fSRodney W. Grimes #include <sys/param.h> 4358f0484fSRodney W. Grimes #include <sys/user.h> 4458f0484fSRodney W. Grimes #include <sys/proc.h> 4558f0484fSRodney W. Grimes #include <sys/ioctl.h> 4658f0484fSRodney W. Grimes #include <sys/stat.h> 4758f0484fSRodney W. Grimes #include <sys/sysctl.h> 4858f0484fSRodney W. Grimes 4958f0484fSRodney W. Grimes #include <vm/vm.h> 5058f0484fSRodney W. Grimes #include <vm/vm_param.h> 5158f0484fSRodney W. Grimes #include <vm/swap_pager.h> 5258f0484fSRodney W. Grimes 5358f0484fSRodney W. Grimes #include <machine/vmparam.h> 5458f0484fSRodney W. Grimes 5558f0484fSRodney W. Grimes #include <ctype.h> 5658f0484fSRodney W. Grimes #include <db.h> 5758f0484fSRodney W. Grimes #include <fcntl.h> 5858f0484fSRodney W. Grimes #include <kvm.h> 5958f0484fSRodney W. Grimes #include <limits.h> 6058f0484fSRodney W. Grimes #include <nlist.h> 6158f0484fSRodney W. Grimes #include <paths.h> 6258f0484fSRodney W. Grimes #include <stdio.h> 6358f0484fSRodney W. Grimes #include <stdlib.h> 6458f0484fSRodney W. Grimes #include <string.h> 6558f0484fSRodney W. Grimes #include <unistd.h> 6658f0484fSRodney W. Grimes 6758f0484fSRodney W. Grimes #include "kvm_private.h" 6858f0484fSRodney W. Grimes 6958f0484fSRodney W. Grimes static int kvm_dbopen __P((kvm_t *, const char *)); 7058f0484fSRodney W. Grimes 7158f0484fSRodney W. Grimes char * 7258f0484fSRodney W. Grimes kvm_geterr(kd) 7358f0484fSRodney W. Grimes kvm_t *kd; 7458f0484fSRodney W. Grimes { 7558f0484fSRodney W. Grimes return (kd->errbuf); 7658f0484fSRodney W. Grimes } 7758f0484fSRodney W. Grimes 7858f0484fSRodney W. Grimes #if __STDC__ 7958f0484fSRodney W. Grimes #include <stdarg.h> 8058f0484fSRodney W. Grimes #else 8158f0484fSRodney W. Grimes #include <varargs.h> 8258f0484fSRodney W. Grimes #endif 8358f0484fSRodney W. Grimes 8458f0484fSRodney W. Grimes /* 8558f0484fSRodney W. Grimes * Report an error using printf style arguments. "program" is kd->program 8658f0484fSRodney W. Grimes * on hard errors, and 0 on soft errors, so that under sun error emulation, 8758f0484fSRodney W. Grimes * only hard errors are printed out (otherwise, programs like gdb will 8858f0484fSRodney W. Grimes * generate tons of error messages when trying to access bogus pointers). 8958f0484fSRodney W. Grimes */ 9058f0484fSRodney W. Grimes void 9158f0484fSRodney W. Grimes #if __STDC__ 9258f0484fSRodney W. Grimes _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 9358f0484fSRodney W. Grimes #else 9458f0484fSRodney W. Grimes _kvm_err(kd, program, fmt, va_alist) 9558f0484fSRodney W. Grimes kvm_t *kd; 9658f0484fSRodney W. Grimes char *program, *fmt; 9758f0484fSRodney W. Grimes va_dcl 9858f0484fSRodney W. Grimes #endif 9958f0484fSRodney W. Grimes { 10058f0484fSRodney W. Grimes va_list ap; 10158f0484fSRodney W. Grimes 10258f0484fSRodney W. Grimes #ifdef __STDC__ 10358f0484fSRodney W. Grimes va_start(ap, fmt); 10458f0484fSRodney W. Grimes #else 10558f0484fSRodney W. Grimes va_start(ap); 10658f0484fSRodney W. Grimes #endif 10758f0484fSRodney W. Grimes if (program != NULL) { 10858f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 10958f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 11058f0484fSRodney W. Grimes (void)fputc('\n', stderr); 11158f0484fSRodney W. Grimes } else 11258f0484fSRodney W. Grimes (void)vsnprintf(kd->errbuf, 11358f0484fSRodney W. Grimes sizeof(kd->errbuf), (char *)fmt, ap); 11458f0484fSRodney W. Grimes 11558f0484fSRodney W. Grimes va_end(ap); 11658f0484fSRodney W. Grimes } 11758f0484fSRodney W. Grimes 11858f0484fSRodney W. Grimes void 11958f0484fSRodney W. Grimes #if __STDC__ 12058f0484fSRodney W. Grimes _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 12158f0484fSRodney W. Grimes #else 12258f0484fSRodney W. Grimes _kvm_syserr(kd, program, fmt, va_alist) 12358f0484fSRodney W. Grimes kvm_t *kd; 12458f0484fSRodney W. Grimes char *program, *fmt; 12558f0484fSRodney W. Grimes va_dcl 12658f0484fSRodney W. Grimes #endif 12758f0484fSRodney W. Grimes { 12858f0484fSRodney W. Grimes va_list ap; 12958f0484fSRodney W. Grimes register int n; 13058f0484fSRodney W. Grimes 13158f0484fSRodney W. Grimes #if __STDC__ 13258f0484fSRodney W. Grimes va_start(ap, fmt); 13358f0484fSRodney W. Grimes #else 13458f0484fSRodney W. Grimes va_start(ap); 13558f0484fSRodney W. Grimes #endif 13658f0484fSRodney W. Grimes if (program != NULL) { 13758f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 13858f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 13958f0484fSRodney W. Grimes (void)fprintf(stderr, ": %s\n", strerror(errno)); 14058f0484fSRodney W. Grimes } else { 14158f0484fSRodney W. Grimes register char *cp = kd->errbuf; 14258f0484fSRodney W. Grimes 14358f0484fSRodney W. Grimes (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 14458f0484fSRodney W. Grimes n = strlen(cp); 14558f0484fSRodney W. Grimes (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 14658f0484fSRodney W. Grimes strerror(errno)); 14758f0484fSRodney W. Grimes } 14858f0484fSRodney W. Grimes va_end(ap); 14958f0484fSRodney W. Grimes } 15058f0484fSRodney W. Grimes 15158f0484fSRodney W. Grimes void * 15258f0484fSRodney W. Grimes _kvm_malloc(kd, n) 15358f0484fSRodney W. Grimes register kvm_t *kd; 15458f0484fSRodney W. Grimes register size_t n; 15558f0484fSRodney W. Grimes { 15658f0484fSRodney W. Grimes void *p; 15758f0484fSRodney W. Grimes 15858f0484fSRodney W. Grimes if ((p = malloc(n)) == NULL) 15958f0484fSRodney W. Grimes _kvm_err(kd, kd->program, strerror(errno)); 16058f0484fSRodney W. Grimes return (p); 16158f0484fSRodney W. Grimes } 16258f0484fSRodney W. Grimes 16358f0484fSRodney W. Grimes static kvm_t * 16458f0484fSRodney W. Grimes _kvm_open(kd, uf, mf, sf, flag, errout) 16558f0484fSRodney W. Grimes register kvm_t *kd; 16658f0484fSRodney W. Grimes const char *uf; 16758f0484fSRodney W. Grimes const char *mf; 16858f0484fSRodney W. Grimes const char *sf; 16958f0484fSRodney W. Grimes int flag; 17058f0484fSRodney W. Grimes char *errout; 17158f0484fSRodney W. Grimes { 17258f0484fSRodney W. Grimes struct stat st; 17358f0484fSRodney W. Grimes 17458f0484fSRodney W. Grimes kd->vmfd = -1; 17558f0484fSRodney W. Grimes kd->pmfd = -1; 17658f0484fSRodney W. Grimes kd->swfd = -1; 17758f0484fSRodney W. Grimes kd->nlfd = -1; 17858f0484fSRodney W. Grimes kd->vmst = 0; 17958f0484fSRodney W. Grimes kd->db = 0; 18058f0484fSRodney W. Grimes kd->procbase = 0; 18158f0484fSRodney W. Grimes kd->argspc = 0; 18258f0484fSRodney W. Grimes kd->argv = 0; 18358f0484fSRodney W. Grimes 18458f0484fSRodney W. Grimes if (uf == 0) 1854be4929cSGarrett Wollman uf = getbootfile(); 18658f0484fSRodney W. Grimes else if (strlen(uf) >= MAXPATHLEN) { 18758f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "exec file name too long"); 18858f0484fSRodney W. Grimes goto failed; 18958f0484fSRodney W. Grimes } 19058f0484fSRodney W. Grimes if (flag & ~O_RDWR) { 19158f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "bad flags arg"); 19258f0484fSRodney W. Grimes goto failed; 19358f0484fSRodney W. Grimes } 19458f0484fSRodney W. Grimes if (mf == 0) 19558f0484fSRodney W. Grimes mf = _PATH_MEM; 19658f0484fSRodney W. Grimes if (sf == 0) 19758f0484fSRodney W. Grimes sf = _PATH_DRUM; 19858f0484fSRodney W. Grimes 19958f0484fSRodney W. Grimes if ((kd->pmfd = open(mf, flag, 0)) < 0) { 20058f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 20158f0484fSRodney W. Grimes goto failed; 20258f0484fSRodney W. Grimes } 20358f0484fSRodney W. Grimes if (fstat(kd->pmfd, &st) < 0) { 20458f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 20558f0484fSRodney W. Grimes goto failed; 20658f0484fSRodney W. Grimes } 20758f0484fSRodney W. Grimes if (S_ISCHR(st.st_mode)) { 20858f0484fSRodney W. Grimes /* 20958f0484fSRodney W. Grimes * If this is a character special device, then check that 21058f0484fSRodney W. Grimes * it's /dev/mem. If so, open kmem too. (Maybe we should 21158f0484fSRodney W. Grimes * make it work for either /dev/mem or /dev/kmem -- in either 21258f0484fSRodney W. Grimes * case you're working with a live kernel.) 21358f0484fSRodney W. Grimes */ 21458f0484fSRodney W. Grimes if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */ 21558f0484fSRodney W. Grimes _kvm_err(kd, kd->program, 21658f0484fSRodney W. Grimes "%s: not physical memory device", mf); 21758f0484fSRodney W. Grimes goto failed; 21858f0484fSRodney W. Grimes } 21958f0484fSRodney W. Grimes if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 22058f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 22158f0484fSRodney W. Grimes goto failed; 22258f0484fSRodney W. Grimes } 22358f0484fSRodney W. Grimes if ((kd->swfd = open(sf, flag, 0)) < 0) { 22458f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", sf); 22558f0484fSRodney W. Grimes goto failed; 22658f0484fSRodney W. Grimes } 22758f0484fSRodney W. Grimes /* 22858f0484fSRodney W. Grimes * Open kvm nlist database. We go ahead and do this 229b3bfc719SDavid Greenman * here so that we don't have to hold on to the kernel 23058f0484fSRodney W. Grimes * path name. Since a kvm application will surely do 23158f0484fSRodney W. Grimes * a kvm_nlist(), this probably won't be a wasted effort. 23258f0484fSRodney W. Grimes * If the database cannot be opened, open the namelist 23358f0484fSRodney W. Grimes * argument so we revert to slow nlist() calls. 23458f0484fSRodney W. Grimes */ 23558f0484fSRodney W. Grimes if (kvm_dbopen(kd, uf) < 0 && 23658f0484fSRodney W. Grimes (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 23758f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", uf); 23858f0484fSRodney W. Grimes goto failed; 23958f0484fSRodney W. Grimes } 24058f0484fSRodney W. Grimes } else { 24158f0484fSRodney W. Grimes /* 24258f0484fSRodney W. Grimes * This is a crash dump. 24358f0484fSRodney W. Grimes * Initalize the virtual address translation machinery, 24458f0484fSRodney W. Grimes * but first setup the namelist fd. 24558f0484fSRodney W. Grimes */ 24658f0484fSRodney W. Grimes if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 24758f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", uf); 24858f0484fSRodney W. Grimes goto failed; 24958f0484fSRodney W. Grimes } 25058f0484fSRodney W. Grimes if (_kvm_initvtop(kd) < 0) 25158f0484fSRodney W. Grimes goto failed; 25258f0484fSRodney W. Grimes } 25358f0484fSRodney W. Grimes return (kd); 25458f0484fSRodney W. Grimes failed: 25558f0484fSRodney W. Grimes /* 25658f0484fSRodney W. Grimes * Copy out the error if doing sane error semantics. 25758f0484fSRodney W. Grimes */ 25858f0484fSRodney W. Grimes if (errout != 0) 25958f0484fSRodney W. Grimes strcpy(errout, kd->errbuf); 26058f0484fSRodney W. Grimes (void)kvm_close(kd); 26158f0484fSRodney W. Grimes return (0); 26258f0484fSRodney W. Grimes } 26358f0484fSRodney W. Grimes 26458f0484fSRodney W. Grimes kvm_t * 26558f0484fSRodney W. Grimes kvm_openfiles(uf, mf, sf, flag, errout) 26658f0484fSRodney W. Grimes const char *uf; 26758f0484fSRodney W. Grimes const char *mf; 26858f0484fSRodney W. Grimes const char *sf; 26958f0484fSRodney W. Grimes int flag; 27058f0484fSRodney W. Grimes char *errout; 27158f0484fSRodney W. Grimes { 27258f0484fSRodney W. Grimes register kvm_t *kd; 27358f0484fSRodney W. Grimes 27458f0484fSRodney W. Grimes if ((kd = malloc(sizeof(*kd))) == NULL) { 27558f0484fSRodney W. Grimes (void)strcpy(errout, strerror(errno)); 27658f0484fSRodney W. Grimes return (0); 27758f0484fSRodney W. Grimes } 27858f0484fSRodney W. Grimes kd->program = 0; 27958f0484fSRodney W. Grimes return (_kvm_open(kd, uf, mf, sf, flag, errout)); 28058f0484fSRodney W. Grimes } 28158f0484fSRodney W. Grimes 28258f0484fSRodney W. Grimes kvm_t * 28358f0484fSRodney W. Grimes kvm_open(uf, mf, sf, flag, program) 28458f0484fSRodney W. Grimes const char *uf; 28558f0484fSRodney W. Grimes const char *mf; 28658f0484fSRodney W. Grimes const char *sf; 28758f0484fSRodney W. Grimes int flag; 28858f0484fSRodney W. Grimes const char *program; 28958f0484fSRodney W. Grimes { 29058f0484fSRodney W. Grimes register kvm_t *kd; 29158f0484fSRodney W. Grimes 29258f0484fSRodney W. Grimes if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) { 29358f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: %s\n", strerror(errno)); 29458f0484fSRodney W. Grimes return (0); 29558f0484fSRodney W. Grimes } 29658f0484fSRodney W. Grimes kd->program = program; 29758f0484fSRodney W. Grimes return (_kvm_open(kd, uf, mf, sf, flag, NULL)); 29858f0484fSRodney W. Grimes } 29958f0484fSRodney W. Grimes 30058f0484fSRodney W. Grimes int 30158f0484fSRodney W. Grimes kvm_close(kd) 30258f0484fSRodney W. Grimes kvm_t *kd; 30358f0484fSRodney W. Grimes { 30458f0484fSRodney W. Grimes register int error = 0; 30558f0484fSRodney W. Grimes 30658f0484fSRodney W. Grimes if (kd->pmfd >= 0) 30758f0484fSRodney W. Grimes error |= close(kd->pmfd); 30858f0484fSRodney W. Grimes if (kd->vmfd >= 0) 30958f0484fSRodney W. Grimes error |= close(kd->vmfd); 31058f0484fSRodney W. Grimes if (kd->nlfd >= 0) 31158f0484fSRodney W. Grimes error |= close(kd->nlfd); 31258f0484fSRodney W. Grimes if (kd->swfd >= 0) 31358f0484fSRodney W. Grimes error |= close(kd->swfd); 31458f0484fSRodney W. Grimes if (kd->db != 0) 31558f0484fSRodney W. Grimes error |= (kd->db->close)(kd->db); 31658f0484fSRodney W. Grimes if (kd->vmst) 31758f0484fSRodney W. Grimes _kvm_freevtop(kd); 31858f0484fSRodney W. Grimes if (kd->procbase != 0) 31958f0484fSRodney W. Grimes free((void *)kd->procbase); 32058f0484fSRodney W. Grimes if (kd->argv != 0) 32158f0484fSRodney W. Grimes free((void *)kd->argv); 32258f0484fSRodney W. Grimes free((void *)kd); 32358f0484fSRodney W. Grimes 32458f0484fSRodney W. Grimes return (0); 32558f0484fSRodney W. Grimes } 32658f0484fSRodney W. Grimes 32758f0484fSRodney W. Grimes /* 32858f0484fSRodney W. Grimes * Set up state necessary to do queries on the kernel namelist 32958f0484fSRodney W. Grimes * data base. If the data base is out-of-data/incompatible with 33058f0484fSRodney W. Grimes * given executable, set up things so we revert to standard nlist call. 33158f0484fSRodney W. Grimes * Only called for live kernels. Return 0 on success, -1 on failure. 33258f0484fSRodney W. Grimes */ 33358f0484fSRodney W. Grimes static int 33458f0484fSRodney W. Grimes kvm_dbopen(kd, uf) 33558f0484fSRodney W. Grimes kvm_t *kd; 33658f0484fSRodney W. Grimes const char *uf; 33758f0484fSRodney W. Grimes { 33858f0484fSRodney W. Grimes char *cp; 33958f0484fSRodney W. Grimes DBT rec; 34058f0484fSRodney W. Grimes int dbversionlen; 34158f0484fSRodney W. Grimes struct nlist nitem; 34258f0484fSRodney W. Grimes char dbversion[_POSIX2_LINE_MAX]; 34358f0484fSRodney W. Grimes char kversion[_POSIX2_LINE_MAX]; 34458f0484fSRodney W. Grimes char dbname[MAXPATHLEN]; 34558f0484fSRodney W. Grimes 34658f0484fSRodney W. Grimes if ((cp = rindex(uf, '/')) != 0) 34758f0484fSRodney W. Grimes uf = cp + 1; 34858f0484fSRodney W. Grimes 34958f0484fSRodney W. Grimes (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); 35058f0484fSRodney W. Grimes kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); 35158f0484fSRodney W. Grimes if (kd->db == 0) 35258f0484fSRodney W. Grimes return (-1); 35358f0484fSRodney W. Grimes /* 35458f0484fSRodney W. Grimes * read version out of database 35558f0484fSRodney W. Grimes */ 35658f0484fSRodney W. Grimes rec.data = VRS_KEY; 35758f0484fSRodney W. Grimes rec.size = sizeof(VRS_KEY) - 1; 35858f0484fSRodney W. Grimes if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 35958f0484fSRodney W. Grimes goto close; 36058f0484fSRodney W. Grimes if (rec.data == 0 || rec.size > sizeof(dbversion)) 36158f0484fSRodney W. Grimes goto close; 36258f0484fSRodney W. Grimes 36358f0484fSRodney W. Grimes bcopy(rec.data, dbversion, rec.size); 36458f0484fSRodney W. Grimes dbversionlen = rec.size; 36558f0484fSRodney W. Grimes /* 36658f0484fSRodney W. Grimes * Read version string from kernel memory. 36758f0484fSRodney W. Grimes * Since we are dealing with a live kernel, we can call kvm_read() 36858f0484fSRodney W. Grimes * at this point. 36958f0484fSRodney W. Grimes */ 37058f0484fSRodney W. Grimes rec.data = VRS_SYM; 37158f0484fSRodney W. Grimes rec.size = sizeof(VRS_SYM) - 1; 37258f0484fSRodney W. Grimes if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 37358f0484fSRodney W. Grimes goto close; 37458f0484fSRodney W. Grimes if (rec.data == 0 || rec.size != sizeof(struct nlist)) 37558f0484fSRodney W. Grimes goto close; 37658f0484fSRodney W. Grimes bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem)); 37758f0484fSRodney W. Grimes if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) != 37858f0484fSRodney W. Grimes dbversionlen) 37958f0484fSRodney W. Grimes goto close; 38058f0484fSRodney W. Grimes /* 38158f0484fSRodney W. Grimes * If they match, we win - otherwise clear out kd->db so 38258f0484fSRodney W. Grimes * we revert to slow nlist(). 38358f0484fSRodney W. Grimes */ 38458f0484fSRodney W. Grimes if (bcmp(dbversion, kversion, dbversionlen) == 0) 38558f0484fSRodney W. Grimes return (0); 38658f0484fSRodney W. Grimes close: 38758f0484fSRodney W. Grimes (void)(kd->db->close)(kd->db); 38858f0484fSRodney W. Grimes kd->db = 0; 38958f0484fSRodney W. Grimes 39058f0484fSRodney W. Grimes return (-1); 39158f0484fSRodney W. Grimes } 39258f0484fSRodney W. Grimes 39358f0484fSRodney W. Grimes int 39458f0484fSRodney W. Grimes kvm_nlist(kd, nl) 39558f0484fSRodney W. Grimes kvm_t *kd; 39658f0484fSRodney W. Grimes struct nlist *nl; 39758f0484fSRodney W. Grimes { 39858f0484fSRodney W. Grimes register struct nlist *p; 39958f0484fSRodney W. Grimes register int nvalid; 40058f0484fSRodney W. Grimes 40158f0484fSRodney W. Grimes /* 40258f0484fSRodney W. Grimes * If we can't use the data base, revert to the 40358f0484fSRodney W. Grimes * slow library call. 40458f0484fSRodney W. Grimes */ 40558f0484fSRodney W. Grimes if (kd->db == 0) 40658f0484fSRodney W. Grimes return (__fdnlist(kd->nlfd, nl)); 40758f0484fSRodney W. Grimes 40858f0484fSRodney W. Grimes /* 40958f0484fSRodney W. Grimes * We can use the kvm data base. Go through each nlist entry 41058f0484fSRodney W. Grimes * and look it up with a db query. 41158f0484fSRodney W. Grimes */ 41258f0484fSRodney W. Grimes nvalid = 0; 41358f0484fSRodney W. Grimes for (p = nl; p->n_name && p->n_name[0]; ++p) { 41458f0484fSRodney W. Grimes register int len; 41558f0484fSRodney W. Grimes DBT rec; 41658f0484fSRodney W. Grimes 41758f0484fSRodney W. Grimes if ((len = strlen(p->n_name)) > 4096) { 41858f0484fSRodney W. Grimes /* sanity */ 41958f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "symbol too large"); 42058f0484fSRodney W. Grimes return (-1); 42158f0484fSRodney W. Grimes } 42258f0484fSRodney W. Grimes rec.data = p->n_name; 42358f0484fSRodney W. Grimes rec.size = len; 42458f0484fSRodney W. Grimes if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 42558f0484fSRodney W. Grimes continue; 42658f0484fSRodney W. Grimes if (rec.data == 0 || rec.size != sizeof(struct nlist)) 42758f0484fSRodney W. Grimes continue; 42858f0484fSRodney W. Grimes ++nvalid; 42958f0484fSRodney W. Grimes /* 43058f0484fSRodney W. Grimes * Avoid alignment issues. 43158f0484fSRodney W. Grimes */ 43258f0484fSRodney W. Grimes bcopy((char *)&((struct nlist *)rec.data)->n_type, 43358f0484fSRodney W. Grimes (char *)&p->n_type, 43458f0484fSRodney W. Grimes sizeof(p->n_type)); 43558f0484fSRodney W. Grimes bcopy((char *)&((struct nlist *)rec.data)->n_value, 43658f0484fSRodney W. Grimes (char *)&p->n_value, 43758f0484fSRodney W. Grimes sizeof(p->n_value)); 43858f0484fSRodney W. Grimes } 43958f0484fSRodney W. Grimes /* 44058f0484fSRodney W. Grimes * Return the number of entries that weren't found. 44158f0484fSRodney W. Grimes */ 44258f0484fSRodney W. Grimes return ((p - nl) - nvalid); 44358f0484fSRodney W. Grimes } 44458f0484fSRodney W. Grimes 44558f0484fSRodney W. Grimes ssize_t 44658f0484fSRodney W. Grimes kvm_read(kd, kva, buf, len) 44758f0484fSRodney W. Grimes kvm_t *kd; 44858f0484fSRodney W. Grimes register u_long kva; 44958f0484fSRodney W. Grimes register void *buf; 45058f0484fSRodney W. Grimes register size_t len; 45158f0484fSRodney W. Grimes { 45258f0484fSRodney W. Grimes register int cc; 45358f0484fSRodney W. Grimes register void *cp; 45458f0484fSRodney W. Grimes 45558f0484fSRodney W. Grimes if (ISALIVE(kd)) { 45658f0484fSRodney W. Grimes /* 45758f0484fSRodney W. Grimes * We're using /dev/kmem. Just read straight from the 45858f0484fSRodney W. Grimes * device and let the active kernel do the address translation. 45958f0484fSRodney W. Grimes */ 46058f0484fSRodney W. Grimes errno = 0; 46158f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 46258f0484fSRodney W. Grimes _kvm_err(kd, 0, "invalid address (%x)", kva); 46358f0484fSRodney W. Grimes return (0); 46458f0484fSRodney W. Grimes } 46558f0484fSRodney W. Grimes cc = read(kd->vmfd, buf, len); 46658f0484fSRodney W. Grimes if (cc < 0) { 46758f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_read"); 46858f0484fSRodney W. Grimes return (0); 46958f0484fSRodney W. Grimes } else if (cc < len) 47058f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short read"); 47158f0484fSRodney W. Grimes return (cc); 47258f0484fSRodney W. Grimes } else { 47358f0484fSRodney W. Grimes cp = buf; 47458f0484fSRodney W. Grimes while (len > 0) { 47558f0484fSRodney W. Grimes u_long pa; 47658f0484fSRodney W. Grimes 47758f0484fSRodney W. Grimes cc = _kvm_kvatop(kd, kva, &pa); 47858f0484fSRodney W. Grimes if (cc == 0) 47958f0484fSRodney W. Grimes return (0); 48058f0484fSRodney W. Grimes if (cc > len) 48158f0484fSRodney W. Grimes cc = len; 48258f0484fSRodney W. Grimes errno = 0; 48358f0484fSRodney W. Grimes if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 48458f0484fSRodney W. Grimes _kvm_syserr(kd, 0, _PATH_MEM); 48558f0484fSRodney W. Grimes break; 48658f0484fSRodney W. Grimes } 48758f0484fSRodney W. Grimes cc = read(kd->pmfd, cp, cc); 48858f0484fSRodney W. Grimes if (cc < 0) { 48958f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "kvm_read"); 49058f0484fSRodney W. Grimes break; 49158f0484fSRodney W. Grimes } 49258f0484fSRodney W. Grimes /* 49358f0484fSRodney W. Grimes * If kvm_kvatop returns a bogus value or our core 49458f0484fSRodney W. Grimes * file is truncated, we might wind up seeking beyond 49558f0484fSRodney W. Grimes * the end of the core file in which case the read will 49658f0484fSRodney W. Grimes * return 0 (EOF). 49758f0484fSRodney W. Grimes */ 49858f0484fSRodney W. Grimes if (cc == 0) 49958f0484fSRodney W. Grimes break; 50058f0484fSRodney W. Grimes (char *)cp += cc; 50158f0484fSRodney W. Grimes kva += cc; 50258f0484fSRodney W. Grimes len -= cc; 50358f0484fSRodney W. Grimes } 50458f0484fSRodney W. Grimes return ((char *)cp - (char *)buf); 50558f0484fSRodney W. Grimes } 50658f0484fSRodney W. Grimes /* NOTREACHED */ 50758f0484fSRodney W. Grimes } 50858f0484fSRodney W. Grimes 50958f0484fSRodney W. Grimes ssize_t 51058f0484fSRodney W. Grimes kvm_write(kd, kva, buf, len) 51158f0484fSRodney W. Grimes kvm_t *kd; 51258f0484fSRodney W. Grimes register u_long kva; 51358f0484fSRodney W. Grimes register const void *buf; 51458f0484fSRodney W. Grimes register size_t len; 51558f0484fSRodney W. Grimes { 51658f0484fSRodney W. Grimes register int cc; 51758f0484fSRodney W. Grimes 51858f0484fSRodney W. Grimes if (ISALIVE(kd)) { 51958f0484fSRodney W. Grimes /* 52058f0484fSRodney W. Grimes * Just like kvm_read, only we write. 52158f0484fSRodney W. Grimes */ 52258f0484fSRodney W. Grimes errno = 0; 52358f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 52458f0484fSRodney W. Grimes _kvm_err(kd, 0, "invalid address (%x)", kva); 52558f0484fSRodney W. Grimes return (0); 52658f0484fSRodney W. Grimes } 52758f0484fSRodney W. Grimes cc = write(kd->vmfd, buf, len); 52858f0484fSRodney W. Grimes if (cc < 0) { 52958f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_write"); 53058f0484fSRodney W. Grimes return (0); 53158f0484fSRodney W. Grimes } else if (cc < len) 53258f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short write"); 53358f0484fSRodney W. Grimes return (cc); 53458f0484fSRodney W. Grimes } else { 53558f0484fSRodney W. Grimes _kvm_err(kd, kd->program, 53658f0484fSRodney W. Grimes "kvm_write not implemented for dead kernels"); 53758f0484fSRodney W. Grimes return (0); 53858f0484fSRodney W. Grimes } 53958f0484fSRodney W. Grimes /* NOTREACHED */ 54058f0484fSRodney W. Grimes } 541