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 76b7875890SDavid E. O'Brien /* from src/lib/libc/gen/nlist.c */ 7769160b1eSDavid E. O'Brien int __fdnlist(int, struct nlist *); 78b7875890SDavid E. O'Brien 7958f0484fSRodney W. Grimes char * 80c10970ddSUlrich Spörlein kvm_geterr(kvm_t *kd) 8158f0484fSRodney W. Grimes { 8258f0484fSRodney W. Grimes return (kd->errbuf); 8358f0484fSRodney W. Grimes } 8458f0484fSRodney W. Grimes 8558f0484fSRodney W. Grimes #include <stdarg.h> 8658f0484fSRodney W. Grimes 8758f0484fSRodney W. Grimes /* 8858f0484fSRodney W. Grimes * Report an error using printf style arguments. "program" is kd->program 8958f0484fSRodney W. Grimes * on hard errors, and 0 on soft errors, so that under sun error emulation, 9058f0484fSRodney W. Grimes * only hard errors are printed out (otherwise, programs like gdb will 9158f0484fSRodney W. Grimes * generate tons of error messages when trying to access bogus pointers). 9258f0484fSRodney W. Grimes */ 9358f0484fSRodney W. Grimes void 9458f0484fSRodney W. Grimes _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 9558f0484fSRodney W. Grimes { 9658f0484fSRodney W. Grimes va_list ap; 9758f0484fSRodney W. Grimes 9858f0484fSRodney W. Grimes va_start(ap, fmt); 9958f0484fSRodney W. Grimes if (program != NULL) { 10058f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 10158f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 10258f0484fSRodney W. Grimes (void)fputc('\n', stderr); 10358f0484fSRodney W. Grimes } else 10458f0484fSRodney W. Grimes (void)vsnprintf(kd->errbuf, 105c10970ddSUlrich Spörlein sizeof(kd->errbuf), fmt, ap); 10658f0484fSRodney W. Grimes 10758f0484fSRodney W. Grimes va_end(ap); 10858f0484fSRodney W. Grimes } 10958f0484fSRodney W. Grimes 11058f0484fSRodney W. Grimes void 11158f0484fSRodney W. Grimes _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 11258f0484fSRodney W. Grimes { 11358f0484fSRodney W. Grimes va_list ap; 114be04b6d1SDavid E. O'Brien int n; 11558f0484fSRodney W. Grimes 11658f0484fSRodney W. Grimes va_start(ap, fmt); 11758f0484fSRodney W. Grimes if (program != NULL) { 11858f0484fSRodney W. Grimes (void)fprintf(stderr, "%s: ", program); 11958f0484fSRodney W. Grimes (void)vfprintf(stderr, fmt, ap); 12058f0484fSRodney W. Grimes (void)fprintf(stderr, ": %s\n", strerror(errno)); 12158f0484fSRodney W. Grimes } else { 122be04b6d1SDavid E. O'Brien char *cp = kd->errbuf; 12358f0484fSRodney W. Grimes 124c10970ddSUlrich Spörlein (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); 12558f0484fSRodney W. Grimes n = strlen(cp); 12658f0484fSRodney W. Grimes (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 12758f0484fSRodney W. Grimes strerror(errno)); 12858f0484fSRodney W. Grimes } 12958f0484fSRodney W. Grimes va_end(ap); 13058f0484fSRodney W. Grimes } 13158f0484fSRodney W. Grimes 13258f0484fSRodney W. Grimes void * 133c10970ddSUlrich Spörlein _kvm_malloc(kvm_t *kd, size_t n) 13458f0484fSRodney W. Grimes { 13558f0484fSRodney W. Grimes void *p; 13658f0484fSRodney W. Grimes 137d7b100f9SAndrey A. Chernov if ((p = calloc(n, sizeof(char))) == NULL) 138c10970ddSUlrich Spörlein _kvm_err(kd, kd->program, "can't allocate %zu bytes: %s", 139d7b100f9SAndrey A. Chernov n, strerror(errno)); 14058f0484fSRodney W. Grimes return (p); 14158f0484fSRodney W. Grimes } 14258f0484fSRodney W. Grimes 14358f0484fSRodney W. Grimes static kvm_t * 144c10970ddSUlrich Spörlein _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) 14558f0484fSRodney W. Grimes { 14658f0484fSRodney W. Grimes struct stat st; 14758f0484fSRodney W. Grimes 14858f0484fSRodney W. Grimes kd->vmfd = -1; 14958f0484fSRodney W. Grimes kd->pmfd = -1; 15058f0484fSRodney W. Grimes kd->nlfd = -1; 15158f0484fSRodney W. Grimes kd->vmst = 0; 15258f0484fSRodney W. Grimes kd->procbase = 0; 15358f0484fSRodney W. Grimes kd->argspc = 0; 15458f0484fSRodney W. Grimes kd->argv = 0; 15558f0484fSRodney W. Grimes 15658f0484fSRodney W. Grimes if (uf == 0) 1574be4929cSGarrett Wollman uf = getbootfile(); 15858f0484fSRodney W. Grimes else if (strlen(uf) >= MAXPATHLEN) { 15958f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "exec file name too long"); 16058f0484fSRodney W. Grimes goto failed; 16158f0484fSRodney W. Grimes } 16258f0484fSRodney W. Grimes if (flag & ~O_RDWR) { 16358f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "bad flags arg"); 16458f0484fSRodney W. Grimes goto failed; 16558f0484fSRodney W. Grimes } 16658f0484fSRodney W. Grimes if (mf == 0) 16758f0484fSRodney W. Grimes mf = _PATH_MEM; 16858f0484fSRodney W. Grimes 169*76dce67fSJilles Tjoelker if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { 17058f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 17158f0484fSRodney W. Grimes goto failed; 17258f0484fSRodney W. Grimes } 17358f0484fSRodney W. Grimes if (fstat(kd->pmfd, &st) < 0) { 17458f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "%s", mf); 17558f0484fSRodney W. Grimes goto failed; 17658f0484fSRodney W. Grimes } 17765efc5eeSChristian S.J. Peron if (S_ISREG(st.st_mode) && st.st_size <= 0) { 17865efc5eeSChristian S.J. Peron errno = EINVAL; 17965efc5eeSChristian S.J. Peron _kvm_syserr(kd, kd->program, "empty file"); 18065efc5eeSChristian S.J. Peron goto failed; 18165efc5eeSChristian S.J. Peron } 18258f0484fSRodney W. Grimes if (S_ISCHR(st.st_mode)) { 18358f0484fSRodney W. Grimes /* 18458f0484fSRodney W. Grimes * If this is a character special device, then check that 18558f0484fSRodney W. Grimes * it's /dev/mem. If so, open kmem too. (Maybe we should 18658f0484fSRodney W. Grimes * make it work for either /dev/mem or /dev/kmem -- in either 18758f0484fSRodney W. Grimes * case you're working with a live kernel.) 18858f0484fSRodney W. Grimes */ 18935e6b695SPoul-Henning Kamp if (strcmp(mf, _PATH_DEVNULL) == 0) { 19035e6b695SPoul-Henning Kamp kd->vmfd = open(_PATH_DEVNULL, O_RDONLY); 1917928124aSHidetoshi Shimokawa return (kd); 1927928124aSHidetoshi Shimokawa } else if (strcmp(mf, _PATH_MEM) == 0) { 193*76dce67fSJilles Tjoelker if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC)) < 194*76dce67fSJilles Tjoelker 0) { 195f76b74d6SJacques Vidrine _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 196f76b74d6SJacques Vidrine goto failed; 197f76b74d6SJacques Vidrine } 1987928124aSHidetoshi Shimokawa return (kd); 19935e6b695SPoul-Henning Kamp } 2007928124aSHidetoshi Shimokawa } 20158f0484fSRodney W. Grimes /* 20258f0484fSRodney W. Grimes * This is a crash dump. 20335e6b695SPoul-Henning Kamp * Initialize the virtual address translation machinery, 20458f0484fSRodney W. Grimes * but first setup the namelist fd. 20558f0484fSRodney W. Grimes */ 206*76dce67fSJilles Tjoelker if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { 207f76b74d6SJacques Vidrine _kvm_syserr(kd, kd->program, "%s", uf); 208f76b74d6SJacques Vidrine goto failed; 209f76b74d6SJacques Vidrine } 210d7dc9f76SHidetoshi Shimokawa if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0) 211d7dc9f76SHidetoshi Shimokawa kd->rawdump = 1; 21258f0484fSRodney W. Grimes if (_kvm_initvtop(kd) < 0) 21358f0484fSRodney W. Grimes goto failed; 21458f0484fSRodney W. Grimes return (kd); 21558f0484fSRodney W. Grimes failed: 21658f0484fSRodney W. Grimes /* 21758f0484fSRodney W. Grimes * Copy out the error if doing sane error semantics. 21858f0484fSRodney W. Grimes */ 21958f0484fSRodney W. Grimes if (errout != 0) 220ba3c0383SKris Kennaway strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 22158f0484fSRodney W. Grimes (void)kvm_close(kd); 22258f0484fSRodney W. Grimes return (0); 22358f0484fSRodney W. Grimes } 22458f0484fSRodney W. Grimes 22558f0484fSRodney W. Grimes kvm_t * 226c10970ddSUlrich Spörlein kvm_openfiles(const char *uf, const char *mf, const char *sf __unused, int flag, 227c10970ddSUlrich Spörlein char *errout) 22858f0484fSRodney W. Grimes { 229be04b6d1SDavid E. O'Brien kvm_t *kd; 23058f0484fSRodney W. Grimes 23101c56ef2SXin LI if ((kd = calloc(1, sizeof(*kd))) == NULL) { 232ba3c0383SKris Kennaway (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 23358f0484fSRodney W. Grimes return (0); 23458f0484fSRodney W. Grimes } 23558f0484fSRodney W. Grimes kd->program = 0; 2368771870cSPeter Wemm return (_kvm_open(kd, uf, mf, flag, errout)); 23758f0484fSRodney W. Grimes } 23858f0484fSRodney W. Grimes 23958f0484fSRodney W. Grimes kvm_t * 240c10970ddSUlrich Spörlein kvm_open(const char *uf, const char *mf, const char *sf __unused, int flag, 241c10970ddSUlrich Spörlein const char *errstr) 24258f0484fSRodney W. Grimes { 243be04b6d1SDavid E. O'Brien kvm_t *kd; 24458f0484fSRodney W. Grimes 24501c56ef2SXin LI if ((kd = calloc(1, sizeof(*kd))) == NULL) { 24664f14011SBruce Evans if (errstr != NULL) 24712eaa3d5SPoul-Henning Kamp (void)fprintf(stderr, "%s: %s\n", 24864f14011SBruce Evans errstr, strerror(errno)); 24958f0484fSRodney W. Grimes return (0); 25058f0484fSRodney W. Grimes } 25112eaa3d5SPoul-Henning Kamp kd->program = errstr; 2528771870cSPeter Wemm return (_kvm_open(kd, uf, mf, flag, NULL)); 25358f0484fSRodney W. Grimes } 25458f0484fSRodney W. Grimes 25558f0484fSRodney W. Grimes int 256c10970ddSUlrich Spörlein kvm_close(kvm_t *kd) 25758f0484fSRodney W. Grimes { 258be04b6d1SDavid E. O'Brien int error = 0; 25958f0484fSRodney W. Grimes 26058f0484fSRodney W. Grimes if (kd->pmfd >= 0) 26158f0484fSRodney W. Grimes error |= close(kd->pmfd); 26258f0484fSRodney W. Grimes if (kd->vmfd >= 0) 26358f0484fSRodney W. Grimes error |= close(kd->vmfd); 26458f0484fSRodney W. Grimes if (kd->nlfd >= 0) 26558f0484fSRodney W. Grimes error |= close(kd->nlfd); 26658f0484fSRodney W. Grimes if (kd->vmst) 26758f0484fSRodney W. Grimes _kvm_freevtop(kd); 26858f0484fSRodney W. Grimes if (kd->procbase != 0) 26958f0484fSRodney W. Grimes free((void *)kd->procbase); 2708b8ffe64SXin LI if (kd->argbuf != 0) 2718b8ffe64SXin LI free((void *) kd->argbuf); 2728b8ffe64SXin LI if (kd->argspc != 0) 2738b8ffe64SXin LI free((void *) kd->argspc); 27458f0484fSRodney W. Grimes if (kd->argv != 0) 27558f0484fSRodney W. Grimes free((void *)kd->argv); 27658f0484fSRodney W. Grimes free((void *)kd); 27758f0484fSRodney W. Grimes 27858f0484fSRodney W. Grimes return (0); 27958f0484fSRodney W. Grimes } 28058f0484fSRodney W. Grimes 2817cf8b4b9SBjoern A. Zeeb /* 2827cf8b4b9SBjoern A. Zeeb * Walk the list of unresolved symbols, generate a new list and prefix the 2837cf8b4b9SBjoern A. Zeeb * symbol names, try again, and merge back what we could resolve. 2847cf8b4b9SBjoern A. Zeeb */ 2857cf8b4b9SBjoern A. Zeeb static int 2867cf8b4b9SBjoern A. Zeeb kvm_fdnlist_prefix(kvm_t *kd, struct nlist *nl, int missing, const char *prefix, 2877cf8b4b9SBjoern A. Zeeb uintptr_t (*validate_fn)(kvm_t *, uintptr_t)) 2887cf8b4b9SBjoern A. Zeeb { 2897cf8b4b9SBjoern A. Zeeb struct nlist *n, *np, *p; 2907cf8b4b9SBjoern A. Zeeb char *cp, *ce; 291c10970ddSUlrich Spörlein const char *ccp; 2927cf8b4b9SBjoern A. Zeeb size_t len; 293c10970ddSUlrich Spörlein int slen, unresolved; 2947cf8b4b9SBjoern A. Zeeb 2957cf8b4b9SBjoern A. Zeeb /* 2967cf8b4b9SBjoern A. Zeeb * Calculate the space we need to malloc for nlist and names. 2977cf8b4b9SBjoern A. Zeeb * We are going to store the name twice for later lookups: once 2987cf8b4b9SBjoern A. Zeeb * with the prefix and once the unmodified name delmited by \0. 2997cf8b4b9SBjoern A. Zeeb */ 3007cf8b4b9SBjoern A. Zeeb len = 0; 3017cf8b4b9SBjoern A. Zeeb unresolved = 0; 3027cf8b4b9SBjoern A. Zeeb for (p = nl; p->n_name && p->n_name[0]; ++p) { 3037cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3047cf8b4b9SBjoern A. Zeeb continue; 3057cf8b4b9SBjoern A. Zeeb len += sizeof(struct nlist) + strlen(prefix) + 3067cf8b4b9SBjoern A. Zeeb 2 * (strlen(p->n_name) + 1); 3077cf8b4b9SBjoern A. Zeeb unresolved++; 3087cf8b4b9SBjoern A. Zeeb } 3097cf8b4b9SBjoern A. Zeeb if (unresolved == 0) 3107cf8b4b9SBjoern A. Zeeb return (unresolved); 3117cf8b4b9SBjoern A. Zeeb /* Add space for the terminating nlist entry. */ 3127cf8b4b9SBjoern A. Zeeb len += sizeof(struct nlist); 3137cf8b4b9SBjoern A. Zeeb unresolved++; 3147cf8b4b9SBjoern A. Zeeb 3157cf8b4b9SBjoern A. Zeeb /* Alloc one chunk for (nlist, [names]) and setup pointers. */ 3167cf8b4b9SBjoern A. Zeeb n = np = malloc(len); 3177cf8b4b9SBjoern A. Zeeb bzero(n, len); 3187cf8b4b9SBjoern A. Zeeb if (n == NULL) 3197cf8b4b9SBjoern A. Zeeb return (missing); 3207cf8b4b9SBjoern A. Zeeb cp = ce = (char *)np; 3217cf8b4b9SBjoern A. Zeeb cp += unresolved * sizeof(struct nlist); 3227cf8b4b9SBjoern A. Zeeb ce += len; 3237cf8b4b9SBjoern A. Zeeb 3247cf8b4b9SBjoern A. Zeeb /* Generate shortened nlist with special prefix. */ 3257cf8b4b9SBjoern A. Zeeb unresolved = 0; 3267cf8b4b9SBjoern A. Zeeb for (p = nl; p->n_name && p->n_name[0]; ++p) { 3277cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3287cf8b4b9SBjoern A. Zeeb continue; 3297cf8b4b9SBjoern A. Zeeb bcopy(p, np, sizeof(struct nlist)); 3307cf8b4b9SBjoern A. Zeeb /* Save the new\0orig. name so we can later match it again. */ 331c10970ddSUlrich Spörlein slen = snprintf(cp, ce - cp, "%s%s%c%s", prefix, 3327cf8b4b9SBjoern A. Zeeb (prefix[0] != '\0' && p->n_name[0] == '_') ? 3337cf8b4b9SBjoern A. Zeeb (p->n_name + 1) : p->n_name, '\0', p->n_name); 334c10970ddSUlrich Spörlein if (slen < 0 || slen >= ce - cp) 3357cf8b4b9SBjoern A. Zeeb continue; 3367cf8b4b9SBjoern A. Zeeb np->n_name = cp; 337c10970ddSUlrich Spörlein cp += slen + 1; 3387cf8b4b9SBjoern A. Zeeb np++; 3397cf8b4b9SBjoern A. Zeeb unresolved++; 3407cf8b4b9SBjoern A. Zeeb } 3417cf8b4b9SBjoern A. Zeeb 3427cf8b4b9SBjoern A. Zeeb /* Do lookup on the reduced list. */ 3437cf8b4b9SBjoern A. Zeeb np = n; 3447cf8b4b9SBjoern A. Zeeb unresolved = __fdnlist(kd->nlfd, np); 3457cf8b4b9SBjoern A. Zeeb 3467cf8b4b9SBjoern A. Zeeb /* Check if we could resolve further symbols and update the list. */ 3477cf8b4b9SBjoern A. Zeeb if (unresolved >= 0 && unresolved < missing) { 3487cf8b4b9SBjoern A. Zeeb /* Find the first freshly resolved entry. */ 3497cf8b4b9SBjoern A. Zeeb for (; np->n_name && np->n_name[0]; np++) 3507cf8b4b9SBjoern A. Zeeb if (np->n_type != N_UNDF) 3517cf8b4b9SBjoern A. Zeeb break; 3527cf8b4b9SBjoern A. Zeeb /* 3537cf8b4b9SBjoern A. Zeeb * The lists are both in the same order, 3547cf8b4b9SBjoern A. Zeeb * so we can walk them in parallel. 3557cf8b4b9SBjoern A. Zeeb */ 3567cf8b4b9SBjoern A. Zeeb for (p = nl; np->n_name && np->n_name[0] && 3577cf8b4b9SBjoern A. Zeeb p->n_name && p->n_name[0]; ++p) { 3587cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 3597cf8b4b9SBjoern A. Zeeb continue; 3607cf8b4b9SBjoern A. Zeeb /* Skip expanded name and compare to orig. one. */ 361c10970ddSUlrich Spörlein ccp = np->n_name + strlen(np->n_name) + 1; 362c10970ddSUlrich Spörlein if (strcmp(ccp, p->n_name) != 0) 3637cf8b4b9SBjoern A. Zeeb continue; 3647cf8b4b9SBjoern A. Zeeb /* Update nlist with new, translated results. */ 3657cf8b4b9SBjoern A. Zeeb p->n_type = np->n_type; 3667cf8b4b9SBjoern A. Zeeb p->n_other = np->n_other; 3677cf8b4b9SBjoern A. Zeeb p->n_desc = np->n_desc; 3687cf8b4b9SBjoern A. Zeeb if (validate_fn) 3697cf8b4b9SBjoern A. Zeeb p->n_value = (*validate_fn)(kd, np->n_value); 3707cf8b4b9SBjoern A. Zeeb else 3717cf8b4b9SBjoern A. Zeeb p->n_value = np->n_value; 3727cf8b4b9SBjoern A. Zeeb missing--; 3737cf8b4b9SBjoern A. Zeeb /* Find next freshly resolved entry. */ 3747cf8b4b9SBjoern A. Zeeb for (np++; np->n_name && np->n_name[0]; np++) 3757cf8b4b9SBjoern A. Zeeb if (np->n_type != N_UNDF) 3767cf8b4b9SBjoern A. Zeeb break; 3777cf8b4b9SBjoern A. Zeeb } 3787cf8b4b9SBjoern A. Zeeb } 3797cf8b4b9SBjoern A. Zeeb /* We could assert missing = unresolved here. */ 3807cf8b4b9SBjoern A. Zeeb 3817cf8b4b9SBjoern A. Zeeb free(n); 3827cf8b4b9SBjoern A. Zeeb return (unresolved); 3837cf8b4b9SBjoern A. Zeeb } 3847cf8b4b9SBjoern A. Zeeb 38558f0484fSRodney W. Grimes int 3867cf8b4b9SBjoern A. Zeeb _kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize) 38758f0484fSRodney W. Grimes { 388be04b6d1SDavid E. O'Brien struct nlist *p; 389be04b6d1SDavid E. O'Brien int nvalid; 390c4a7cdb3SPeter Wemm struct kld_sym_lookup lookup; 3916e6dfbf2SWojciech A. Koszek int error; 392c10970ddSUlrich Spörlein const char *prefix = ""; 393c10970ddSUlrich Spörlein char symname[1024]; /* XXX-BZ symbol name length limit? */ 394ccd8bad0SRobert Watson int tried_vnet, tried_dpcpu; 395ccd8bad0SRobert Watson 39658f0484fSRodney W. Grimes /* 397c4a7cdb3SPeter Wemm * If we can't use the kld symbol lookup, revert to the 39858f0484fSRodney W. Grimes * slow library call. 39958f0484fSRodney W. Grimes */ 4007cf8b4b9SBjoern A. Zeeb if (!ISALIVE(kd)) { 4017cf8b4b9SBjoern A. Zeeb error = __fdnlist(kd->nlfd, nl); 4027cf8b4b9SBjoern A. Zeeb if (error <= 0) /* Hard error or success. */ 4037cf8b4b9SBjoern A. Zeeb return (error); 4047cf8b4b9SBjoern A. Zeeb 4057cf8b4b9SBjoern A. Zeeb if (_kvm_vnet_initialized(kd, initialize)) 4067cf8b4b9SBjoern A. Zeeb error = kvm_fdnlist_prefix(kd, nl, error, 4077cf8b4b9SBjoern A. Zeeb VNET_SYMPREFIX, _kvm_vnet_validaddr); 4087cf8b4b9SBjoern A. Zeeb 409ccd8bad0SRobert Watson if (error > 0 && _kvm_dpcpu_initialized(kd, initialize)) 410ccd8bad0SRobert Watson error = kvm_fdnlist_prefix(kd, nl, error, 4115f67450dSDimitry Andric DPCPU_SYMPREFIX, _kvm_dpcpu_validaddr); 412ccd8bad0SRobert Watson 4137cf8b4b9SBjoern A. Zeeb return (error); 4147cf8b4b9SBjoern A. Zeeb } 41558f0484fSRodney W. Grimes 41658f0484fSRodney W. Grimes /* 417c4a7cdb3SPeter Wemm * We can use the kld lookup syscall. Go through each nlist entry 418c4a7cdb3SPeter Wemm * and look it up with a kldsym(2) syscall. 41958f0484fSRodney W. Grimes */ 42058f0484fSRodney W. Grimes nvalid = 0; 421ccd8bad0SRobert Watson tried_vnet = 0; 422ccd8bad0SRobert Watson tried_dpcpu = 0; 4237cf8b4b9SBjoern A. Zeeb again: 42458f0484fSRodney W. Grimes for (p = nl; p->n_name && p->n_name[0]; ++p) { 4257cf8b4b9SBjoern A. Zeeb if (p->n_type != N_UNDF) 4267cf8b4b9SBjoern A. Zeeb continue; 4277cf8b4b9SBjoern A. Zeeb 428c4a7cdb3SPeter Wemm lookup.version = sizeof(lookup); 429c4a7cdb3SPeter Wemm lookup.symvalue = 0; 430c4a7cdb3SPeter Wemm lookup.symsize = 0; 43158f0484fSRodney W. Grimes 4327cf8b4b9SBjoern A. Zeeb error = snprintf(symname, sizeof(symname), "%s%s", prefix, 4337cf8b4b9SBjoern A. Zeeb (prefix[0] != '\0' && p->n_name[0] == '_') ? 4347cf8b4b9SBjoern A. Zeeb (p->n_name + 1) : p->n_name); 435c10970ddSUlrich Spörlein if (error < 0 || error >= (int)sizeof(symname)) 4367cf8b4b9SBjoern A. Zeeb continue; 4377cf8b4b9SBjoern A. Zeeb lookup.symname = symname; 438c4a7cdb3SPeter Wemm if (lookup.symname[0] == '_') 439c4a7cdb3SPeter Wemm lookup.symname++; 440c4a7cdb3SPeter Wemm 441c4a7cdb3SPeter Wemm if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 442c4a7cdb3SPeter Wemm p->n_type = N_TEXT; 443c4a7cdb3SPeter Wemm p->n_other = 0; 444c4a7cdb3SPeter Wemm p->n_desc = 0; 4457cf8b4b9SBjoern A. Zeeb if (_kvm_vnet_initialized(kd, initialize) && 446948db0b9SUlrich Spörlein strcmp(prefix, VNET_SYMPREFIX) == 0) 4477cf8b4b9SBjoern A. Zeeb p->n_value = 4487cf8b4b9SBjoern A. Zeeb _kvm_vnet_validaddr(kd, lookup.symvalue); 449ccd8bad0SRobert Watson else if (_kvm_dpcpu_initialized(kd, initialize) && 450948db0b9SUlrich Spörlein strcmp(prefix, DPCPU_SYMPREFIX) == 0) 451ccd8bad0SRobert Watson p->n_value = 452ccd8bad0SRobert Watson _kvm_dpcpu_validaddr(kd, lookup.symvalue); 4537cf8b4b9SBjoern A. Zeeb else 454c4a7cdb3SPeter Wemm p->n_value = lookup.symvalue; 45558f0484fSRodney W. Grimes ++nvalid; 456c4a7cdb3SPeter Wemm /* lookup.symsize */ 457c4a7cdb3SPeter Wemm } 45858f0484fSRodney W. Grimes } 4597cf8b4b9SBjoern A. Zeeb 4607cf8b4b9SBjoern A. Zeeb /* 4617cf8b4b9SBjoern A. Zeeb * Check the number of entries that weren't found. If they exist, 462ccd8bad0SRobert Watson * try again with a prefix for virtualized or DPCPU symbol names. 4637cf8b4b9SBjoern A. Zeeb */ 4647cf8b4b9SBjoern A. Zeeb error = ((p - nl) - nvalid); 465ccd8bad0SRobert Watson if (error && _kvm_vnet_initialized(kd, initialize) && !tried_vnet) { 466ccd8bad0SRobert Watson tried_vnet = 1; 4677cf8b4b9SBjoern A. Zeeb prefix = VNET_SYMPREFIX; 4687cf8b4b9SBjoern A. Zeeb goto again; 4697cf8b4b9SBjoern A. Zeeb } 470ccd8bad0SRobert Watson if (error && _kvm_dpcpu_initialized(kd, initialize) && !tried_dpcpu) { 471ccd8bad0SRobert Watson tried_dpcpu = 1; 4725f67450dSDimitry Andric prefix = DPCPU_SYMPREFIX; 473ccd8bad0SRobert Watson goto again; 474ccd8bad0SRobert Watson } 4757cf8b4b9SBjoern A. Zeeb 47658f0484fSRodney W. Grimes /* 4776e6dfbf2SWojciech A. Koszek * Return the number of entries that weren't found. If they exist, 4786e6dfbf2SWojciech A. Koszek * also fill internal error buffer. 47958f0484fSRodney W. Grimes */ 4806e6dfbf2SWojciech A. Koszek error = ((p - nl) - nvalid); 4816e6dfbf2SWojciech A. Koszek if (error) 4826e6dfbf2SWojciech A. Koszek _kvm_syserr(kd, kd->program, "kvm_nlist"); 4836e6dfbf2SWojciech A. Koszek return (error); 48458f0484fSRodney W. Grimes } 48558f0484fSRodney W. Grimes 4867cf8b4b9SBjoern A. Zeeb int 487c10970ddSUlrich Spörlein kvm_nlist(kvm_t *kd, struct nlist *nl) 4887cf8b4b9SBjoern A. Zeeb { 4897cf8b4b9SBjoern A. Zeeb 4907cf8b4b9SBjoern A. Zeeb /* 4917cf8b4b9SBjoern A. Zeeb * If called via the public interface, permit intialization of 4927cf8b4b9SBjoern A. Zeeb * further virtualized modules on demand. 4937cf8b4b9SBjoern A. Zeeb */ 4947cf8b4b9SBjoern A. Zeeb return (_kvm_nlist(kd, nl, 1)); 4957cf8b4b9SBjoern A. Zeeb } 4967cf8b4b9SBjoern A. Zeeb 49758f0484fSRodney W. Grimes ssize_t 498c10970ddSUlrich Spörlein kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) 49958f0484fSRodney W. Grimes { 500be04b6d1SDavid E. O'Brien int cc; 501c10970ddSUlrich Spörlein ssize_t cr; 502c10970ddSUlrich Spörlein off_t pa; 5031a5ff928SStefan Farfeleder char *cp; 50458f0484fSRodney W. Grimes 50558f0484fSRodney W. Grimes if (ISALIVE(kd)) { 50658f0484fSRodney W. Grimes /* 50758f0484fSRodney W. Grimes * We're using /dev/kmem. Just read straight from the 50858f0484fSRodney W. Grimes * device and let the active kernel do the address translation. 50958f0484fSRodney W. Grimes */ 51058f0484fSRodney W. Grimes errno = 0; 51158f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 512c10970ddSUlrich Spörlein _kvm_err(kd, 0, "invalid address (%lx)", kva); 51391a594d8SJacques Vidrine return (-1); 51458f0484fSRodney W. Grimes } 515c10970ddSUlrich Spörlein cr = read(kd->vmfd, buf, len); 516c10970ddSUlrich Spörlein if (cr < 0) { 51758f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_read"); 51891a594d8SJacques Vidrine return (-1); 519c10970ddSUlrich Spörlein } else if (cr < (ssize_t)len) 52058f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short read"); 521c10970ddSUlrich Spörlein return (cr); 522c10970ddSUlrich Spörlein } 523c10970ddSUlrich Spörlein 52458f0484fSRodney W. Grimes cp = buf; 52558f0484fSRodney W. Grimes while (len > 0) { 52658f0484fSRodney W. Grimes cc = _kvm_kvatop(kd, kva, &pa); 52758f0484fSRodney W. Grimes if (cc == 0) 52891a594d8SJacques Vidrine return (-1); 529c10970ddSUlrich Spörlein if (cc > (ssize_t)len) 53058f0484fSRodney W. Grimes cc = len; 53158f0484fSRodney W. Grimes errno = 0; 532e55a0cd8SPeter Wemm if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 53358f0484fSRodney W. Grimes _kvm_syserr(kd, 0, _PATH_MEM); 53458f0484fSRodney W. Grimes break; 53558f0484fSRodney W. Grimes } 536c10970ddSUlrich Spörlein cr = read(kd->pmfd, cp, cc); 537c10970ddSUlrich Spörlein if (cr < 0) { 53858f0484fSRodney W. Grimes _kvm_syserr(kd, kd->program, "kvm_read"); 53958f0484fSRodney W. Grimes break; 54058f0484fSRodney W. Grimes } 54158f0484fSRodney W. Grimes /* 542c10970ddSUlrich Spörlein * If kvm_kvatop returns a bogus value or our core file is 543c10970ddSUlrich Spörlein * truncated, we might wind up seeking beyond the end of the 544c10970ddSUlrich Spörlein * core file in which case the read will return 0 (EOF). 54558f0484fSRodney W. Grimes */ 546c10970ddSUlrich Spörlein if (cr == 0) 54758f0484fSRodney W. Grimes break; 548c10970ddSUlrich Spörlein cp += cr; 549c10970ddSUlrich Spörlein kva += cr; 550c10970ddSUlrich Spörlein len -= cr; 55158f0484fSRodney W. Grimes } 552c10970ddSUlrich Spörlein 5531a5ff928SStefan Farfeleder return (cp - (char *)buf); 55458f0484fSRodney W. Grimes } 55558f0484fSRodney W. Grimes 55658f0484fSRodney W. Grimes ssize_t 557c10970ddSUlrich Spörlein kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) 55858f0484fSRodney W. Grimes { 559be04b6d1SDavid E. O'Brien int cc; 56058f0484fSRodney W. Grimes 56158f0484fSRodney W. Grimes if (ISALIVE(kd)) { 56258f0484fSRodney W. Grimes /* 56358f0484fSRodney W. Grimes * Just like kvm_read, only we write. 56458f0484fSRodney W. Grimes */ 56558f0484fSRodney W. Grimes errno = 0; 56658f0484fSRodney W. Grimes if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 567c10970ddSUlrich Spörlein _kvm_err(kd, 0, "invalid address (%lx)", kva); 56891a594d8SJacques Vidrine return (-1); 56958f0484fSRodney W. Grimes } 57058f0484fSRodney W. Grimes cc = write(kd->vmfd, buf, len); 57158f0484fSRodney W. Grimes if (cc < 0) { 57258f0484fSRodney W. Grimes _kvm_syserr(kd, 0, "kvm_write"); 57391a594d8SJacques Vidrine return (-1); 574c10970ddSUlrich Spörlein } else if ((size_t)cc < len) 57558f0484fSRodney W. Grimes _kvm_err(kd, kd->program, "short write"); 57658f0484fSRodney W. Grimes return (cc); 57758f0484fSRodney W. Grimes } else { 57858f0484fSRodney W. Grimes _kvm_err(kd, kd->program, 57958f0484fSRodney W. Grimes "kvm_write not implemented for dead kernels"); 58091a594d8SJacques Vidrine return (-1); 58158f0484fSRodney W. Grimes } 58258f0484fSRodney W. Grimes /* NOTREACHED */ 58358f0484fSRodney W. Grimes } 584