xref: /freebsd/lib/libkvm/kvm.c (revision 76dce67f0f14ec28297a51e190e03f5a670f265f)
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