kvm.c revision 6701
190792Sgshapiro/*-
2261363Sgshapiro * Copyright (c) 1989, 1992, 1993
390792Sgshapiro *	The Regents of the University of California.  All rights reserved.
490792Sgshapiro *
590792Sgshapiro * This code is derived from software developed by the Computer Systems
690792Sgshapiro * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
790792Sgshapiro * BG 91-66 and contributed to Berkeley.
890792Sgshapiro *
9266692Sgshapiro * Redistribution and use in source and binary forms, with or without
1090792Sgshapiro * modification, are permitted provided that the following conditions
1190792Sgshapiro * are met:
1290792Sgshapiro * 1. Redistributions of source code must retain the above copyright
1390792Sgshapiro *    notice, this list of conditions and the following disclaimer.
1490792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright
1590792Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1690792Sgshapiro *    documentation and/or other materials provided with the distribution.
1790792Sgshapiro * 3. All advertising materials mentioning features or use of this software
1890792Sgshapiro *    must display the following acknowledgement:
1990792Sgshapiro *	This product includes software developed by the University of
2090792Sgshapiro *	California, Berkeley and its contributors.
2190792Sgshapiro * 4. Neither the name of the University nor the names of its contributors
2290792Sgshapiro *    may be used to endorse or promote products derived from this software
2390792Sgshapiro *    without specific prior written permission.
2490792Sgshapiro *
2590792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2690792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2790792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2890792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2990792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3090792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3190792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3290792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3390792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3490792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3590792Sgshapiro * SUCH DAMAGE.
3690792Sgshapiro */
3790792Sgshapiro
3890792Sgshapiro#if defined(LIBC_SCCS) && !defined(lint)
3990792Sgshapirostatic char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
4090792Sgshapiro#endif /* LIBC_SCCS and not lint */
4190792Sgshapiro
4290792Sgshapiro#include <sys/param.h>
4390792Sgshapiro#include <sys/user.h>
4490792Sgshapiro#include <sys/proc.h>
4590792Sgshapiro#include <sys/ioctl.h>
4690792Sgshapiro#include <sys/stat.h>
4790792Sgshapiro#include <sys/sysctl.h>
4890792Sgshapiro
4990792Sgshapiro#include <vm/vm.h>
5090792Sgshapiro#include <vm/vm_param.h>
5190792Sgshapiro#include <vm/swap_pager.h>
5290792Sgshapiro
5390792Sgshapiro#include <machine/vmparam.h>
5490792Sgshapiro
5590792Sgshapiro#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 = malloc(n)) == NULL)
159		_kvm_err(kd, kd->program, strerror(errno));
160	return (p);
161}
162
163static kvm_t *
164_kvm_open(kd, uf, mf, sf, flag, errout)
165	register kvm_t *kd;
166	const char *uf;
167	const char *mf;
168	const char *sf;
169	int flag;
170	char *errout;
171{
172	struct stat st;
173
174	kd->vmfd = -1;
175	kd->pmfd = -1;
176	kd->swfd = -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_MEM) != 0) {	/* XXX */
215			_kvm_err(kd, kd->program,
216				 "%s: not physical memory device", mf);
217			goto failed;
218		}
219		if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
220			_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
221			goto failed;
222		}
223		if ((kd->swfd = open(sf, flag, 0)) < 0) {
224			_kvm_syserr(kd, kd->program, "%s", sf);
225			goto failed;
226		}
227		/*
228		 * Open kvm nlist database.  We go ahead and do this
229		 * here so that we don't have to hold on to the kernel
230		 * path name.  Since a kvm application will surely do
231		 * a kvm_nlist(), this probably won't be a wasted effort.
232		 * If the database cannot be opened, open the namelist
233		 * argument so we revert to slow nlist() calls.
234		 */
235		if (kvm_dbopen(kd, uf) < 0 &&
236		    (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
237			_kvm_syserr(kd, kd->program, "%s", uf);
238			goto failed;
239		}
240	} else {
241		/*
242		 * This is a crash dump.
243		 * Initalize the virtual address translation machinery,
244		 * but first setup the namelist fd.
245		 */
246		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
247			_kvm_syserr(kd, kd->program, "%s", uf);
248			goto failed;
249		}
250		if (_kvm_initvtop(kd) < 0)
251			goto failed;
252	}
253	return (kd);
254failed:
255	/*
256	 * Copy out the error if doing sane error semantics.
257	 */
258	if (errout != 0)
259		strcpy(errout, kd->errbuf);
260	(void)kvm_close(kd);
261	return (0);
262}
263
264kvm_t *
265kvm_openfiles(uf, mf, sf, flag, errout)
266	const char *uf;
267	const char *mf;
268	const char *sf;
269	int flag;
270	char *errout;
271{
272	register kvm_t *kd;
273
274	if ((kd = malloc(sizeof(*kd))) == NULL) {
275		(void)strcpy(errout, strerror(errno));
276		return (0);
277	}
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	kd->program = errstr;
299	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
300}
301
302int
303kvm_close(kd)
304	kvm_t *kd;
305{
306	register int error = 0;
307
308	if (kd->pmfd >= 0)
309		error |= close(kd->pmfd);
310	if (kd->vmfd >= 0)
311		error |= close(kd->vmfd);
312	if (kd->nlfd >= 0)
313		error |= close(kd->nlfd);
314	if (kd->swfd >= 0)
315		error |= close(kd->swfd);
316	if (kd->db != 0)
317		error |= (kd->db->close)(kd->db);
318	if (kd->vmst)
319		_kvm_freevtop(kd);
320	if (kd->procbase != 0)
321		free((void *)kd->procbase);
322	if (kd->argv != 0)
323		free((void *)kd->argv);
324	free((void *)kd);
325
326	return (0);
327}
328
329/*
330 * Set up state necessary to do queries on the kernel namelist
331 * data base.  If the data base is out-of-data/incompatible with
332 * given executable, set up things so we revert to standard nlist call.
333 * Only called for live kernels.  Return 0 on success, -1 on failure.
334 */
335static int
336kvm_dbopen(kd, uf)
337	kvm_t *kd;
338	const char *uf;
339{
340	char *cp;
341	DBT rec;
342	int dbversionlen;
343	struct nlist nitem;
344	char dbversion[_POSIX2_LINE_MAX];
345	char kversion[_POSIX2_LINE_MAX];
346	char dbname[MAXPATHLEN];
347
348	if ((cp = rindex(uf, '/')) != 0)
349		uf = cp + 1;
350
351	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
352	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
353	if (kd->db == 0)
354		return (-1);
355	/*
356	 * read version out of database
357	 */
358	rec.data = VRS_KEY;
359	rec.size = sizeof(VRS_KEY) - 1;
360	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
361		goto close;
362	if (rec.data == 0 || rec.size > sizeof(dbversion))
363		goto close;
364
365	bcopy(rec.data, dbversion, rec.size);
366	dbversionlen = rec.size;
367	/*
368	 * Read version string from kernel memory.
369	 * Since we are dealing with a live kernel, we can call kvm_read()
370	 * at this point.
371	 */
372	rec.data = VRS_SYM;
373	rec.size = sizeof(VRS_SYM) - 1;
374	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
375		goto close;
376	if (rec.data == 0 || rec.size != sizeof(struct nlist))
377		goto close;
378	bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
379	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
380	    dbversionlen)
381		goto close;
382	/*
383	 * If they match, we win - otherwise clear out kd->db so
384	 * we revert to slow nlist().
385	 */
386	if (bcmp(dbversion, kversion, dbversionlen) == 0)
387		return (0);
388close:
389	(void)(kd->db->close)(kd->db);
390	kd->db = 0;
391
392	return (-1);
393}
394
395int
396kvm_nlist(kd, nl)
397	kvm_t *kd;
398	struct nlist *nl;
399{
400	register struct nlist *p;
401	register int nvalid;
402
403	/*
404	 * If we can't use the data base, revert to the
405	 * slow library call.
406	 */
407	if (kd->db == 0)
408		return (__fdnlist(kd->nlfd, nl));
409
410	/*
411	 * We can use the kvm data base.  Go through each nlist entry
412	 * and look it up with a db query.
413	 */
414	nvalid = 0;
415	for (p = nl; p->n_name && p->n_name[0]; ++p) {
416		register int len;
417		DBT rec;
418
419		if ((len = strlen(p->n_name)) > 4096) {
420			/* sanity */
421			_kvm_err(kd, kd->program, "symbol too large");
422			return (-1);
423		}
424		rec.data = p->n_name;
425		rec.size = len;
426		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
427			continue;
428		if (rec.data == 0 || rec.size != sizeof(struct nlist))
429			continue;
430		++nvalid;
431		/*
432		 * Avoid alignment issues.
433		 */
434		bcopy((char *)&((struct nlist *)rec.data)->n_type,
435		      (char *)&p->n_type,
436		      sizeof(p->n_type));
437		bcopy((char *)&((struct nlist *)rec.data)->n_value,
438		      (char *)&p->n_value,
439		      sizeof(p->n_value));
440	}
441	/*
442	 * Return the number of entries that weren't found.
443	 */
444	return ((p - nl) - nvalid);
445}
446
447ssize_t
448kvm_read(kd, kva, buf, len)
449	kvm_t *kd;
450	register u_long kva;
451	register void *buf;
452	register size_t len;
453{
454	register int cc;
455	register void *cp;
456
457	if (ISALIVE(kd)) {
458		/*
459		 * We're using /dev/kmem.  Just read straight from the
460		 * device and let the active kernel do the address translation.
461		 */
462		errno = 0;
463		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
464			_kvm_err(kd, 0, "invalid address (%x)", kva);
465			return (0);
466		}
467		cc = read(kd->vmfd, buf, len);
468		if (cc < 0) {
469			_kvm_syserr(kd, 0, "kvm_read");
470			return (0);
471		} else if (cc < len)
472			_kvm_err(kd, kd->program, "short read");
473		return (cc);
474	} else {
475		cp = buf;
476		while (len > 0) {
477			u_long pa;
478
479			cc = _kvm_kvatop(kd, kva, &pa);
480			if (cc == 0)
481				return (0);
482			if (cc > len)
483				cc = len;
484			errno = 0;
485			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
486				_kvm_syserr(kd, 0, _PATH_MEM);
487				break;
488			}
489			cc = read(kd->pmfd, cp, cc);
490			if (cc < 0) {
491				_kvm_syserr(kd, kd->program, "kvm_read");
492				break;
493			}
494			/*
495			 * If kvm_kvatop returns a bogus value or our core
496			 * file is truncated, we might wind up seeking beyond
497			 * the end of the core file in which case the read will
498			 * return 0 (EOF).
499			 */
500			if (cc == 0)
501				break;
502			(char *)cp += cc;
503			kva += cc;
504			len -= cc;
505		}
506		return ((char *)cp - (char *)buf);
507	}
508	/* NOTREACHED */
509}
510
511ssize_t
512kvm_write(kd, kva, buf, len)
513	kvm_t *kd;
514	register u_long kva;
515	register const void *buf;
516	register size_t len;
517{
518	register int cc;
519
520	if (ISALIVE(kd)) {
521		/*
522		 * Just like kvm_read, only we write.
523		 */
524		errno = 0;
525		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
526			_kvm_err(kd, 0, "invalid address (%x)", kva);
527			return (0);
528		}
529		cc = write(kd->vmfd, buf, len);
530		if (cc < 0) {
531			_kvm_syserr(kd, 0, "kvm_write");
532			return (0);
533		} else if (cc < len)
534			_kvm_err(kd, kd->program, "short write");
535		return (cc);
536	} else {
537		_kvm_err(kd, kd->program,
538		    "kvm_write not implemented for dead kernels");
539		return (0);
540	}
541	/* NOTREACHED */
542}
543