kvm.c revision 83551
1/*-
2 * Copyright (c) 1989, 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software developed by the Computer Systems
6 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7 * BG 91-66 and contributed to Berkeley.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: head/lib/libkvm/kvm.c 83551 2001-09-16 21:35:07Z dillon $");
40
41#if defined(LIBC_SCCS) && !defined(lint)
42#if 0
43static char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
44#endif
45#endif /* LIBC_SCCS and not lint */
46
47#include <sys/param.h>
48#include <sys/lock.h>
49#include <sys/mutex.h>
50#include <sys/user.h>
51#include <sys/proc.h>
52#include <sys/ioctl.h>
53#include <sys/stat.h>
54#include <sys/sysctl.h>
55#include <sys/linker.h>
56
57#include <vm/vm.h>
58#include <vm/vm_param.h>
59#include <vm/swap_pager.h>
60
61#include <machine/vmparam.h>
62
63#include <ctype.h>
64#include <fcntl.h>
65#include <kvm.h>
66#include <limits.h>
67#include <nlist.h>
68#include <paths.h>
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#include <unistd.h>
73
74#include "kvm_private.h"
75
76/* from src/lib/libc/gen/nlist.c */
77int __fdnlist		__P((int, struct nlist *));
78
79char *
80kvm_geterr(kd)
81	kvm_t *kd;
82{
83	return (kd->errbuf);
84}
85
86#if __STDC__
87#include <stdarg.h>
88#else
89#include <varargs.h>
90#endif
91
92/*
93 * Report an error using printf style arguments.  "program" is kd->program
94 * on hard errors, and 0 on soft errors, so that under sun error emulation,
95 * only hard errors are printed out (otherwise, programs like gdb will
96 * generate tons of error messages when trying to access bogus pointers).
97 */
98void
99#if __STDC__
100_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
101#else
102_kvm_err(kd, program, fmt, va_alist)
103	kvm_t *kd;
104	char *program, *fmt;
105	va_dcl
106#endif
107{
108	va_list ap;
109
110#ifdef __STDC__
111	va_start(ap, fmt);
112#else
113	va_start(ap);
114#endif
115	if (program != NULL) {
116		(void)fprintf(stderr, "%s: ", program);
117		(void)vfprintf(stderr, fmt, ap);
118		(void)fputc('\n', stderr);
119	} else
120		(void)vsnprintf(kd->errbuf,
121		    sizeof(kd->errbuf), (char *)fmt, ap);
122
123	va_end(ap);
124}
125
126void
127#if __STDC__
128_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
129#else
130_kvm_syserr(kd, program, fmt, va_alist)
131	kvm_t *kd;
132	char *program, *fmt;
133	va_dcl
134#endif
135{
136	va_list ap;
137	register int n;
138
139#if __STDC__
140	va_start(ap, fmt);
141#else
142	va_start(ap);
143#endif
144	if (program != NULL) {
145		(void)fprintf(stderr, "%s: ", program);
146		(void)vfprintf(stderr, fmt, ap);
147		(void)fprintf(stderr, ": %s\n", strerror(errno));
148	} else {
149		register char *cp = kd->errbuf;
150
151		(void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
152		n = strlen(cp);
153		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
154		    strerror(errno));
155	}
156	va_end(ap);
157}
158
159void *
160_kvm_malloc(kd, n)
161	register kvm_t *kd;
162	register size_t n;
163{
164	void *p;
165
166	if ((p = calloc(n, sizeof(char))) == NULL)
167		_kvm_err(kd, kd->program, "can't allocate %u bytes: %s",
168			 n, strerror(errno));
169	return (p);
170}
171
172static kvm_t *
173_kvm_open(kd, uf, mf, flag, errout)
174	register kvm_t *kd;
175	const char *uf;
176	const char *mf;
177	int flag;
178	char *errout;
179{
180	struct stat st;
181
182	kd->vmfd = -1;
183	kd->pmfd = -1;
184	kd->nlfd = -1;
185	kd->vmst = 0;
186	kd->procbase = 0;
187	kd->argspc = 0;
188	kd->argv = 0;
189
190	if (uf == 0)
191		uf = getbootfile();
192	else if (strlen(uf) >= MAXPATHLEN) {
193		_kvm_err(kd, kd->program, "exec file name too long");
194		goto failed;
195	}
196	if (flag & ~O_RDWR) {
197		_kvm_err(kd, kd->program, "bad flags arg");
198		goto failed;
199	}
200	if (mf == 0)
201		mf = _PATH_MEM;
202
203	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
204		_kvm_syserr(kd, kd->program, "%s", mf);
205		goto failed;
206	}
207	if (fstat(kd->pmfd, &st) < 0) {
208		_kvm_syserr(kd, kd->program, "%s", mf);
209		goto failed;
210	}
211	if (S_ISCHR(st.st_mode)) {
212		/*
213		 * If this is a character special device, then check that
214		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
215		 * make it work for either /dev/mem or /dev/kmem -- in either
216		 * case you're working with a live kernel.)
217		 */
218		if (strcmp(mf, _PATH_DEVNULL) == 0) {
219			kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
220		} else if (strcmp(mf, _PATH_MEM) != 0) {
221			_kvm_err(kd, kd->program,
222				 "%s: not physical memory device", mf);
223			goto failed;
224		} else {
225			if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
226				_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
227				goto failed;
228			}
229		}
230	} else {
231		/*
232		 * This is a crash dump.
233		 * Initialize the virtual address translation machinery,
234		 * but first setup the namelist fd.
235		 */
236		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
237			_kvm_syserr(kd, kd->program, "%s", uf);
238			goto failed;
239		}
240		if (_kvm_initvtop(kd) < 0)
241			goto failed;
242	}
243	return (kd);
244failed:
245	/*
246	 * Copy out the error if doing sane error semantics.
247	 */
248	if (errout != 0)
249		strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
250	(void)kvm_close(kd);
251	return (0);
252}
253
254kvm_t *
255kvm_openfiles(uf, mf, sf, flag, errout)
256	const char *uf;
257	const char *mf;
258	const char *sf;
259	int flag;
260	char *errout;
261{
262	register kvm_t *kd;
263
264	if ((kd = malloc(sizeof(*kd))) == NULL) {
265		(void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
266		return (0);
267	}
268	memset(kd, 0, sizeof(*kd));
269	kd->program = 0;
270	return (_kvm_open(kd, uf, mf, flag, errout));
271}
272
273kvm_t *
274kvm_open(uf, mf, sf, flag, errstr)
275	const char *uf;
276	const char *mf;
277	const char *sf;
278	int flag;
279	const char *errstr;
280{
281	register kvm_t *kd;
282
283	if ((kd = malloc(sizeof(*kd))) == NULL) {
284		if (errstr != NULL)
285			(void)fprintf(stderr, "%s: %s\n",
286				      errstr, strerror(errno));
287		return (0);
288	}
289	memset(kd, 0, sizeof(*kd));
290	kd->program = errstr;
291	return (_kvm_open(kd, uf, mf, flag, NULL));
292}
293
294int
295kvm_close(kd)
296	kvm_t *kd;
297{
298	register int error = 0;
299
300	if (kd->pmfd >= 0)
301		error |= close(kd->pmfd);
302	if (kd->vmfd >= 0)
303		error |= close(kd->vmfd);
304	if (kd->nlfd >= 0)
305		error |= close(kd->nlfd);
306	if (kd->vmst)
307		_kvm_freevtop(kd);
308	if (kd->procbase != 0)
309		free((void *)kd->procbase);
310	if (kd->argv != 0)
311		free((void *)kd->argv);
312	free((void *)kd);
313
314	return (0);
315}
316
317int
318kvm_nlist(kd, nl)
319	kvm_t *kd;
320	struct nlist *nl;
321{
322	register struct nlist *p;
323	register int nvalid;
324	struct kld_sym_lookup lookup;
325
326	/*
327	 * If we can't use the kld symbol lookup, revert to the
328	 * slow library call.
329	 */
330	if (!ISALIVE(kd))
331		return (__fdnlist(kd->nlfd, nl));
332
333	/*
334	 * We can use the kld lookup syscall.  Go through each nlist entry
335	 * and look it up with a kldsym(2) syscall.
336	 */
337	nvalid = 0;
338	for (p = nl; p->n_name && p->n_name[0]; ++p) {
339		lookup.version = sizeof(lookup);
340		lookup.symname = p->n_name;
341		lookup.symvalue = 0;
342		lookup.symsize = 0;
343
344		if (lookup.symname[0] == '_')
345			lookup.symname++;
346
347		if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) {
348			p->n_type = N_TEXT;
349			p->n_other = 0;
350			p->n_desc = 0;
351			p->n_value = lookup.symvalue;
352			++nvalid;
353			/* lookup.symsize */
354		}
355	}
356	/*
357	 * Return the number of entries that weren't found.
358	 */
359	return ((p - nl) - nvalid);
360}
361
362ssize_t
363kvm_read(kd, kva, buf, len)
364	kvm_t *kd;
365	register u_long kva;
366	register void *buf;
367	register size_t len;
368{
369	register int cc;
370	register void *cp;
371
372	if (ISALIVE(kd)) {
373		/*
374		 * We're using /dev/kmem.  Just read straight from the
375		 * device and let the active kernel do the address translation.
376		 */
377		errno = 0;
378		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
379			_kvm_err(kd, 0, "invalid address (%x)", kva);
380			return (-1);
381		}
382		cc = read(kd->vmfd, buf, len);
383		if (cc < 0) {
384			_kvm_syserr(kd, 0, "kvm_read");
385			return (-1);
386		} else if (cc < len)
387			_kvm_err(kd, kd->program, "short read");
388		return (cc);
389	} else {
390		cp = buf;
391		while (len > 0) {
392			u_long pa;
393
394			cc = _kvm_kvatop(kd, kva, &pa);
395			if (cc == 0)
396				return (-1);
397			if (cc > len)
398				cc = len;
399			errno = 0;
400			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
401				_kvm_syserr(kd, 0, _PATH_MEM);
402				break;
403			}
404			cc = read(kd->pmfd, cp, cc);
405			if (cc < 0) {
406				_kvm_syserr(kd, kd->program, "kvm_read");
407				break;
408			}
409			/*
410			 * If kvm_kvatop returns a bogus value or our core
411			 * file is truncated, we might wind up seeking beyond
412			 * the end of the core file in which case the read will
413			 * return 0 (EOF).
414			 */
415			if (cc == 0)
416				break;
417			(char *)cp += cc;
418			kva += cc;
419			len -= cc;
420		}
421		return ((char *)cp - (char *)buf);
422	}
423	/* NOTREACHED */
424}
425
426ssize_t
427kvm_write(kd, kva, buf, len)
428	kvm_t *kd;
429	register u_long kva;
430	register const void *buf;
431	register size_t len;
432{
433	register int cc;
434
435	if (ISALIVE(kd)) {
436		/*
437		 * Just like kvm_read, only we write.
438		 */
439		errno = 0;
440		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
441			_kvm_err(kd, 0, "invalid address (%x)", kva);
442			return (-1);
443		}
444		cc = write(kd->vmfd, buf, len);
445		if (cc < 0) {
446			_kvm_syserr(kd, 0, "kvm_write");
447			return (-1);
448		} else if (cc < len)
449			_kvm_err(kd, kd->program, "short write");
450		return (cc);
451	} else {
452		_kvm_err(kd, kd->program,
453		    "kvm_write not implemented for dead kernels");
454		return (-1);
455	}
456	/* NOTREACHED */
457}
458