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 * 4. Neither the name of the University nor the names of its contributors 1858f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1958f0484fSRodney W. Grimes * without specific prior written permission. 2058f0484fSRodney W. Grimes * 2158f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2258f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2358f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2458f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2558f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2658f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2758f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2858f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2958f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3058f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3158f0484fSRodney W. Grimes * SUCH DAMAGE. 3258f0484fSRodney W. Grimes */ 3358f0484fSRodney W. Grimes 34e67f5b9fSMatthew Dillon #include <sys/cdefs.h> 35e67f5b9fSMatthew Dillon __FBSDID("$FreeBSD$"); 36e67f5b9fSMatthew Dillon 3758f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 388771870cSPeter Wemm #if 0 3958f0484fSRodney W. Grimes static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 408771870cSPeter Wemm #endif 4158f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 4258f0484fSRodney W. Grimes 4358f0484fSRodney W. Grimes #include <sys/param.h> 447cf8b4b9SBjoern A. Zeeb 457cf8b4b9SBjoern A. Zeeb #define _WANT_VNET 467cf8b4b9SBjoern A. Zeeb 4758f0484fSRodney W. Grimes #include <sys/user.h> 4858f0484fSRodney W. Grimes #include <sys/proc.h> 4958f0484fSRodney W. Grimes #include <sys/ioctl.h> 5058f0484fSRodney W. Grimes #include <sys/stat.h> 5158f0484fSRodney W. Grimes #include <sys/sysctl.h> 52c4a7cdb3SPeter Wemm #include <sys/linker.h> 535f67450dSDimitry Andric #include <sys/pcpu.h> 5458f0484fSRodney W. Grimes 557cf8b4b9SBjoern A. Zeeb #include <net/vnet.h> 567cf8b4b9SBjoern A. Zeeb 5758f0484fSRodney W. Grimes #include <vm/vm.h> 5858f0484fSRodney W. Grimes #include <vm/vm_param.h> 5958f0484fSRodney W. Grimes 6058f0484fSRodney W. Grimes #include <machine/vmparam.h> 6158f0484fSRodney W. Grimes 6258f0484fSRodney W. Grimes #include <ctype.h> 6358f0484fSRodney W. Grimes #include <fcntl.h> 6458f0484fSRodney W. Grimes #include <kvm.h> 6558f0484fSRodney W. Grimes #include <limits.h> 6658f0484fSRodney W. Grimes #include <nlist.h> 6758f0484fSRodney W. Grimes #include <paths.h> 6858f0484fSRodney W. Grimes #include <stdio.h> 6958f0484fSRodney W. Grimes #include <stdlib.h> 7058f0484fSRodney W. Grimes #include <string.h> 717cf8b4b9SBjoern A. Zeeb #include <strings.h> 7258f0484fSRodney W. Grimes #include <unistd.h> 7358f0484fSRodney W. Grimes 7458f0484fSRodney W. Grimes #include "kvm_private.h" 7558f0484fSRodney W. Grimes 76*3f6558c4SMarcel Moolenaar #ifndef CROSS_LIBKVM 77*3f6558c4SMarcel Moolenaar 78b7875890SDavid E. O'Brien /* from src/lib/libc/gen/nlist.c */ 7969160b1eSDavid E. O'Brien int __fdnlist(int, struct nlist *); 80b7875890SDavid E. O'Brien 81*3f6558c4SMarcel Moolenaar #define kvm_fdnlist __fdnlist 82*3f6558c4SMarcel Moolenaar 83*3f6558c4SMarcel Moolenaar #else 84*3f6558c4SMarcel Moolenaar 85*3f6558c4SMarcel Moolenaar #include <proc_service.h> 86*3f6558c4SMarcel Moolenaar 87*3f6558c4SMarcel Moolenaar static int 88*3f6558c4SMarcel Moolenaar kvm_fdnlist(int fd, struct nlist *list) 89*3f6558c4SMarcel Moolenaar { 90*3f6558c4SMarcel Moolenaar psaddr_t addr; 91*3f6558c4SMarcel Moolenaar ps_err_e pserr; 92*3f6558c4SMarcel Moolenaar int nfail; 93*3f6558c4SMarcel Moolenaar 94*3f6558c4SMarcel Moolenaar nfail = 0; 95*3f6558c4SMarcel Moolenaar while (list->n_name != NULL && list->n_name[0] != '\0') { 96*3f6558c4SMarcel Moolenaar list->n_other = 0; 97*3f6558c4SMarcel Moolenaar list->n_desc = 0; 98*3f6558c4SMarcel Moolenaar pserr = ps_pglobal_lookup(NULL, NULL, list->n_name, &addr); 99*3f6558c4SMarcel Moolenaar if (pserr != PS_OK) { 100*3f6558c4SMarcel Moolenaar nfail++; 101*3f6558c4SMarcel Moolenaar list->n_value = 0; 102*3f6558c4SMarcel Moolenaar list->n_type = 0; 103*3f6558c4SMarcel Moolenaar } else { 104*3f6558c4SMarcel Moolenaar list->n_value = addr; 105*3f6558c4SMarcel Moolenaar list->n_type = N_DATA | N_EXT; 106*3f6558c4SMarcel Moolenaar } 107*3f6558c4SMarcel Moolenaar list++; 108*3f6558c4SMarcel Moolenaar } 109*3f6558c4SMarcel Moolenaar return (nfail); 110*3f6558c4SMarcel Moolenaar } 111*3f6558c4SMarcel Moolenaar 112*3f6558c4SMarcel Moolenaar #endif /* CROSS_LIBKVM */ 113*3f6558c4SMarcel Moolenaar 11458f0484fSRodney W. Grimes char * 115c10970ddSUlrich Spörlein kvm_geterr(kvm_t *kd) 11658f0484fSRodney W. Grimes { 11758f0484fSRodney W. Grimes return (kd->errbuf); 11858f0484fSRodney W. Grimes } 11958f0484fSRodney W. Grimes 12058f0484fSRodney W. Grimes #include <stdarg.h> 12158f0484fSRodney W. Grimes 12258f0484fSRodney W. Grimes /* 12358f0484fSRodney W. Grimes * Report an error using printf style arguments. "program" is kd->program 12458f0484fSRodney W. Grimes * on hard errors, and 0 on soft errors, so that under sun error emulation, 12558f0484fSRodney W. Grimes * only hard errors are printed out (otherwise, programs like gdb will 12658f0484fSRodney W. Grimes * generate tons of error messages when trying to access bogus pointers). 12758f0484fSRodney W. Grimes */ 12858f0484fSRodney W. Grimes void 12958f0484fSRodney W. Grimes _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 13058f0484fSRodney W. Grimes { 13158f0484fSRodney W. Grimes va_list ap; 13258f0484fSRodney W. Grimes 13358f0484fSRodney W. Grimes va_start(ap, fmt); 13458f0484fSRodney W. Grimes if (program != NULL) { 13558f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 13658f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 13758f0484fSRodney W. Grimes (void)fputc('\n', stderr); 13858f0484fSRodney W. Grimes } else 13958f0484fSRodney W. Grimes (void)vsnprintf(kd->errbuf, 140c10970ddSUlrich Spörlein sizeof(kd->errbuf), fmt, ap); 14158f0484fSRodney W. Grimes 14258f0484fSRodney W. Grimes va_end(ap); 14358f0484fSRodney W. Grimes } 14458f0484fSRodney W. Grimes 14558f0484fSRodney W. Grimes void 14658f0484fSRodney W. Grimes _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 14758f0484fSRodney W. Grimes { 14858f0484fSRodney W. Grimes va_list ap; 149be04b6d1SDavid E. O'Brien int n; 15058f0484fSRodney W. Grimes 15158f0484fSRodney W. Grimes va_start(ap, fmt); 15258f0484fSRodney W. Grimes if (program != NULL) { 15358f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 15458f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 15558f0484fSRodney W. Grimes (void)fprintf(stderr, ": %s\n", strerror(errno)); 15658f0484fSRodney W. Grimes } else { 157be04b6d1SDavid E. O'Brien char *cp = kd->errbuf; 15858f0484fSRodney W. Grimes 159c10970ddSUlrich Spörlein (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); 16058f0484fSRodney W. Grimes n = strlen(cp); 16158f0484fSRodney W. Grimes (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 16258f0484fSRodney W. Grimes strerror(errno)); 16358f0484fSRodney W. Grimes } 16458f0484fSRodney W. Grimes va_end(ap); 16558f0484fSRodney W. Grimes } 16658f0484fSRodney W. Grimes 16758f0484fSRodney W. Grimes void * 168c10970ddSUlrich Spörlein _kvm_malloc(kvm_t *kd, size_t n) 16958f0484fSRodney W. Grimes { 17058f0484fSRodney W. Grimes void *p; 17158f0484fSRodney W. Grimes 172d7b100f9SAndrey A. Chernov if ((p = calloc(n, sizeof(char))) == NULL) 173c10970ddSUlrich Spörlein _kvm_err(kd, kd->program, "can't allocate %zu bytes: %s", 174d7b100f9SAndrey A. Chernov n, strerror(errno)); 17558f0484fSRodney W. Grimes return (p); 17658f0484fSRodney W. Grimes } 17758f0484fSRodney W. Grimes 17858f0484fSRodney W. Grimes static kvm_t * 179c10970ddSUlrich Spörlein _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) 18058f0484fSRodney W. Grimes { 18158f0484fSRodney W. Grimes struct stat st; 18258f0484fSRodney W. Grimes 18358f0484fSRodney W. Grimes kd->vmfd = -1; 18458f0484fSRodney W. Grimes kd->pmfd = -1; 18558f0484fSRodney W. Grimes kd->nlfd = -1; 18658f0484fSRodney W. Grimes kd->vmst = 0; 18758f0484fSRodney W. Grimes kd->procbase = 0; 18858f0484fSRodney W. Grimes kd->argspc = 0; 18958f0484fSRodney W. Grimes kd->argv = 0; 19058f0484fSRodney W. Grimes 19158f0484fSRodney W. Grimes if (uf == 0) 1924be4929cSGarrett Wollman uf = getbootfile(); 19358f0484fSRodney W. Grimes else if (strlen(uf) >= MAXPATHLEN) { 19458f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "exec file name too long"); 19558f0484fSRodney W. Grimes goto failed; 19658f0484fSRodney W. Grimes } 19758f0484fSRodney W. Grimes if (flag & ~O_RDWR) { 19858f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "bad flags arg"); 19958f0484fSRodney W. Grimes goto failed; 20058f0484fSRodney W. Grimes } 20158f0484fSRodney W. Grimes if (mf == 0) 20258f0484fSRodney W. Grimes mf = _PATH_MEM; 20358f0484fSRodney W. Grimes 20476dce67fSJilles Tjoelker if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { 20558f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 20658f0484fSRodney W. Grimes goto failed; 20758f0484fSRodney W. Grimes } 20858f0484fSRodney W. Grimes if (fstat(kd->pmfd, &st) < 0) { 20958f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 21058f0484fSRodney W. Grimes goto failed; 21158f0484fSRodney W. Grimes } 21265efc5eeSChristian S.J. Peron if (S_ISREG(st.st_mode) && st.st_size <= 0) { 21365efc5eeSChristian S.J. Peron errno = EINVAL; 21465efc5eeSChristian S.J. Peron _kvm_syserr(kd, kd->program, "empty file"); 21565efc5eeSChristian S.J. Peron goto failed; 21665efc5eeSChristian S.J. Peron } 21758f0484fSRodney W. Grimes if (S_ISCHR(st.st_mode)) { 21858f0484fSRodney W. Grimes /* 21958f0484fSRodney W. Grimes * If this is a character special device, then check that 22058f0484fSRodney W. Grimes * it's /dev/mem. If so, open kmem too. (Maybe we should 22158f0484fSRodney W. Grimes * make it work for either /dev/mem or /dev/kmem -- in either 22258f0484fSRodney W. Grimes * case you're working with a live kernel.) 22358f0484fSRodney W. Grimes */ 22435e6b695SPoul-Henning Kamp if (strcmp(mf, _PATH_DEVNULL) == 0) { 2257b05a799SJilles Tjoelker kd->vmfd = open(_PATH_DEVNULL, O_RDONLY | O_CLOEXEC); 2267928124aSHidetoshi Shimokawa return (kd); 2277928124aSHidetoshi Shimokawa } else if (strcmp(mf, _PATH_MEM) == 0) { 22876dce67fSJilles Tjoelker if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC)) < 22976dce67fSJilles Tjoelker 0) { 230f76b74d6SJacques Vidrine _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 231f76b74d6SJacques Vidrine goto failed; 232f76b74d6SJacques Vidrine } 2337928124aSHidetoshi Shimokawa return (kd); 23435e6b695SPoul-Henning Kamp } 2357928124aSHidetoshi Shimokawa } 23658f0484fSRodney W. Grimes /* 23758f0484fSRodney W. Grimes * This is a crash dump. 23835e6b695SPoul-Henning Kamp * Initialize the virtual address translation machinery, 23958f0484fSRodney W. Grimes * but first setup the namelist fd. 24058f0484fSRodney W. Grimes */ 24176dce67fSJilles Tjoelker if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { 242f76b74d6SJacques Vidrine _kvm_syserr(kd, kd->program, "%s", uf); 243f76b74d6SJacques Vidrine goto failed; 244f76b74d6SJacques Vidrine } 245d7dc9f76SHidetoshi Shimokawa if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0) 246d7dc9f76SHidetoshi Shimokawa kd->rawdump = 1; 24758f0484fSRodney W. Grimes if (_kvm_initvtop(kd) < 0) 24858f0484fSRodney W. Grimes goto failed; 24958f0484fSRodney W. Grimes return (kd); 25058f0484fSRodney W. Grimes failed: 25158f0484fSRodney W. Grimes /* 25258f0484fSRodney W. Grimes * Copy out the error if doing sane error semantics. 25358f0484fSRodney W. Grimes */ 25458f0484fSRodney W. Grimes if (errout != 0) 255ba3c0383SKris Kennaway strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 25658f0484fSRodney W. Grimes (void)kvm_close(kd); 25758f0484fSRodney W. Grimes return (0); 25858f0484fSRodney W. Grimes } 25958f0484fSRodney W. Grimes 26058f0484fSRodney W. Grimes kvm_t * 261c10970ddSUlrich Spörlein kvm_openfiles(const char *uf, const char *mf, const char *sf __unused, int flag, 262c10970ddSUlrich Spörlein char *errout) 26358f0484fSRodney W. Grimes { 264be04b6d1SDavid E. O'Brien kvm_t *kd; 26558f0484fSRodney W. Grimes 26601c56ef2SXin LI if ((kd = calloc(1, sizeof(*kd))) == NULL) { 267ba3c0383SKris Kennaway (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 26858f0484fSRodney W. Grimes return (0); 26958f0484fSRodney W. Grimes } 27058f0484fSRodney W. Grimes kd->program = 0; 2718771870cSPeter Wemm return (_kvm_open(kd, uf, mf, flag, errout)); 27258f0484fSRodney W. Grimes } 27358f0484fSRodney W. Grimes 27458f0484fSRodney W. Grimes kvm_t * 275c10970ddSUlrich Spörlein kvm_open(const char *uf, const char *mf, const char *sf __unused, int flag, 276c10970ddSUlrich Spörlein const char *errstr) 27758f0484fSRodney W. Grimes { 278be04b6d1SDavid E. O'Brien kvm_t *kd; 27958f0484fSRodney W. Grimes 28001c56ef2SXin LI if ((kd = calloc(1, sizeof(*kd))) == NULL) { 28164f14011SBruce Evans if (errstr != NULL) 28212eaa3d5SPoul-Henning Kamp (void)fprintf(stderr, "%s: %s\n", 28364f14011SBruce Evans errstr, strerror(errno)); 28458f0484fSRodney W. Grimes return (0); 28558f0484fSRodney W. Grimes } 28612eaa3d5SPoul-Henning Kamp kd->program = errstr; 2878771870cSPeter Wemm return (_kvm_open(kd, uf, mf, flag, NULL)); 28858f0484fSRodney W. Grimes } 28958f0484fSRodney W. Grimes 29058f0484fSRodney W. Grimes int 291c10970ddSUlrich Spörlein kvm_close(kvm_t *kd) 29258f0484fSRodney W. Grimes { 293be04b6d1SDavid E. O'Brien int error = 0; 29458f0484fSRodney W. Grimes 29558f0484fSRodney W. Grimes if (kd->pmfd >= 0) 29658f0484fSRodney W. Grimes error |= close(kd->pmfd); 29758f0484fSRodney W. Grimes if (kd->vmfd >= 0) 29858f0484fSRodney W. Grimes error |= close(kd->vmfd); 29958f0484fSRodney W. Grimes if (kd->nlfd >= 0) 30058f0484fSRodney W. Grimes error |= close(kd->nlfd); 30158f0484fSRodney W. Grimes if (kd->vmst) 30258f0484fSRodney W. Grimes _kvm_freevtop(kd); 30358f0484fSRodney W. Grimes if (kd->procbase != 0) 30458f0484fSRodney W. Grimes free((void *)kd->procbase); 3058b8ffe64SXin LI if (kd->argbuf != 0) 3068b8ffe64SXin LI free((void *) kd->argbuf); 3078b8ffe64SXin LI if (kd->argspc != 0) 3088b8ffe64SXin LI free((void *) kd->argspc); 30958f0484fSRodney W. Grimes if (kd->argv != 0) 31058f0484fSRodney W. Grimes free((void *)kd->argv); 31158f0484fSRodney W. Grimes free((void *)kd); 31258f0484fSRodney W. Grimes 31358f0484fSRodney W. Grimes return (0); 31458f0484fSRodney W. Grimes } 31558f0484fSRodney W. Grimes 3167cf8b4b9SBjoern A. Zeeb /* 3177cf8b4b9SBjoern A. Zeeb * Walk the list of unresolved symbols, generate a new list and prefix the 3187cf8b4b9SBjoern A. Zeeb * symbol names, try again, and merge back what we could resolve. 3197cf8b4b9SBjoern A. Zeeb */ 3207cf8b4b9SBjoern A. Zeeb static int 3217cf8b4b9SBjoern A. Zeeb kvm_fdnlist_prefix(kvm_t *kd, struct nlist *nl, int missing, const char *prefix, 3227cf8b4b9SBjoern A. Zeeb uintptr_t (*validate_fn)(kvm_t *, uintptr_t)) 3237cf8b4b9SBjoern A. Zeeb { 3247cf8b4b9SBjoern A. Zeeb struct nlist *n, *np, *p; 3257cf8b4b9SBjoern A. Zeeb char *cp, *ce; 326c10970ddSUlrich Spörlein const char *ccp; 3277cf8b4b9SBjoern A. Zeeb size_t len; 328c10970ddSUlrich Spörlein int slen, unresolved; 3297cf8b4b9SBjoern A. Zeeb 3307cf8b4b9SBjoern A. Zeeb /* 3317cf8b4b9SBjoern A. Zeeb * Calculate the space we need to malloc for nlist and names. 3327cf8b4b9SBjoern A. Zeeb * We are going to store the name twice for later lookups: once 3337cf8b4b9SBjoern A. Zeeb * with the prefix and once the unmodified name delmited by \0. 3347cf8b4b9SBjoern A. Zeeb */ 3357cf8b4b9SBjoern A. Zeeb len = 0; 3367cf8b4b9SBjoern A. Zeeb unresolved = 0; 3377cf8b4b9SBjoern A. Zeeb for (p = nl; p->n_name && p->n_name[0]; ++p) { 3387cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3397cf8b4b9SBjoern A. Zeeb continue; 3407cf8b4b9SBjoern A. Zeeb len += sizeof(struct nlist) + strlen(prefix) + 3417cf8b4b9SBjoern A. Zeeb 2 * (strlen(p->n_name) + 1); 3427cf8b4b9SBjoern A. Zeeb unresolved++; 3437cf8b4b9SBjoern A. Zeeb } 3447cf8b4b9SBjoern A. Zeeb if (unresolved == 0) 3457cf8b4b9SBjoern A. Zeeb return (unresolved); 3467cf8b4b9SBjoern A. Zeeb /* Add space for the terminating nlist entry. */ 3477cf8b4b9SBjoern A. Zeeb len += sizeof(struct nlist); 3487cf8b4b9SBjoern A. Zeeb unresolved++; 3497cf8b4b9SBjoern A. Zeeb 3507cf8b4b9SBjoern A. Zeeb /* Alloc one chunk for (nlist, [names]) and setup pointers. */ 3517cf8b4b9SBjoern A. Zeeb n = np = malloc(len); 3527cf8b4b9SBjoern A. Zeeb bzero(n, len); 3537cf8b4b9SBjoern A. Zeeb if (n == NULL) 3547cf8b4b9SBjoern A. Zeeb return (missing); 3557cf8b4b9SBjoern A. Zeeb cp = ce = (char *)np; 3567cf8b4b9SBjoern A. Zeeb cp += unresolved * sizeof(struct nlist); 3577cf8b4b9SBjoern A. Zeeb ce += len; 3587cf8b4b9SBjoern A. Zeeb 3597cf8b4b9SBjoern A. Zeeb /* Generate shortened nlist with special prefix. */ 3607cf8b4b9SBjoern A. Zeeb unresolved = 0; 3617cf8b4b9SBjoern A. Zeeb for (p = nl; p->n_name && p->n_name[0]; ++p) { 3627cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3637cf8b4b9SBjoern A. Zeeb continue; 3647cf8b4b9SBjoern A. Zeeb bcopy(p, np, sizeof(struct nlist)); 3657cf8b4b9SBjoern A. Zeeb /* Save the new\0orig. name so we can later match it again. */ 366c10970ddSUlrich Spörlein slen = snprintf(cp, ce - cp, "%s%s%c%s", prefix, 3677cf8b4b9SBjoern A. Zeeb (prefix[0] != '\0' && p->n_name[0] == '_') ? 3687cf8b4b9SBjoern A. Zeeb (p->n_name + 1) : p->n_name, '\0', p->n_name); 369c10970ddSUlrich Spörlein if (slen < 0 || slen >= ce - cp) 3707cf8b4b9SBjoern A. Zeeb continue; 3717cf8b4b9SBjoern A. Zeeb np->n_name = cp; 372c10970ddSUlrich Spörlein cp += slen + 1; 3737cf8b4b9SBjoern A. Zeeb np++; 3747cf8b4b9SBjoern A. Zeeb unresolved++; 3757cf8b4b9SBjoern A. Zeeb } 3767cf8b4b9SBjoern A. Zeeb 3777cf8b4b9SBjoern A. Zeeb /* Do lookup on the reduced list. */ 3787cf8b4b9SBjoern A. Zeeb np = n; 379*3f6558c4SMarcel Moolenaar unresolved = kvm_fdnlist(kd->nlfd, np); 3807cf8b4b9SBjoern A. Zeeb 3817cf8b4b9SBjoern A. Zeeb /* Check if we could resolve further symbols and update the list. */ 3827cf8b4b9SBjoern A. Zeeb if (unresolved >= 0 && unresolved < missing) { 3837cf8b4b9SBjoern A. Zeeb /* Find the first freshly resolved entry. */ 3847cf8b4b9SBjoern A. Zeeb for (; np->n_name && np->n_name[0]; np++) 3857cf8b4b9SBjoern A. Zeeb if (np->n_type != N_UNDF) 3867cf8b4b9SBjoern A. Zeeb break; 3877cf8b4b9SBjoern A. Zeeb /* 3887cf8b4b9SBjoern A. Zeeb * The lists are both in the same order, 3897cf8b4b9SBjoern A. Zeeb * so we can walk them in parallel. 3907cf8b4b9SBjoern A. Zeeb */ 3917cf8b4b9SBjoern A. Zeeb for (p = nl; np->n_name && np->n_name[0] && 3927cf8b4b9SBjoern A. Zeeb p->n_name && p->n_name[0]; ++p) { 3937cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3947cf8b4b9SBjoern A. Zeeb continue; 3957cf8b4b9SBjoern A. Zeeb /* Skip expanded name and compare to orig. one. */ 396c10970ddSUlrich Spörlein ccp = np->n_name + strlen(np->n_name) + 1; 397c10970ddSUlrich Spörlein if (strcmp(ccp, p->n_name) != 0) 3987cf8b4b9SBjoern A. Zeeb continue; 3997cf8b4b9SBjoern A. Zeeb /* Update nlist with new, translated results. */ 4007cf8b4b9SBjoern A. Zeeb p->n_type = np->n_type; 4017cf8b4b9SBjoern A. Zeeb p->n_other = np->n_other; 4027cf8b4b9SBjoern A. Zeeb p->n_desc = np->n_desc; 4037cf8b4b9SBjoern A. Zeeb if (validate_fn) 4047cf8b4b9SBjoern A. Zeeb p->n_value = (*validate_fn)(kd, np->n_value); 4057cf8b4b9SBjoern A. Zeeb else 4067cf8b4b9SBjoern A. Zeeb p->n_value = np->n_value; 4077cf8b4b9SBjoern A. Zeeb missing--; 4087cf8b4b9SBjoern A. Zeeb /* Find next freshly resolved entry. */ 4097cf8b4b9SBjoern A. Zeeb for (np++; np->n_name && np->n_name[0]; np++) 4107cf8b4b9SBjoern A. Zeeb if (np->n_type != N_UNDF) 4117cf8b4b9SBjoern A. Zeeb break; 4127cf8b4b9SBjoern A. Zeeb } 4137cf8b4b9SBjoern A. Zeeb } 4147cf8b4b9SBjoern A. Zeeb /* We could assert missing = unresolved here. */ 4157cf8b4b9SBjoern A. Zeeb 4167cf8b4b9SBjoern A. Zeeb free(n); 4177cf8b4b9SBjoern A. Zeeb return (unresolved); 4187cf8b4b9SBjoern A. Zeeb } 4197cf8b4b9SBjoern A. Zeeb 42058f0484fSRodney W. Grimes int 4217cf8b4b9SBjoern A. Zeeb _kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize) 42258f0484fSRodney W. Grimes { 423be04b6d1SDavid E. O'Brien struct nlist *p; 424be04b6d1SDavid E. O'Brien int nvalid; 425c4a7cdb3SPeter Wemm struct kld_sym_lookup lookup; 4266e6dfbf2SWojciech A. Koszek int error; 427c10970ddSUlrich Spörlein const char *prefix = ""; 428c10970ddSUlrich Spörlein char symname[1024]; /* XXX-BZ symbol name length limit? */ 429ccd8bad0SRobert Watson int tried_vnet, tried_dpcpu; 430ccd8bad0SRobert Watson 43158f0484fSRodney W. Grimes /* 432c4a7cdb3SPeter Wemm * If we can't use the kld symbol lookup, revert to the 43358f0484fSRodney W. Grimes * slow library call. 43458f0484fSRodney W. Grimes */ 4357cf8b4b9SBjoern A. Zeeb if (!ISALIVE(kd)) { 436*3f6558c4SMarcel Moolenaar error = kvm_fdnlist(kd->nlfd, nl); 4377cf8b4b9SBjoern A. Zeeb if (error <= 0) /* Hard error or success. */ 4387cf8b4b9SBjoern A. Zeeb return (error); 4397cf8b4b9SBjoern A. Zeeb 4407cf8b4b9SBjoern A. Zeeb if (_kvm_vnet_initialized(kd, initialize)) 4417cf8b4b9SBjoern A. Zeeb error = kvm_fdnlist_prefix(kd, nl, error, 4427cf8b4b9SBjoern A. Zeeb VNET_SYMPREFIX, _kvm_vnet_validaddr); 4437cf8b4b9SBjoern A. Zeeb 444ccd8bad0SRobert Watson if (error > 0 && _kvm_dpcpu_initialized(kd, initialize)) 445ccd8bad0SRobert Watson error = kvm_fdnlist_prefix(kd, nl, error, 4465f67450dSDimitry Andric DPCPU_SYMPREFIX, _kvm_dpcpu_validaddr); 447ccd8bad0SRobert Watson 4487cf8b4b9SBjoern A. Zeeb return (error); 4497cf8b4b9SBjoern A. Zeeb } 45058f0484fSRodney W. Grimes 45158f0484fSRodney W. Grimes /* 452c4a7cdb3SPeter Wemm * We can use the kld lookup syscall. Go through each nlist entry 453c4a7cdb3SPeter Wemm * and look it up with a kldsym(2) syscall. 45458f0484fSRodney W. Grimes */ 45558f0484fSRodney W. Grimes nvalid = 0; 456ccd8bad0SRobert Watson tried_vnet = 0; 457ccd8bad0SRobert Watson tried_dpcpu = 0; 4587cf8b4b9SBjoern A. Zeeb again: 45958f0484fSRodney W. Grimes for (p = nl; p->n_name && p->n_name[0]; ++p) { 4607cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 4617cf8b4b9SBjoern A. Zeeb continue; 4627cf8b4b9SBjoern A. Zeeb 463c4a7cdb3SPeter Wemm lookup.version = sizeof(lookup); 464c4a7cdb3SPeter Wemm lookup.symvalue = 0; 465c4a7cdb3SPeter Wemm lookup.symsize = 0; 46658f0484fSRodney W. Grimes 4677cf8b4b9SBjoern A. Zeeb error = snprintf(symname, sizeof(symname), "%s%s", prefix, 4687cf8b4b9SBjoern A. Zeeb (prefix[0] != '\0' && p->n_name[0] == '_') ? 4697cf8b4b9SBjoern A. Zeeb (p->n_name + 1) : p->n_name); 470c10970ddSUlrich Spörlein if (error < 0 || error >= (int)sizeof(symname)) 4717cf8b4b9SBjoern A. Zeeb continue; 4727cf8b4b9SBjoern A. Zeeb lookup.symname = symname; 473c4a7cdb3SPeter Wemm if (lookup.symname[0] == '_') 474c4a7cdb3SPeter Wemm lookup.symname++; 475c4a7cdb3SPeter Wemm 476c4a7cdb3SPeter Wemm if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 477c4a7cdb3SPeter Wemm p->n_type = N_TEXT; 478c4a7cdb3SPeter Wemm p->n_other = 0; 479c4a7cdb3SPeter Wemm p->n_desc = 0; 4807cf8b4b9SBjoern A. Zeeb if (_kvm_vnet_initialized(kd, initialize) && 481948db0b9SUlrich Spörlein strcmp(prefix, VNET_SYMPREFIX) == 0) 4827cf8b4b9SBjoern A. Zeeb p->n_value = 4837cf8b4b9SBjoern A. Zeeb _kvm_vnet_validaddr(kd, lookup.symvalue); 484ccd8bad0SRobert Watson else if (_kvm_dpcpu_initialized(kd, initialize) && 485948db0b9SUlrich Spörlein strcmp(prefix, DPCPU_SYMPREFIX) == 0) 486ccd8bad0SRobert Watson p->n_value = 487ccd8bad0SRobert Watson _kvm_dpcpu_validaddr(kd, lookup.symvalue); 4887cf8b4b9SBjoern A. Zeeb else 489c4a7cdb3SPeter Wemm p->n_value = lookup.symvalue; 49058f0484fSRodney W. Grimes ++nvalid; 491c4a7cdb3SPeter Wemm /* lookup.symsize */ 492c4a7cdb3SPeter Wemm } 49358f0484fSRodney W. Grimes } 4947cf8b4b9SBjoern A. Zeeb 4957cf8b4b9SBjoern A. Zeeb /* 4967cf8b4b9SBjoern A. Zeeb * Check the number of entries that weren't found. If they exist, 497ccd8bad0SRobert Watson * try again with a prefix for virtualized or DPCPU symbol names. 4987cf8b4b9SBjoern A. Zeeb */ 4997cf8b4b9SBjoern A. Zeeb error = ((p - nl) - nvalid); 500ccd8bad0SRobert Watson if (error && _kvm_vnet_initialized(kd, initialize) && !tried_vnet) { 501ccd8bad0SRobert Watson tried_vnet = 1; 5027cf8b4b9SBjoern A. Zeeb prefix = VNET_SYMPREFIX; 5037cf8b4b9SBjoern A. Zeeb goto again; 5047cf8b4b9SBjoern A. Zeeb } 505ccd8bad0SRobert Watson if (error && _kvm_dpcpu_initialized(kd, initialize) && !tried_dpcpu) { 506ccd8bad0SRobert Watson tried_dpcpu = 1; 5075f67450dSDimitry Andric prefix = DPCPU_SYMPREFIX; 508ccd8bad0SRobert Watson goto again; 509ccd8bad0SRobert Watson } 5107cf8b4b9SBjoern A. Zeeb 51158f0484fSRodney W. Grimes /* 5126e6dfbf2SWojciech A. Koszek * Return the number of entries that weren't found. If they exist, 5136e6dfbf2SWojciech A. Koszek * also fill internal error buffer. 51458f0484fSRodney W. Grimes */ 5156e6dfbf2SWojciech A. Koszek error = ((p - nl) - nvalid); 5166e6dfbf2SWojciech A. Koszek if (error) 5176e6dfbf2SWojciech A. Koszek _kvm_syserr(kd, kd->program, "kvm_nlist"); 5186e6dfbf2SWojciech A. Koszek return (error); 51958f0484fSRodney W. Grimes } 52058f0484fSRodney W. Grimes 5217cf8b4b9SBjoern A. Zeeb int 522c10970ddSUlrich Spörlein kvm_nlist(kvm_t *kd, struct nlist *nl) 5237cf8b4b9SBjoern A. Zeeb { 5247cf8b4b9SBjoern A. Zeeb 5257cf8b4b9SBjoern A. Zeeb /* 5267cf8b4b9SBjoern A. Zeeb * If called via the public interface, permit intialization of 5277cf8b4b9SBjoern A. Zeeb * further virtualized modules on demand. 5287cf8b4b9SBjoern A. Zeeb */ 5297cf8b4b9SBjoern A. Zeeb return (_kvm_nlist(kd, nl, 1)); 5307cf8b4b9SBjoern A. Zeeb } 5317cf8b4b9SBjoern A. Zeeb 53258f0484fSRodney W. Grimes ssize_t 533c10970ddSUlrich Spörlein kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) 53458f0484fSRodney W. Grimes { 535be04b6d1SDavid E. O'Brien int cc; 536c10970ddSUlrich Spörlein ssize_t cr; 537c10970ddSUlrich Spörlein off_t pa; 5381a5ff928SStefan Farfeleder char *cp; 53958f0484fSRodney W. Grimes 54058f0484fSRodney W. Grimes if (ISALIVE(kd)) { 54158f0484fSRodney W. Grimes /* 54258f0484fSRodney W. Grimes * We're using /dev/kmem. Just read straight from the 54358f0484fSRodney W. Grimes * device and let the active kernel do the address translation. 54458f0484fSRodney W. Grimes */ 54558f0484fSRodney W. Grimes errno = 0; 54658f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 547c10970ddSUlrich Spörlein _kvm_err(kd, 0, "invalid address (%lx)", kva); 54891a594d8SJacques Vidrine return (-1); 54958f0484fSRodney W. Grimes } 550c10970ddSUlrich Spörlein cr = read(kd->vmfd, buf, len); 551c10970ddSUlrich Spörlein if (cr < 0) { 55258f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_read"); 55391a594d8SJacques Vidrine return (-1); 554c10970ddSUlrich Spörlein } else if (cr < (ssize_t)len) 55558f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short read"); 556c10970ddSUlrich Spörlein return (cr); 557c10970ddSUlrich Spörlein } 558c10970ddSUlrich Spörlein 55958f0484fSRodney W. Grimes cp = buf; 56058f0484fSRodney W. Grimes while (len > 0) { 56158f0484fSRodney W. Grimes cc = _kvm_kvatop(kd, kva, &pa); 56258f0484fSRodney W. Grimes if (cc == 0) 56391a594d8SJacques Vidrine return (-1); 564c10970ddSUlrich Spörlein if (cc > (ssize_t)len) 56558f0484fSRodney W. Grimes cc = len; 56658f0484fSRodney W. Grimes errno = 0; 567e55a0cd8SPeter Wemm if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 56858f0484fSRodney W. Grimes _kvm_syserr(kd, 0, _PATH_MEM); 56958f0484fSRodney W. Grimes break; 57058f0484fSRodney W. Grimes } 571c10970ddSUlrich Spörlein cr = read(kd->pmfd, cp, cc); 572c10970ddSUlrich Spörlein if (cr < 0) { 57358f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "kvm_read"); 57458f0484fSRodney W. Grimes break; 57558f0484fSRodney W. Grimes } 57658f0484fSRodney W. Grimes /* 577c10970ddSUlrich Spörlein * If kvm_kvatop returns a bogus value or our core file is 578c10970ddSUlrich Spörlein * truncated, we might wind up seeking beyond the end of the 579c10970ddSUlrich Spörlein * core file in which case the read will return 0 (EOF). 58058f0484fSRodney W. Grimes */ 581c10970ddSUlrich Spörlein if (cr == 0) 58258f0484fSRodney W. Grimes break; 583c10970ddSUlrich Spörlein cp += cr; 584c10970ddSUlrich Spörlein kva += cr; 585c10970ddSUlrich Spörlein len -= cr; 58658f0484fSRodney W. Grimes } 587c10970ddSUlrich Spörlein 5881a5ff928SStefan Farfeleder return (cp - (char *)buf); 58958f0484fSRodney W. Grimes } 59058f0484fSRodney W. Grimes 59158f0484fSRodney W. Grimes ssize_t 592c10970ddSUlrich Spörlein kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) 59358f0484fSRodney W. Grimes { 594be04b6d1SDavid E. O'Brien int cc; 59558f0484fSRodney W. Grimes 59658f0484fSRodney W. Grimes if (ISALIVE(kd)) { 59758f0484fSRodney W. Grimes /* 59858f0484fSRodney W. Grimes * Just like kvm_read, only we write. 59958f0484fSRodney W. Grimes */ 60058f0484fSRodney W. Grimes errno = 0; 60158f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 602c10970ddSUlrich Spörlein _kvm_err(kd, 0, "invalid address (%lx)", kva); 60391a594d8SJacques Vidrine return (-1); 60458f0484fSRodney W. Grimes } 60558f0484fSRodney W. Grimes cc = write(kd->vmfd, buf, len); 60658f0484fSRodney W. Grimes if (cc < 0) { 60758f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_write"); 60891a594d8SJacques Vidrine return (-1); 609c10970ddSUlrich Spörlein } else if ((size_t)cc < len) 61058f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short write"); 61158f0484fSRodney W. Grimes return (cc); 61258f0484fSRodney W. Grimes } else { 61358f0484fSRodney W. Grimes _kvm_err(kd, kd->program, 61458f0484fSRodney W. Grimes "kvm_write not implemented for dead kernels"); 61591a594d8SJacques Vidrine return (-1); 61658f0484fSRodney W. Grimes } 61758f0484fSRodney W. Grimes /* NOTREACHED */ 61858f0484fSRodney W. Grimes } 619