kvm.c revision 50331
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->nlfd = -1;
178	kd->vmst = 0;
179	kd->db = 0;
180	kd->procbase = 0;
181	kd->argspc = 0;
182	kd->argv = 0;
183
184	if (uf == 0)
185		uf = getbootfile();
186	else if (strlen(uf) >= MAXPATHLEN) {
187		_kvm_err(kd, kd->program, "exec file name too long");
188		goto failed;
189	}
190	if (flag & ~O_RDWR) {
191		_kvm_err(kd, kd->program, "bad flags arg");
192		goto failed;
193	}
194	if (mf == 0)
195		mf = _PATH_MEM;
196	if (sf == 0)
197		sf = _PATH_DRUM;
198
199	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
200		_kvm_syserr(kd, kd->program, "%s", mf);
201		goto failed;
202	}
203	if (fstat(kd->pmfd, &st) < 0) {
204		_kvm_syserr(kd, kd->program, "%s", mf);
205		goto failed;
206	}
207	if (S_ISCHR(st.st_mode)) {
208		/*
209		 * If this is a character special device, then check that
210		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
211		 * make it work for either /dev/mem or /dev/kmem -- in either
212		 * case you're working with a live kernel.)
213		 */
214		if (strcmp(mf, _PATH_DEVNULL) == 0) {
215			kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
216		} else if (strcmp(mf, _PATH_MEM) != 0) {
217			_kvm_err(kd, kd->program,
218				 "%s: not physical memory device", mf);
219			goto failed;
220		} else {
221			if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
222				_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
223				goto failed;
224			}
225		}
226		/*
227		 * Open kvm nlist database.  We go ahead and do this
228		 * here so that we don't have to hold on to the kernel
229		 * path name.  Since a kvm application will surely do
230		 * a kvm_nlist(), this probably won't be a wasted effort.
231		 * If the database cannot be opened, open the namelist
232		 * argument so we revert to slow nlist() calls.
233		 */
234		if (kvm_dbopen(kd, uf) < 0 &&
235		    (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
236			_kvm_syserr(kd, kd->program, "%s", uf);
237			goto failed;
238		}
239	} else {
240		/*
241		 * This is a crash dump.
242		 * Initialize the virtual address translation machinery,
243		 * but first setup the namelist fd.
244		 */
245		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
246			_kvm_syserr(kd, kd->program, "%s", uf);
247			goto failed;
248		}
249		if (_kvm_initvtop(kd) < 0)
250			goto failed;
251	}
252	return (kd);
253failed:
254	/*
255	 * Copy out the error if doing sane error semantics.
256	 */
257	if (errout != 0)
258		strcpy(errout, kd->errbuf);
259	(void)kvm_close(kd);
260	return (0);
261}
262
263kvm_t *
264kvm_openfiles(uf, mf, sf, flag, errout)
265	const char *uf;
266	const char *mf;
267	const char *sf;
268	int flag;
269	char *errout;
270{
271	register kvm_t *kd;
272
273	if ((kd = malloc(sizeof(*kd))) == NULL) {
274		(void)strcpy(errout, strerror(errno));
275		return (0);
276	}
277	memset(kd, 0, sizeof(*kd));
278	kd->program = 0;
279	return (_kvm_open(kd, uf, mf, sf, flag, errout));
280}
281
282kvm_t *
283kvm_open(uf, mf, sf, flag, errstr)
284	const char *uf;
285	const char *mf;
286	const char *sf;
287	int flag;
288	const char *errstr;
289{
290	register kvm_t *kd;
291
292	if ((kd = malloc(sizeof(*kd))) == NULL) {
293		if (errstr != NULL)
294			(void)fprintf(stderr, "%s: %s\n",
295				      errstr, strerror(errno));
296		return (0);
297	}
298	memset(kd, 0, sizeof(*kd));
299	kd->program = errstr;
300	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
301}
302
303int
304kvm_close(kd)
305	kvm_t *kd;
306{
307	register int error = 0;
308
309	if (kd->pmfd >= 0)
310		error |= close(kd->pmfd);
311	if (kd->vmfd >= 0)
312		error |= close(kd->vmfd);
313	if (kd->nlfd >= 0)
314		error |= close(kd->nlfd);
315	if (kd->db != 0)
316		error |= (kd->db->close)(kd->db);
317	if (kd->vmst)
318		_kvm_freevtop(kd);
319	if (kd->procbase != 0)
320		free((void *)kd->procbase);
321	if (kd->argv != 0)
322		free((void *)kd->argv);
323	free((void *)kd);
324
325	return (0);
326}
327
328/*
329 * Set up state necessary to do queries on the kernel namelist
330 * data base.  If the data base is out-of-data/incompatible with
331 * given executable, set up things so we revert to standard nlist call.
332 * Only called for live kernels.  Return 0 on success, -1 on failure.
333 */
334static int
335kvm_dbopen(kd, uf)
336	kvm_t *kd;
337	const char *uf;
338{
339	char *cp;
340	DBT rec;
341	int dbversionlen;
342	struct nlist nitem;
343	char dbversion[_POSIX2_LINE_MAX];
344	char kversion[_POSIX2_LINE_MAX];
345	char dbname[MAXPATHLEN];
346
347	if ((cp = rindex(uf, '/')) != 0)
348		uf = cp + 1;
349
350	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
351	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
352	if (kd->db == 0)
353		return (-1);
354	/*
355	 * read version out of database
356	 */
357	rec.data = VRS_KEY;
358	rec.size = sizeof(VRS_KEY) - 1;
359	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
360		goto close;
361	if (rec.data == 0 || rec.size > sizeof(dbversion))
362		goto close;
363
364	bcopy(rec.data, dbversion, rec.size);
365	dbversionlen = rec.size;
366	/*
367	 * Read version string from kernel memory.
368	 * Since we are dealing with a live kernel, we can call kvm_read()
369	 * at this point.
370	 */
371	rec.data = VRS_SYM;
372	rec.size = sizeof(VRS_SYM) - 1;
373	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
374		goto close;
375	if (rec.data == 0 || rec.size != sizeof(struct nlist))
376		goto close;
377	bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
378	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
379	    dbversionlen)
380		goto close;
381	/*
382	 * If they match, we win - otherwise clear out kd->db so
383	 * we revert to slow nlist().
384	 */
385	if (bcmp(dbversion, kversion, dbversionlen) == 0)
386		return (0);
387close:
388	(void)(kd->db->close)(kd->db);
389	kd->db = 0;
390
391	return (-1);
392}
393
394int
395kvm_nlist(kd, nl)
396	kvm_t *kd;
397	struct nlist *nl;
398{
399	register struct nlist *p;
400	register int nvalid;
401
402	/*
403	 * If we can't use the data base, revert to the
404	 * slow library call.
405	 */
406	if (kd->db == 0)
407		return (__fdnlist(kd->nlfd, nl));
408
409	/*
410	 * We can use the kvm data base.  Go through each nlist entry
411	 * and look it up with a db query.
412	 */
413	nvalid = 0;
414	for (p = nl; p->n_name && p->n_name[0]; ++p) {
415		register int len;
416		DBT rec;
417
418		if ((len = strlen(p->n_name)) > 4096) {
419			/* sanity */
420			_kvm_err(kd, kd->program, "symbol too large");
421			return (-1);
422		}
423		rec.data = p->n_name;
424		rec.size = len;
425		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
426			continue;
427		if (rec.data == 0 || rec.size != sizeof(struct nlist))
428			continue;
429		++nvalid;
430		/*
431		 * Avoid alignment issues.
432		 */
433		bcopy((char *)&((struct nlist *)rec.data)->n_type,
434		      (char *)&p->n_type,
435		      sizeof(p->n_type));
436		bcopy((char *)&((struct nlist *)rec.data)->n_value,
437		      (char *)&p->n_value,
438		      sizeof(p->n_value));
439	}
440	/*
441	 * Return the number of entries that weren't found.
442	 */
443	return ((p - nl) - nvalid);
444}
445
446ssize_t
447kvm_read(kd, kva, buf, len)
448	kvm_t *kd;
449	register u_long kva;
450	register void *buf;
451	register size_t len;
452{
453	register int cc;
454	register void *cp;
455
456	if (ISALIVE(kd)) {
457		/*
458		 * We're using /dev/kmem.  Just read straight from the
459		 * device and let the active kernel do the address translation.
460		 */
461		errno = 0;
462		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
463			_kvm_err(kd, 0, "invalid address (%x)", kva);
464			return (0);
465		}
466		cc = read(kd->vmfd, buf, len);
467		if (cc < 0) {
468			_kvm_syserr(kd, 0, "kvm_read");
469			return (0);
470		} else if (cc < len)
471			_kvm_err(kd, kd->program, "short read");
472		return (cc);
473	} else {
474		cp = buf;
475		while (len > 0) {
476			u_long pa;
477
478			cc = _kvm_kvatop(kd, kva, &pa);
479			if (cc == 0)
480				return (0);
481			if (cc > len)
482				cc = len;
483			errno = 0;
484			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
485				_kvm_syserr(kd, 0, _PATH_MEM);
486				break;
487			}
488			cc = read(kd->pmfd, cp, cc);
489			if (cc < 0) {
490				_kvm_syserr(kd, kd->program, "kvm_read");
491				break;
492			}
493			/*
494			 * If kvm_kvatop returns a bogus value or our core
495			 * file is truncated, we might wind up seeking beyond
496			 * the end of the core file in which case the read will
497			 * return 0 (EOF).
498			 */
499			if (cc == 0)
500				break;
501			(char *)cp += cc;
502			kva += cc;
503			len -= cc;
504		}
505		return ((char *)cp - (char *)buf);
506	}
507	/* NOTREACHED */
508}
509
510ssize_t
511kvm_write(kd, kva, buf, len)
512	kvm_t *kd;
513	register u_long kva;
514	register const void *buf;
515	register size_t len;
516{
517	register int cc;
518
519	if (ISALIVE(kd)) {
520		/*
521		 * Just like kvm_read, only we write.
522		 */
523		errno = 0;
524		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
525			_kvm_err(kd, 0, "invalid address (%x)", kva);
526			return (0);
527		}
528		cc = write(kd->vmfd, buf, len);
529		if (cc < 0) {
530			_kvm_syserr(kd, 0, "kvm_write");
531			return (0);
532		} else if (cc < len)
533			_kvm_err(kd, kd->program, "short write");
534		return (cc);
535	} else {
536		_kvm_err(kd, kd->program,
537		    "kvm_write not implemented for dead kernels");
538		return (0);
539	}
540	/* NOTREACHED */
541}
542