kvm.c revision 147672
117683Spst/*-
239291Sfenner * Copyright (c) 1989, 1992, 1993
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * This code is derived from software developed by the Computer Systems
617683Spst * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
717683Spst * BG 91-66 and contributed to Berkeley.
817683Spst *
917683Spst * Redistribution and use in source and binary forms, with or without
1017683Spst * modification, are permitted provided that the following conditions
1117683Spst * are met:
1217683Spst * 1. Redistributions of source code must retain the above copyright
1317683Spst *    notice, this list of conditions and the following disclaimer.
1417683Spst * 2. Redistributions in binary form must reproduce the above copyright
1517683Spst *    notice, this list of conditions and the following disclaimer in the
1617683Spst *    documentation and/or other materials provided with the distribution.
1717683Spst * 3. All advertising materials mentioning features or use of this software
1817683Spst *    must display the following acknowledgement:
1917683Spst *	This product includes software developed by the University of
20162020Ssam *	California, Berkeley and its contributors.
21162020Ssam * 4. Neither the name of the University nor the names of its contributors
2217683Spst *    may be used to endorse or promote products derived from this software
2317683Spst *    without specific prior written permission.
24127664Sbms *
25172680Smlaier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2617683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2717683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2875107Sfenner * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2975107Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3075107Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3175107Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3217683Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33183102Scsjp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3417683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3517683Spst * SUCH DAMAGE.
3617683Spst */
3717683Spst
3817683Spst#include <sys/cdefs.h>
39127664Sbms__FBSDID("$FreeBSD: head/lib/libkvm/kvm.c 147672 2005-06-29 22:39:41Z peter $");
4017683Spst
4117683Spst#if defined(LIBC_SCCS) && !defined(lint)
42127664Sbms#if 0
4398530Sfennerstatic char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
44127664Sbms#endif
4598530Sfenner#endif /* LIBC_SCCS and not lint */
46127664Sbms
47127664Sbms#include <sys/param.h>
4898530Sfenner#include <sys/user.h>
49127664Sbms#include <sys/proc.h>
50127664Sbms#include <sys/ioctl.h>
51127664Sbms#include <sys/stat.h>
52127664Sbms#include <sys/sysctl.h>
53127664Sbms#include <sys/linker.h>
54127664Sbms
55127664Sbms#include <vm/vm.h>
56127664Sbms#include <vm/vm_param.h>
57127664Sbms
58127664Sbms#include <machine/vmparam.h>
59127664Sbms
60127664Sbms#include <ctype.h>
61127664Sbms#include <fcntl.h>
6298530Sfenner#include <kvm.h>
63127664Sbms#include <limits.h>
64127664Sbms#include <nlist.h>
65147894Ssam#include <paths.h>
66127664Sbms#include <stdio.h>
6717683Spst#include <stdlib.h>
68127664Sbms#include <string.h>
69127664Sbms#include <unistd.h>
70127664Sbms
71127664Sbms#include "kvm_private.h"
72127664Sbms
73127664Sbms/* from src/lib/libc/gen/nlist.c */
74127664Sbmsint __fdnlist(int, struct nlist *);
75127664Sbms
76127664Sbmschar *
77127664Sbmskvm_geterr(kd)
78127664Sbms	kvm_t *kd;
79127664Sbms{
80127664Sbms	return (kd->errbuf);
81127664Sbms}
82127664Sbms
83127664Sbms#include <stdarg.h>
84127664Sbms
85127664Sbms/*
86127664Sbms * Report an error using printf style arguments.  "program" is kd->program
87127664Sbms * on hard errors, and 0 on soft errors, so that under sun error emulation,
88127664Sbms * only hard errors are printed out (otherwise, programs like gdb will
89127664Sbms * generate tons of error messages when trying to access bogus pointers).
90183102Scsjp */
91183102Scsjpvoid
92183102Scsjp_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
93183102Scsjp{
9417683Spst	va_list ap;
9517683Spst
9617683Spst	va_start(ap, fmt);
9717683Spst	if (program != NULL) {
9817683Spst		(void)fprintf(stderr, "%s: ", program);
9917683Spst		(void)vfprintf(stderr, fmt, ap);
10017683Spst		(void)fputc('\n', stderr);
10117683Spst	} else
10217683Spst		(void)vsnprintf(kd->errbuf,
10317683Spst		    sizeof(kd->errbuf), (char *)fmt, ap);
104127664Sbms
105127664Sbms	va_end(ap);
106127664Sbms}
107127664Sbms
10817683Spstvoid
10917683Spst_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
11017683Spst{
11117683Spst	va_list ap;
112127664Sbms	int n;
11356889Sfenner
114127664Sbms	va_start(ap, fmt);
115162012Ssam	if (program != NULL) {
116127664Sbms		(void)fprintf(stderr, "%s: ", program);
117127664Sbms		(void)vfprintf(stderr, fmt, ap);
118127664Sbms		(void)fprintf(stderr, ": %s\n", strerror(errno));
119127664Sbms	} else {
12017683Spst		char *cp = kd->errbuf;
12117683Spst
12217683Spst		(void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
12398530Sfenner		n = strlen(cp);
12498530Sfenner		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
12598530Sfenner		    strerror(errno));
12698530Sfenner	}
12798530Sfenner	va_end(ap);
12898530Sfenner}
12998530Sfenner
13098530Sfennervoid *
13198530Sfenner_kvm_malloc(kd, n)
13298530Sfenner	kvm_t *kd;
13398530Sfenner	size_t n;
13498530Sfenner{
13598530Sfenner	void *p;
13617683Spst
13775107Sfenner	if ((p = calloc(n, sizeof(char))) == NULL)
13875107Sfenner		_kvm_err(kd, kd->program, "can't allocate %u bytes: %s",
13917683Spst			 n, strerror(errno));
14017683Spst	return (p);
14117683Spst}
14217683Spst
14317683Spststatic kvm_t *
14417683Spst_kvm_open(kd, uf, mf, flag, errout)
14517683Spst	kvm_t *kd;
14617683Spst	const char *uf;
147183102Scsjp	const char *mf;
148183102Scsjp	int flag;
149183102Scsjp	char *errout;
150183102Scsjp{
151183102Scsjp	struct stat st;
152183102Scsjp
153183102Scsjp	kd->vmfd = -1;
154183102Scsjp	kd->pmfd = -1;
155183102Scsjp	kd->nlfd = -1;
156183102Scsjp	kd->vmst = 0;
157127664Sbms	kd->procbase = 0;
158183102Scsjp	kd->argspc = 0;
159183102Scsjp	kd->argv = 0;
160183102Scsjp
161183102Scsjp	if (uf == 0)
162183102Scsjp		uf = getbootfile();
163183102Scsjp	else if (strlen(uf) >= MAXPATHLEN) {
164183102Scsjp		_kvm_err(kd, kd->program, "exec file name too long");
165183102Scsjp		goto failed;
166183102Scsjp	}
167183102Scsjp	if (flag & ~O_RDWR) {
168183102Scsjp		_kvm_err(kd, kd->program, "bad flags arg");
169183102Scsjp		goto failed;
170183102Scsjp	}
171183102Scsjp	if (mf == 0)
172183102Scsjp		mf = _PATH_MEM;
173183102Scsjp
174183102Scsjp	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
175183102Scsjp		_kvm_syserr(kd, kd->program, "%s", mf);
176183102Scsjp		goto failed;
177183102Scsjp	}
178183102Scsjp	if (fstat(kd->pmfd, &st) < 0) {
179183102Scsjp		_kvm_syserr(kd, kd->program, "%s", mf);
180183102Scsjp		goto failed;
181183102Scsjp	}
182183102Scsjp	if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) {
183183102Scsjp		_kvm_syserr(kd, kd->program, "%s", mf);
184183102Scsjp		goto failed;
185183102Scsjp	}
186183102Scsjp	if (S_ISCHR(st.st_mode)) {
187183102Scsjp		/*
188183102Scsjp		 * If this is a character special device, then check that
189183102Scsjp		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
190183102Scsjp		 * make it work for either /dev/mem or /dev/kmem -- in either
191183102Scsjp		 * case you're working with a live kernel.)
192183102Scsjp		 */
193183102Scsjp		if (strcmp(mf, _PATH_DEVNULL) == 0) {
194183102Scsjp			kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
195183102Scsjp			return (kd);
196183102Scsjp		} else if (strcmp(mf, _PATH_MEM) == 0) {
197183102Scsjp			if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
198183102Scsjp				_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
199183102Scsjp				goto failed;
200183102Scsjp			}
201183102Scsjp			if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) {
202183102Scsjp				_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
203183102Scsjp				goto failed;
204183102Scsjp			}
205183102Scsjp			return (kd);
206183102Scsjp		}
207183102Scsjp	}
208183102Scsjp	/*
209183102Scsjp	 * This is a crash dump.
210183102Scsjp	 * Initialize the virtual address translation machinery,
211183102Scsjp	 * but first setup the namelist fd.
212183102Scsjp	 */
213183102Scsjp	if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
214183102Scsjp		_kvm_syserr(kd, kd->program, "%s", uf);
215183102Scsjp		goto failed;
216183102Scsjp	}
217183102Scsjp	if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) {
218183102Scsjp		_kvm_syserr(kd, kd->program, "%s", uf);
219183102Scsjp		goto failed;
220183102Scsjp	}
221183102Scsjp	if (_kvm_initvtop(kd) < 0)
222183102Scsjp		goto failed;
223183102Scsjp	return (kd);
224183102Scsjpfailed:
225183102Scsjp	/*
226183102Scsjp	 * Copy out the error if doing sane error semantics.
227183102Scsjp	 */
228183102Scsjp	if (errout != 0)
229183102Scsjp		strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
230183102Scsjp	(void)kvm_close(kd);
231183102Scsjp	return (0);
232183102Scsjp}
233183102Scsjp
234183102Scsjpkvm_t *
235183102Scsjpkvm_openfiles(uf, mf, sf, flag, errout)
236183102Scsjp	const char *uf;
237183102Scsjp	const char *mf;
238183102Scsjp	const char *sf __unused;
239183102Scsjp	int flag;
240183102Scsjp	char *errout;
241183102Scsjp{
242183102Scsjp	kvm_t *kd;
243183102Scsjp
244183102Scsjp	if ((kd = malloc(sizeof(*kd))) == NULL) {
245183102Scsjp		(void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
246183102Scsjp		return (0);
247183102Scsjp	}
248183102Scsjp	memset(kd, 0, sizeof(*kd));
249183102Scsjp	kd->program = 0;
250183102Scsjp	return (_kvm_open(kd, uf, mf, flag, errout));
251183102Scsjp}
252183102Scsjp
253183102Scsjpkvm_t *
254183102Scsjpkvm_open(uf, mf, sf, flag, errstr)
255183102Scsjp	const char *uf;
256183102Scsjp	const char *mf;
257183102Scsjp	const char *sf __unused;
258183102Scsjp	int flag;
259183102Scsjp	const char *errstr;
260183102Scsjp{
261183102Scsjp	kvm_t *kd;
262183102Scsjp
263183102Scsjp	if ((kd = malloc(sizeof(*kd))) == NULL) {
264183102Scsjp		if (errstr != NULL)
265183102Scsjp			(void)fprintf(stderr, "%s: %s\n",
266183102Scsjp				      errstr, strerror(errno));
267183102Scsjp		return (0);
268183102Scsjp	}
269183102Scsjp	memset(kd, 0, sizeof(*kd));
270183102Scsjp	kd->program = errstr;
271183102Scsjp	return (_kvm_open(kd, uf, mf, flag, NULL));
272183102Scsjp}
273183102Scsjp
274183102Scsjpint
275183102Scsjpkvm_close(kd)
276183102Scsjp	kvm_t *kd;
277183102Scsjp{
278183102Scsjp	int error = 0;
279183102Scsjp
280183102Scsjp	if (kd->pmfd >= 0)
281183102Scsjp		error |= close(kd->pmfd);
282183102Scsjp	if (kd->vmfd >= 0)
283183102Scsjp		error |= close(kd->vmfd);
284183102Scsjp	if (kd->nlfd >= 0)
285183102Scsjp		error |= close(kd->nlfd);
286183102Scsjp	if (kd->vmst)
287183102Scsjp		_kvm_freevtop(kd);
288183102Scsjp	if (kd->procbase != 0)
289183102Scsjp		free((void *)kd->procbase);
290183102Scsjp	if (kd->argv != 0)
291183102Scsjp		free((void *)kd->argv);
292183102Scsjp	free((void *)kd);
293183102Scsjp
294183102Scsjp	return (0);
295183102Scsjp}
296183102Scsjp
297183102Scsjpint
298183102Scsjpkvm_nlist(kd, nl)
299183102Scsjp	kvm_t *kd;
300183102Scsjp	struct nlist *nl;
301127664Sbms{
30217683Spst	struct nlist *p;
30317683Spst	int nvalid;
30417683Spst	struct kld_sym_lookup lookup;
30517683Spst
306146768Ssam	/*
307127664Sbms	 * If we can't use the kld symbol lookup, revert to the
308183102Scsjp	 * slow library call.
309183102Scsjp	 */
310183102Scsjp	if (!ISALIVE(kd))
311146768Ssam		return (__fdnlist(kd->nlfd, nl));
312146768Ssam
313146768Ssam	/*
31417683Spst	 * We can use the kld lookup syscall.  Go through each nlist entry
315127664Sbms	 * and look it up with a kldsym(2) syscall.
31617683Spst	 */
317127664Sbms	nvalid = 0;
318127664Sbms	for (p = nl; p->n_name && p->n_name[0]; ++p) {
319127664Sbms		lookup.version = sizeof(lookup);
320127664Sbms		lookup.symname = p->n_name;
321127664Sbms		lookup.symvalue = 0;
322127664Sbms		lookup.symsize = 0;
323127664Sbms
324127664Sbms		if (lookup.symname[0] == '_')
325127664Sbms			lookup.symname++;
326127664Sbms
327127664Sbms		if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) {
328127664Sbms			p->n_type = N_TEXT;
32917683Spst			p->n_other = 0;
33017683Spst			p->n_desc = 0;
331183102Scsjp			p->n_value = lookup.symvalue;
332183102Scsjp			++nvalid;
333183102Scsjp			/* lookup.symsize */
334183102Scsjp		}
335183102Scsjp	}
336183102Scsjp	/*
337183102Scsjp	 * Return the number of entries that weren't found.
338183102Scsjp	 */
339183102Scsjp	return ((p - nl) - nvalid);
340183102Scsjp}
341183102Scsjp
342183102Scsjpssize_t
343183102Scsjpkvm_read(kd, kva, buf, len)
344183102Scsjp	kvm_t *kd;
345183102Scsjp	u_long kva;
346183102Scsjp	void *buf;
347183102Scsjp	size_t len;
348183102Scsjp{
349183102Scsjp	int cc;
350183102Scsjp	char *cp;
351183102Scsjp
35217683Spst	if (ISALIVE(kd)) {
35317683Spst		/*
35417683Spst		 * We're using /dev/kmem.  Just read straight from the
35517683Spst		 * device and let the active kernel do the address translation.
35617683Spst		 */
35717683Spst		errno = 0;
35817683Spst		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
359127664Sbms			_kvm_err(kd, 0, "invalid address (%x)", kva);
360127664Sbms			return (-1);
361127664Sbms		}
362127664Sbms		cc = read(kd->vmfd, buf, len);
363127664Sbms		if (cc < 0) {
364127664Sbms			_kvm_syserr(kd, 0, "kvm_read");
365127664Sbms			return (-1);
366127664Sbms		} else if (cc < len)
367127664Sbms			_kvm_err(kd, kd->program, "short read");
368127664Sbms		return (cc);
369127664Sbms	} else {
370127664Sbms		cp = buf;
371127664Sbms		while (len > 0) {
372127664Sbms			off_t pa;
373127664Sbms
374127664Sbms			cc = _kvm_kvatop(kd, kva, &pa);
375127664Sbms			if (cc == 0)
376127664Sbms				return (-1);
377127664Sbms			if (cc > len)
378127664Sbms				cc = len;
379127664Sbms			errno = 0;
380127664Sbms			if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
381127664Sbms				_kvm_syserr(kd, 0, _PATH_MEM);
382127664Sbms				break;
383127664Sbms			}
384127664Sbms			cc = read(kd->pmfd, cp, cc);
38517683Spst			if (cc < 0) {
38617683Spst				_kvm_syserr(kd, kd->program, "kvm_read");
38717683Spst				break;
38817683Spst			}
38917683Spst			/*
39017683Spst			 * If kvm_kvatop returns a bogus value or our core
39117683Spst			 * file is truncated, we might wind up seeking beyond
39217683Spst			 * the end of the core file in which case the read will
39317683Spst			 * return 0 (EOF).
39417683Spst			 */
39517683Spst			if (cc == 0)
39617683Spst				break;
39717683Spst			cp += cc;
39817683Spst			kva += cc;
39917683Spst			len -= cc;
40017683Spst		}
40117683Spst		return (cp - (char *)buf);
40275107Sfenner	}
40375107Sfenner	/* NOTREACHED */
40417683Spst}
40517683Spst
40617683Spstssize_t
40717683Spstkvm_write(kd, kva, buf, len)
40817683Spst	kvm_t *kd;
40917683Spst	u_long kva;
41017683Spst	const void *buf;
41117683Spst	size_t len;
41217683Spst{
41317683Spst	int cc;
41417683Spst
415146768Ssam	if (ISALIVE(kd)) {
416146768Ssam		/*
417146768Ssam		 * Just like kvm_read, only we write.
41817683Spst		 */
41917683Spst		errno = 0;
420127664Sbms		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
421127664Sbms			_kvm_err(kd, 0, "invalid address (%x)", kva);
422127664Sbms			return (-1);
423127664Sbms		}
424127664Sbms		cc = write(kd->vmfd, buf, len);
425127664Sbms		if (cc < 0) {
426127664Sbms			_kvm_syserr(kd, 0, "kvm_write");
427127664Sbms			return (-1);
428127664Sbms		} else if (cc < len)
429127664Sbms			_kvm_err(kd, kd->program, "short write");
430127664Sbms		return (cc);
431127664Sbms	} else {
432127664Sbms		_kvm_err(kd, kd->program,
433127664Sbms		    "kvm_write not implemented for dead kernels");
434127664Sbms		return (-1);
435127664Sbms	}
436127664Sbms	/* NOTREACHED */
437127664Sbms}
438127664Sbms