kvm.c revision 37316
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#if defined(LIBC_SCCS) && !defined(lint)
39static char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
40#endif /* LIBC_SCCS and not lint */
41
42#include <sys/param.h>
43#include <sys/user.h>
44#include <sys/proc.h>
45#include <sys/ioctl.h>
46#include <sys/stat.h>
47#include <sys/sysctl.h>
48
49#include <vm/vm.h>
50#include <vm/vm_param.h>
51#include <vm/swap_pager.h>
52
53#include <machine/vmparam.h>
54
55#include <ctype.h>
56#include <db.h>
57#include <fcntl.h>
58#include <kvm.h>
59#include <limits.h>
60#include <nlist.h>
61#include <paths.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66
67#include "kvm_private.h"
68
69static int kvm_dbopen __P((kvm_t *, const char *));
70
71char *
72kvm_geterr(kd)
73	kvm_t *kd;
74{
75	return (kd->errbuf);
76}
77
78#if __STDC__
79#include <stdarg.h>
80#else
81#include <varargs.h>
82#endif
83
84/*
85 * Report an error using printf style arguments.  "program" is kd->program
86 * on hard errors, and 0 on soft errors, so that under sun error emulation,
87 * only hard errors are printed out (otherwise, programs like gdb will
88 * generate tons of error messages when trying to access bogus pointers).
89 */
90void
91#if __STDC__
92_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
93#else
94_kvm_err(kd, program, fmt, va_alist)
95	kvm_t *kd;
96	char *program, *fmt;
97	va_dcl
98#endif
99{
100	va_list ap;
101
102#ifdef __STDC__
103	va_start(ap, fmt);
104#else
105	va_start(ap);
106#endif
107	if (program != NULL) {
108		(void)fprintf(stderr, "%s: ", program);
109		(void)vfprintf(stderr, fmt, ap);
110		(void)fputc('\n', stderr);
111	} else
112		(void)vsnprintf(kd->errbuf,
113		    sizeof(kd->errbuf), (char *)fmt, ap);
114
115	va_end(ap);
116}
117
118void
119#if __STDC__
120_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
121#else
122_kvm_syserr(kd, program, fmt, va_alist)
123	kvm_t *kd;
124	char *program, *fmt;
125	va_dcl
126#endif
127{
128	va_list ap;
129	register int n;
130
131#if __STDC__
132	va_start(ap, fmt);
133#else
134	va_start(ap);
135#endif
136	if (program != NULL) {
137		(void)fprintf(stderr, "%s: ", program);
138		(void)vfprintf(stderr, fmt, ap);
139		(void)fprintf(stderr, ": %s\n", strerror(errno));
140	} else {
141		register char *cp = kd->errbuf;
142
143		(void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
144		n = strlen(cp);
145		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
146		    strerror(errno));
147	}
148	va_end(ap);
149}
150
151void *
152_kvm_malloc(kd, n)
153	register kvm_t *kd;
154	register size_t n;
155{
156	void *p;
157
158	if ((p = calloc(n, sizeof(char))) == NULL)
159		_kvm_err(kd, kd->program, "can't allocate %u bytes: %s",
160			 n, strerror(errno));
161	return (p);
162}
163
164static kvm_t *
165_kvm_open(kd, uf, mf, sf, flag, errout)
166	register kvm_t *kd;
167	const char *uf;
168	const char *mf;
169	const char *sf;
170	int flag;
171	char *errout;
172{
173	struct stat st;
174
175	kd->vmfd = -1;
176	kd->pmfd = -1;
177	kd->swfd = -1;
178	kd->nlfd = -1;
179	kd->vmst = 0;
180	kd->db = 0;
181	kd->procbase = 0;
182	kd->argspc = 0;
183	kd->argv = 0;
184
185	if (uf == 0)
186		uf = getbootfile();
187	else if (strlen(uf) >= MAXPATHLEN) {
188		_kvm_err(kd, kd->program, "exec file name too long");
189		goto failed;
190	}
191	if (flag & ~O_RDWR) {
192		_kvm_err(kd, kd->program, "bad flags arg");
193		goto failed;
194	}
195	if (mf == 0)
196		mf = _PATH_MEM;
197	if (sf == 0)
198		sf = _PATH_DRUM;
199
200	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
201		_kvm_syserr(kd, kd->program, "%s", mf);
202		goto failed;
203	}
204	if (fstat(kd->pmfd, &st) < 0) {
205		_kvm_syserr(kd, kd->program, "%s", mf);
206		goto failed;
207	}
208	if (S_ISCHR(st.st_mode)) {
209		/*
210		 * If this is a character special device, then check that
211		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
212		 * make it work for either /dev/mem or /dev/kmem -- in either
213		 * case you're working with a live kernel.)
214		 */
215		if (strcmp(mf, _PATH_DEVNULL) == 0) {
216			kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
217			kd->swfd = open(_PATH_DEVNULL, O_RDONLY);
218		} else if (strcmp(mf, _PATH_MEM) != 0) {
219			_kvm_err(kd, kd->program,
220				 "%s: not physical memory device", mf);
221			goto failed;
222		} else {
223			if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
224				_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
225				goto failed;
226			}
227			if ((kd->swfd = open(sf, flag, 0)) < 0) {
228				_kvm_syserr(kd, kd->program, "%s", sf);
229				goto failed;
230			}
231		}
232		/*
233		 * Open kvm nlist database.  We go ahead and do this
234		 * here so that we don't have to hold on to the kernel
235		 * path name.  Since a kvm application will surely do
236		 * a kvm_nlist(), this probably won't be a wasted effort.
237		 * If the database cannot be opened, open the namelist
238		 * argument so we revert to slow nlist() calls.
239		 */
240		if (kvm_dbopen(kd, uf) < 0 &&
241		    (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
242			_kvm_syserr(kd, kd->program, "%s", uf);
243			goto failed;
244		}
245	} else {
246		/*
247		 * This is a crash dump.
248		 * Initialize the virtual address translation machinery,
249		 * but first setup the namelist fd.
250		 */
251		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
252			_kvm_syserr(kd, kd->program, "%s", uf);
253			goto failed;
254		}
255		if (_kvm_initvtop(kd) < 0)
256			goto failed;
257	}
258	return (kd);
259failed:
260	/*
261	 * Copy out the error if doing sane error semantics.
262	 */
263	if (errout != 0)
264		strcpy(errout, kd->errbuf);
265	(void)kvm_close(kd);
266	return (0);
267}
268
269kvm_t *
270kvm_openfiles(uf, mf, sf, flag, errout)
271	const char *uf;
272	const char *mf;
273	const char *sf;
274	int flag;
275	char *errout;
276{
277	register kvm_t *kd;
278
279	if ((kd = malloc(sizeof(*kd))) == NULL) {
280		(void)strcpy(errout, strerror(errno));
281		return (0);
282	}
283	memset(kd, 0, sizeof(*kd));
284	kd->program = 0;
285	return (_kvm_open(kd, uf, mf, sf, flag, errout));
286}
287
288kvm_t *
289kvm_open(uf, mf, sf, flag, errstr)
290	const char *uf;
291	const char *mf;
292	const char *sf;
293	int flag;
294	const char *errstr;
295{
296	register kvm_t *kd;
297
298	if ((kd = malloc(sizeof(*kd))) == NULL) {
299		if (errstr != NULL)
300			(void)fprintf(stderr, "%s: %s\n",
301				      errstr, strerror(errno));
302		return (0);
303	}
304	memset(kd, 0, sizeof(*kd));
305	kd->program = errstr;
306	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
307}
308
309int
310kvm_close(kd)
311	kvm_t *kd;
312{
313	register int error = 0;
314
315	if (kd->pmfd >= 0)
316		error |= close(kd->pmfd);
317	if (kd->vmfd >= 0)
318		error |= close(kd->vmfd);
319	if (kd->nlfd >= 0)
320		error |= close(kd->nlfd);
321	if (kd->swfd >= 0)
322		error |= close(kd->swfd);
323	if (kd->db != 0)
324		error |= (kd->db->close)(kd->db);
325	if (kd->vmst)
326		_kvm_freevtop(kd);
327	if (kd->procbase != 0)
328		free((void *)kd->procbase);
329	if (kd->argv != 0)
330		free((void *)kd->argv);
331	free((void *)kd);
332
333	return (0);
334}
335
336/*
337 * Set up state necessary to do queries on the kernel namelist
338 * data base.  If the data base is out-of-data/incompatible with
339 * given executable, set up things so we revert to standard nlist call.
340 * Only called for live kernels.  Return 0 on success, -1 on failure.
341 */
342static int
343kvm_dbopen(kd, uf)
344	kvm_t *kd;
345	const char *uf;
346{
347	char *cp;
348	DBT rec;
349	int dbversionlen;
350	struct nlist nitem;
351	char dbversion[_POSIX2_LINE_MAX];
352	char kversion[_POSIX2_LINE_MAX];
353	char dbname[MAXPATHLEN];
354
355	if ((cp = rindex(uf, '/')) != 0)
356		uf = cp + 1;
357
358	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
359	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
360	if (kd->db == 0)
361		return (-1);
362	/*
363	 * read version out of database
364	 */
365	rec.data = VRS_KEY;
366	rec.size = sizeof(VRS_KEY) - 1;
367	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
368		goto close;
369	if (rec.data == 0 || rec.size > sizeof(dbversion))
370		goto close;
371
372	bcopy(rec.data, dbversion, rec.size);
373	dbversionlen = rec.size;
374	/*
375	 * Read version string from kernel memory.
376	 * Since we are dealing with a live kernel, we can call kvm_read()
377	 * at this point.
378	 */
379	rec.data = VRS_SYM;
380	rec.size = sizeof(VRS_SYM) - 1;
381	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
382		goto close;
383	if (rec.data == 0 || rec.size != sizeof(struct nlist))
384		goto close;
385	bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
386	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
387	    dbversionlen)
388		goto close;
389	/*
390	 * If they match, we win - otherwise clear out kd->db so
391	 * we revert to slow nlist().
392	 */
393	if (bcmp(dbversion, kversion, dbversionlen) == 0)
394		return (0);
395close:
396	(void)(kd->db->close)(kd->db);
397	kd->db = 0;
398
399	return (-1);
400}
401
402int
403kvm_nlist(kd, nl)
404	kvm_t *kd;
405	struct nlist *nl;
406{
407	register struct nlist *p;
408	register int nvalid;
409
410	/*
411	 * If we can't use the data base, revert to the
412	 * slow library call.
413	 */
414	if (kd->db == 0)
415		return (__fdnlist(kd->nlfd, nl));
416
417	/*
418	 * We can use the kvm data base.  Go through each nlist entry
419	 * and look it up with a db query.
420	 */
421	nvalid = 0;
422	for (p = nl; p->n_name && p->n_name[0]; ++p) {
423		register int len;
424		DBT rec;
425
426		if ((len = strlen(p->n_name)) > 4096) {
427			/* sanity */
428			_kvm_err(kd, kd->program, "symbol too large");
429			return (-1);
430		}
431		rec.data = p->n_name;
432		rec.size = len;
433		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
434			continue;
435		if (rec.data == 0 || rec.size != sizeof(struct nlist))
436			continue;
437		++nvalid;
438		/*
439		 * Avoid alignment issues.
440		 */
441		bcopy((char *)&((struct nlist *)rec.data)->n_type,
442		      (char *)&p->n_type,
443		      sizeof(p->n_type));
444		bcopy((char *)&((struct nlist *)rec.data)->n_value,
445		      (char *)&p->n_value,
446		      sizeof(p->n_value));
447	}
448	/*
449	 * Return the number of entries that weren't found.
450	 */
451	return ((p - nl) - nvalid);
452}
453
454ssize_t
455kvm_read(kd, kva, buf, len)
456	kvm_t *kd;
457	register u_long kva;
458	register void *buf;
459	register size_t len;
460{
461	register int cc;
462	register void *cp;
463
464	if (ISALIVE(kd)) {
465		/*
466		 * We're using /dev/kmem.  Just read straight from the
467		 * device and let the active kernel do the address translation.
468		 */
469		errno = 0;
470		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
471			_kvm_err(kd, 0, "invalid address (%x)", kva);
472			return (0);
473		}
474		cc = read(kd->vmfd, buf, len);
475		if (cc < 0) {
476			_kvm_syserr(kd, 0, "kvm_read");
477			return (0);
478		} else if (cc < len)
479			_kvm_err(kd, kd->program, "short read");
480		return (cc);
481	} else {
482		cp = buf;
483		while (len > 0) {
484			u_long pa;
485
486			cc = _kvm_kvatop(kd, kva, &pa);
487			if (cc == 0)
488				return (0);
489			if (cc > len)
490				cc = len;
491			errno = 0;
492			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
493				_kvm_syserr(kd, 0, _PATH_MEM);
494				break;
495			}
496			cc = read(kd->pmfd, cp, cc);
497			if (cc < 0) {
498				_kvm_syserr(kd, kd->program, "kvm_read");
499				break;
500			}
501			/*
502			 * If kvm_kvatop returns a bogus value or our core
503			 * file is truncated, we might wind up seeking beyond
504			 * the end of the core file in which case the read will
505			 * return 0 (EOF).
506			 */
507			if (cc == 0)
508				break;
509			(char *)cp += cc;
510			kva += cc;
511			len -= cc;
512		}
513		return ((char *)cp - (char *)buf);
514	}
515	/* NOTREACHED */
516}
517
518ssize_t
519kvm_write(kd, kva, buf, len)
520	kvm_t *kd;
521	register u_long kva;
522	register const void *buf;
523	register size_t len;
524{
525	register int cc;
526
527	if (ISALIVE(kd)) {
528		/*
529		 * Just like kvm_read, only we write.
530		 */
531		errno = 0;
532		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
533			_kvm_err(kd, 0, "invalid address (%x)", kva);
534			return (0);
535		}
536		cc = write(kd->vmfd, buf, len);
537		if (cc < 0) {
538			_kvm_syserr(kd, 0, "kvm_write");
539			return (0);
540		} else if (cc < len)
541			_kvm_err(kd, kd->program, "short write");
542		return (cc);
543	} else {
544		_kvm_err(kd, kd->program,
545		    "kvm_write not implemented for dead kernels");
546		return (0);
547	}
548	/* NOTREACHED */
549}
550