xref: /netbsd-src/lib/libkvm/kvm.c (revision 6506fa2b16cce415f626ca9421c1c2969bfd794f)
161f28255Scgd /*-
2429f62a6Scgd  * Copyright (c) 1989, 1992, 1993
3429f62a6Scgd  *	The Regents of the University of California.  All rights reserved.
4429f62a6Scgd  *
5429f62a6Scgd  * This code is derived from software developed by the Computer Systems
6429f62a6Scgd  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7429f62a6Scgd  * BG 91-66 and contributed to Berkeley.
861f28255Scgd  *
961f28255Scgd  * Redistribution and use in source and binary forms, with or without
1061f28255Scgd  * modification, are permitted provided that the following conditions
1161f28255Scgd  * are met:
1261f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1461f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1561f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1661f28255Scgd  *    documentation and/or other materials provided with the distribution.
1761f28255Scgd  * 3. All advertising materials mentioning features or use of this software
1861f28255Scgd  *    must display the following acknowledgement:
1961f28255Scgd  *	This product includes software developed by the University of
2061f28255Scgd  *	California, Berkeley and its contributors.
2161f28255Scgd  * 4. Neither the name of the University nor the names of its contributors
2261f28255Scgd  *    may be used to endorse or promote products derived from this software
2361f28255Scgd  *    without specific prior written permission.
2461f28255Scgd  *
2561f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2661f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2761f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2861f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2961f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3061f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3161f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3261f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3361f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3461f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3561f28255Scgd  * SUCH DAMAGE.
3661f28255Scgd  */
3761f28255Scgd 
3861f28255Scgd #if defined(LIBC_SCCS) && !defined(lint)
39429f62a6Scgd static char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
4061f28255Scgd #endif /* LIBC_SCCS and not lint */
4161f28255Scgd 
4261f28255Scgd #include <sys/param.h>
4361f28255Scgd #include <sys/user.h>
4461f28255Scgd #include <sys/proc.h>
4561f28255Scgd #include <sys/ioctl.h>
46429f62a6Scgd #include <sys/stat.h>
47429f62a6Scgd #include <sys/sysctl.h>
48429f62a6Scgd 
49429f62a6Scgd #include <vm/vm.h>
50429f62a6Scgd #include <vm/vm_param.h>
51429f62a6Scgd #include <vm/swap_pager.h>
52429f62a6Scgd 
5361f28255Scgd #include <machine/vmparam.h>
54429f62a6Scgd 
55429f62a6Scgd #include <ctype.h>
56429f62a6Scgd #include <db.h>
5761f28255Scgd #include <fcntl.h>
5861f28255Scgd #include <kvm.h>
5961f28255Scgd #include <limits.h>
60429f62a6Scgd #include <nlist.h>
6161f28255Scgd #include <paths.h>
6261f28255Scgd #include <stdio.h>
63429f62a6Scgd #include <stdlib.h>
6461f28255Scgd #include <string.h>
65429f62a6Scgd #include <unistd.h>
6661f28255Scgd 
67429f62a6Scgd #include "kvm_private.h"
6861f28255Scgd 
69429f62a6Scgd static int kvm_dbopen __P((kvm_t *, const char *));
70ea0119dbScgd 
71429f62a6Scgd char *
72429f62a6Scgd kvm_geterr(kd)
73429f62a6Scgd 	kvm_t *kd;
7461f28255Scgd {
75429f62a6Scgd 	return (kd->errbuf);
76429f62a6Scgd }
7761f28255Scgd 
78429f62a6Scgd #if __STDC__
79429f62a6Scgd #include <stdarg.h>
80429f62a6Scgd #else
81429f62a6Scgd #include <varargs.h>
82429f62a6Scgd #endif
83429f62a6Scgd 
84429f62a6Scgd /*
85429f62a6Scgd  * Report an error using printf style arguments.  "program" is kd->program
86429f62a6Scgd  * on hard errors, and 0 on soft errors, so that under sun error emulation,
87429f62a6Scgd  * only hard errors are printed out (otherwise, programs like gdb will
88429f62a6Scgd  * generate tons of error messages when trying to access bogus pointers).
89429f62a6Scgd  */
90429f62a6Scgd void
91429f62a6Scgd #if __STDC__
92429f62a6Scgd _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
93429f62a6Scgd #else
94429f62a6Scgd _kvm_err(kd, program, fmt, va_alist)
95429f62a6Scgd 	kvm_t *kd;
96429f62a6Scgd 	char *program, *fmt;
97429f62a6Scgd 	va_dcl
98429f62a6Scgd #endif
99429f62a6Scgd {
100429f62a6Scgd 	va_list ap;
101429f62a6Scgd 
102429f62a6Scgd #ifdef __STDC__
103429f62a6Scgd 	va_start(ap, fmt);
104429f62a6Scgd #else
105429f62a6Scgd 	va_start(ap);
106429f62a6Scgd #endif
107429f62a6Scgd 	if (program != NULL) {
108429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
109429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
110429f62a6Scgd 		(void)fputc('\n', stderr);
111429f62a6Scgd 	} else
112429f62a6Scgd 		(void)vsnprintf(kd->errbuf,
113429f62a6Scgd 		    sizeof(kd->errbuf), (char *)fmt, ap);
114429f62a6Scgd 
115429f62a6Scgd 	va_end(ap);
11661f28255Scgd }
117429f62a6Scgd 
118429f62a6Scgd void
119429f62a6Scgd #if __STDC__
120429f62a6Scgd _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
121429f62a6Scgd #else
122429f62a6Scgd _kvm_syserr(kd, program, fmt, va_alist)
123429f62a6Scgd 	kvm_t *kd;
124429f62a6Scgd 	char *program, *fmt;
125429f62a6Scgd 	va_dcl
126429f62a6Scgd #endif
127429f62a6Scgd {
128429f62a6Scgd 	va_list ap;
129429f62a6Scgd 	register int n;
130429f62a6Scgd 
131429f62a6Scgd #if __STDC__
132429f62a6Scgd 	va_start(ap, fmt);
133429f62a6Scgd #else
134429f62a6Scgd 	va_start(ap);
135429f62a6Scgd #endif
136429f62a6Scgd 	if (program != NULL) {
137429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
138429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
139429f62a6Scgd 		(void)fprintf(stderr, ": %s\n", strerror(errno));
14061f28255Scgd 	} else {
141429f62a6Scgd 		register char *cp = kd->errbuf;
142429f62a6Scgd 
143429f62a6Scgd 		(void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
144429f62a6Scgd 		n = strlen(cp);
145429f62a6Scgd 		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
146429f62a6Scgd 		    strerror(errno));
147429f62a6Scgd 	}
148429f62a6Scgd 	va_end(ap);
149429f62a6Scgd }
150429f62a6Scgd 
151429f62a6Scgd void *
152429f62a6Scgd _kvm_malloc(kd, n)
153429f62a6Scgd 	register kvm_t *kd;
154429f62a6Scgd 	register size_t n;
155429f62a6Scgd {
156429f62a6Scgd 	void *p;
157429f62a6Scgd 
158429f62a6Scgd 	if ((p = malloc(n)) == NULL)
159429f62a6Scgd 		_kvm_err(kd, kd->program, strerror(errno));
160429f62a6Scgd 	return (p);
161429f62a6Scgd }
162429f62a6Scgd 
163429f62a6Scgd static kvm_t *
164429f62a6Scgd _kvm_open(kd, uf, mf, sf, flag, errout)
165429f62a6Scgd 	register kvm_t *kd;
166429f62a6Scgd 	const char *uf;
167429f62a6Scgd 	const char *mf;
168429f62a6Scgd 	const char *sf;
169429f62a6Scgd 	int flag;
170429f62a6Scgd 	char *errout;
171429f62a6Scgd {
172429f62a6Scgd 	struct stat st;
173429f62a6Scgd 
174c3049714Smycroft 	kd->db = 0;
175429f62a6Scgd 	kd->pmfd = -1;
176c3049714Smycroft 	kd->vmfd = -1;
177429f62a6Scgd 	kd->swfd = -1;
178429f62a6Scgd 	kd->nlfd = -1;
179429f62a6Scgd 	kd->procbase = 0;
180b707f8aaSmycroft 	kd->nbpg = getpagesize();
181b707f8aaSmycroft 	kd->swapspc = 0;
182429f62a6Scgd 	kd->argspc = 0;
183*6506fa2bSmycroft 	kd->argbuf = 0;
184429f62a6Scgd 	kd->argv = 0;
185c3049714Smycroft 	kd->vmst = 0;
186c3049714Smycroft 	kd->vm_page_buckets = 0;
187429f62a6Scgd 
188429f62a6Scgd 	if (uf == 0)
189429f62a6Scgd 		uf = _PATH_UNIX;
190429f62a6Scgd 	else if (strlen(uf) >= MAXPATHLEN) {
191429f62a6Scgd 		_kvm_err(kd, kd->program, "exec file name too long");
19261f28255Scgd 		goto failed;
19361f28255Scgd 	}
194429f62a6Scgd 	if (flag & ~O_RDWR) {
195429f62a6Scgd 		_kvm_err(kd, kd->program, "bad flags arg");
196429f62a6Scgd 		goto failed;
197429f62a6Scgd 	}
198429f62a6Scgd 	if (mf == 0)
199429f62a6Scgd 		mf = _PATH_MEM;
200429f62a6Scgd 	if (sf == 0)
201429f62a6Scgd 		sf = _PATH_DRUM;
202429f62a6Scgd 
203429f62a6Scgd 	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
204429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
205429f62a6Scgd 		goto failed;
206429f62a6Scgd 	}
207429f62a6Scgd 	if (fstat(kd->pmfd, &st) < 0) {
208429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
209429f62a6Scgd 		goto failed;
210429f62a6Scgd 	}
211429f62a6Scgd 	if (S_ISCHR(st.st_mode)) {
21261f28255Scgd 		/*
213429f62a6Scgd 		 * If this is a character special device, then check that
214429f62a6Scgd 		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
215429f62a6Scgd 		 * make it work for either /dev/mem or /dev/kmem -- in either
216429f62a6Scgd 		 * case you're working with a live kernel.)
21761f28255Scgd 		 */
218429f62a6Scgd 		if (strcmp(mf, _PATH_MEM) != 0) {	/* XXX */
219429f62a6Scgd 			_kvm_err(kd, kd->program,
220429f62a6Scgd 				 "%s: not physical memory device", mf);
22161f28255Scgd 			goto failed;
22261f28255Scgd 		}
223429f62a6Scgd 		if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
224429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
225429f62a6Scgd 			goto failed;
226429f62a6Scgd 		}
227429f62a6Scgd 		if ((kd->swfd = open(sf, flag, 0)) < 0) {
228429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", sf);
229429f62a6Scgd 			goto failed;
230429f62a6Scgd 		}
231429f62a6Scgd 		/*
232429f62a6Scgd 		 * Open kvm nlist database.  We go ahead and do this
233429f62a6Scgd 		 * here so that we don't have to hold on to the vmunix
234429f62a6Scgd 		 * path name.  Since a kvm application will surely do
235429f62a6Scgd 		 * a kvm_nlist(), this probably won't be a wasted effort.
236429f62a6Scgd 		 * If the database cannot be opened, open the namelist
237429f62a6Scgd 		 * argument so we revert to slow nlist() calls.
238429f62a6Scgd 		 */
239429f62a6Scgd 		if (kvm_dbopen(kd, uf) < 0 &&
240429f62a6Scgd 		    (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
241429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", uf);
242429f62a6Scgd 			goto failed;
243429f62a6Scgd 		}
244429f62a6Scgd 	} else {
245429f62a6Scgd 		/*
246429f62a6Scgd 		 * This is a crash dump.
247429f62a6Scgd 		 * Initalize the virtual address translation machinery,
248429f62a6Scgd 		 * but first setup the namelist fd.
249429f62a6Scgd 		 */
250429f62a6Scgd 		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
251429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", uf);
252429f62a6Scgd 			goto failed;
253429f62a6Scgd 		}
254429f62a6Scgd 		if (_kvm_initvtop(kd) < 0)
255429f62a6Scgd 			goto failed;
256429f62a6Scgd 	}
257429f62a6Scgd 	return (kd);
25861f28255Scgd failed:
259429f62a6Scgd 	/*
260429f62a6Scgd 	 * Copy out the error if doing sane error semantics.
261429f62a6Scgd 	 */
262429f62a6Scgd 	if (errout != 0)
263429f62a6Scgd 		strcpy(errout, kd->errbuf);
264429f62a6Scgd 	(void)kvm_close(kd);
265429f62a6Scgd 	return (0);
26661f28255Scgd }
26761f28255Scgd 
268429f62a6Scgd kvm_t *
269429f62a6Scgd kvm_openfiles(uf, mf, sf, flag, errout)
270429f62a6Scgd 	const char *uf;
271429f62a6Scgd 	const char *mf;
272429f62a6Scgd 	const char *sf;
273429f62a6Scgd 	int flag;
274429f62a6Scgd 	char *errout;
27561f28255Scgd {
276429f62a6Scgd 	register kvm_t *kd;
277429f62a6Scgd 
278429f62a6Scgd 	if ((kd = malloc(sizeof(*kd))) == NULL) {
279429f62a6Scgd 		(void)strcpy(errout, strerror(errno));
280429f62a6Scgd 		return (0);
281429f62a6Scgd 	}
282429f62a6Scgd 	kd->program = 0;
283429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, errout));
284429f62a6Scgd }
285429f62a6Scgd 
286429f62a6Scgd kvm_t *
287429f62a6Scgd kvm_open(uf, mf, sf, flag, program)
288429f62a6Scgd 	const char *uf;
289429f62a6Scgd 	const char *mf;
290429f62a6Scgd 	const char *sf;
291429f62a6Scgd 	int flag;
292429f62a6Scgd 	const char *program;
293429f62a6Scgd {
294429f62a6Scgd 	register kvm_t *kd;
295429f62a6Scgd 
296429f62a6Scgd 	if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) {
297429f62a6Scgd 		(void)fprintf(stderr, "%s: %s\n", strerror(errno));
298429f62a6Scgd 		return (0);
299429f62a6Scgd 	}
300429f62a6Scgd 	kd->program = program;
301429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
302429f62a6Scgd }
303429f62a6Scgd 
304429f62a6Scgd int
305429f62a6Scgd kvm_close(kd)
306429f62a6Scgd 	kvm_t *kd;
307429f62a6Scgd {
308429f62a6Scgd 	register int error = 0;
309429f62a6Scgd 
310429f62a6Scgd 	if (kd->pmfd >= 0)
311429f62a6Scgd 		error |= close(kd->pmfd);
312429f62a6Scgd 	if (kd->vmfd >= 0)
313429f62a6Scgd 		error |= close(kd->vmfd);
314429f62a6Scgd 	if (kd->nlfd >= 0)
315429f62a6Scgd 		error |= close(kd->nlfd);
316429f62a6Scgd 	if (kd->swfd >= 0)
317429f62a6Scgd 		error |= close(kd->swfd);
318429f62a6Scgd 	if (kd->db != 0)
319429f62a6Scgd 		error |= (kd->db->close)(kd->db);
320429f62a6Scgd 	if (kd->vmst)
321429f62a6Scgd 		_kvm_freevtop(kd);
322429f62a6Scgd 	if (kd->procbase != 0)
323429f62a6Scgd 		free((void *)kd->procbase);
324b707f8aaSmycroft 	if (kd->swapspc != 0)
325b707f8aaSmycroft 		free((void *)kd->swapspc);
326b707f8aaSmycroft 	if (kd->argspc != 0)
327b707f8aaSmycroft 		free((void *)kd->argspc);
328*6506fa2bSmycroft 	if (kd->argbuf != 0)
329*6506fa2bSmycroft 		free((void *)kd->argbuf);
330429f62a6Scgd 	if (kd->argv != 0)
331429f62a6Scgd 		free((void *)kd->argv);
332429f62a6Scgd 	free((void *)kd);
33361f28255Scgd 
33461f28255Scgd 	return (0);
33561f28255Scgd }
33661f28255Scgd 
337429f62a6Scgd /*
338429f62a6Scgd  * Set up state necessary to do queries on the kernel namelist
339429f62a6Scgd  * data base.  If the data base is out-of-data/incompatible with
340429f62a6Scgd  * given executable, set up things so we revert to standard nlist call.
341429f62a6Scgd  * Only called for live kernels.  Return 0 on success, -1 on failure.
342429f62a6Scgd  */
343429f62a6Scgd static int
344429f62a6Scgd kvm_dbopen(kd, uf)
345429f62a6Scgd 	kvm_t *kd;
346429f62a6Scgd 	const char *uf;
34761f28255Scgd {
348429f62a6Scgd 	char *cp;
349429f62a6Scgd 	DBT rec;
350429f62a6Scgd 	int dbversionlen;
351429f62a6Scgd 	struct nlist nitem;
35261f28255Scgd 	char dbversion[_POSIX2_LINE_MAX];
35361f28255Scgd 	char kversion[_POSIX2_LINE_MAX];
354429f62a6Scgd 	char dbname[MAXPATHLEN];
35561f28255Scgd 
356429f62a6Scgd 	if ((cp = rindex(uf, '/')) != 0)
357429f62a6Scgd 		uf = cp + 1;
358429f62a6Scgd 
359429f62a6Scgd 	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
360429f62a6Scgd 	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
361429f62a6Scgd 	if (kd->db == 0)
36261f28255Scgd 		return (-1);
36361f28255Scgd 	/*
36461f28255Scgd 	 * read version out of database
36561f28255Scgd 	 */
366429f62a6Scgd 	rec.data = VRS_KEY;
367429f62a6Scgd 	rec.size = sizeof(VRS_KEY) - 1;
368429f62a6Scgd 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
369429f62a6Scgd 		goto close;
370429f62a6Scgd 	if (rec.data == 0 || rec.size > sizeof(dbversion))
371429f62a6Scgd 		goto close;
372429f62a6Scgd 
373429f62a6Scgd 	bcopy(rec.data, dbversion, rec.size);
374429f62a6Scgd 	dbversionlen = rec.size;
37561f28255Scgd 	/*
376429f62a6Scgd 	 * Read version string from kernel memory.
377429f62a6Scgd 	 * Since we are dealing with a live kernel, we can call kvm_read()
378429f62a6Scgd 	 * at this point.
37961f28255Scgd 	 */
380429f62a6Scgd 	rec.data = VRS_SYM;
381429f62a6Scgd 	rec.size = sizeof(VRS_SYM) - 1;
382429f62a6Scgd 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
383429f62a6Scgd 		goto close;
384429f62a6Scgd 	if (rec.data == 0 || rec.size != sizeof(struct nlist))
385429f62a6Scgd 		goto close;
386429f62a6Scgd 	bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
387429f62a6Scgd 	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
388429f62a6Scgd 	    dbversionlen)
389429f62a6Scgd 		goto close;
39061f28255Scgd 	/*
391429f62a6Scgd 	 * If they match, we win - otherwise clear out kd->db so
392429f62a6Scgd 	 * we revert to slow nlist().
39361f28255Scgd 	 */
394429f62a6Scgd 	if (bcmp(dbversion, kversion, dbversionlen) == 0)
395429f62a6Scgd 		return (0);
396429f62a6Scgd close:
397429f62a6Scgd 	(void)(kd->db->close)(kd->db);
398429f62a6Scgd 	kd->db = 0;
399429f62a6Scgd 
40061f28255Scgd 	return (-1);
40161f28255Scgd }
40261f28255Scgd 
4035089c413Scgd int
404429f62a6Scgd kvm_nlist(kd, nl)
405429f62a6Scgd 	kvm_t *kd;
406429f62a6Scgd 	struct nlist *nl;
4075089c413Scgd {
408429f62a6Scgd 	register struct nlist *p;
409429f62a6Scgd 	register int nvalid;
4105089c413Scgd 
411429f62a6Scgd 	/*
412429f62a6Scgd 	 * If we can't use the data base, revert to the
413429f62a6Scgd 	 * slow library call.
414429f62a6Scgd 	 */
415429f62a6Scgd 	if (kd->db == 0)
416429f62a6Scgd 		return (__fdnlist(kd->nlfd, nl));
4175089c413Scgd 
418429f62a6Scgd 	/*
419429f62a6Scgd 	 * We can use the kvm data base.  Go through each nlist entry
420429f62a6Scgd 	 * and look it up with a db query.
421429f62a6Scgd 	 */
422429f62a6Scgd 	nvalid = 0;
423429f62a6Scgd 	for (p = nl; p->n_name && p->n_name[0]; ++p) {
424429f62a6Scgd 		register int len;
425429f62a6Scgd 		DBT rec;
4265089c413Scgd 
427429f62a6Scgd 		if ((len = strlen(p->n_name)) > 4096) {
428429f62a6Scgd 			/* sanity */
429429f62a6Scgd 			_kvm_err(kd, kd->program, "symbol too large");
430429f62a6Scgd 			return (-1);
43122eaa1f2Smycroft 		}
432429f62a6Scgd 		rec.data = p->n_name;
433429f62a6Scgd 		rec.size = len;
434429f62a6Scgd 		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
435429f62a6Scgd 			continue;
436429f62a6Scgd 		if (rec.data == 0 || rec.size != sizeof(struct nlist))
437429f62a6Scgd 			continue;
438429f62a6Scgd 		++nvalid;
439429f62a6Scgd 		/*
440429f62a6Scgd 		 * Avoid alignment issues.
441429f62a6Scgd 		 */
442429f62a6Scgd 		bcopy((char *)&((struct nlist *)rec.data)->n_type,
443429f62a6Scgd 		      (char *)&p->n_type,
444429f62a6Scgd 		      sizeof(p->n_type));
445429f62a6Scgd 		bcopy((char *)&((struct nlist *)rec.data)->n_value,
446429f62a6Scgd 		      (char *)&p->n_value,
447429f62a6Scgd 		      sizeof(p->n_value));
4485089c413Scgd 	}
449429f62a6Scgd 	/*
450429f62a6Scgd 	 * Return the number of entries that weren't found.
451429f62a6Scgd 	 */
452429f62a6Scgd 	return ((p - nl) - nvalid);
453db3323c9Smycroft }
4545089c413Scgd 
455429f62a6Scgd ssize_t
456429f62a6Scgd kvm_read(kd, kva, buf, len)
457429f62a6Scgd 	kvm_t *kd;
458429f62a6Scgd 	register u_long kva;
459429f62a6Scgd 	register void *buf;
460429f62a6Scgd 	register size_t len;
4615089c413Scgd {
462429f62a6Scgd 	register int cc;
463429f62a6Scgd 	register void *cp;
4645089c413Scgd 
465429f62a6Scgd 	if (ISALIVE(kd)) {
466429f62a6Scgd 		/*
467429f62a6Scgd 		 * We're using /dev/kmem.  Just read straight from the
468429f62a6Scgd 		 * device and let the active kernel do the address translation.
469429f62a6Scgd 		 */
470429f62a6Scgd 		errno = 0;
471429f62a6Scgd 		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
472429f62a6Scgd 			_kvm_err(kd, 0, "invalid address (%x)", kva);
47361f28255Scgd 			return (0);
47461f28255Scgd 		}
475429f62a6Scgd 		cc = read(kd->vmfd, buf, len);
476429f62a6Scgd 		if (cc < 0) {
477429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_read");
478429f62a6Scgd 			return (0);
479429f62a6Scgd 		} else if (cc < len)
480429f62a6Scgd 			_kvm_err(kd, kd->program, "short read");
481429f62a6Scgd 		return (cc);
482429f62a6Scgd 	} else {
483429f62a6Scgd 		cp = buf;
484429f62a6Scgd 		while (len > 0) {
485429f62a6Scgd 			u_long pa;
48661f28255Scgd 
487429f62a6Scgd 			cc = _kvm_kvatop(kd, kva, &pa);
488429f62a6Scgd 			if (cc == 0)
489429f62a6Scgd 				return (0);
490429f62a6Scgd 			if (cc > len)
491429f62a6Scgd 				cc = len;
492429f62a6Scgd 			errno = 0;
493429f62a6Scgd 			if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
494429f62a6Scgd 				_kvm_syserr(kd, 0, _PATH_MEM);
495ea0119dbScgd 				break;
496669b9e50Smycroft 			}
497429f62a6Scgd 			cc = read(kd->pmfd, cp, cc);
498429f62a6Scgd 			if (cc < 0) {
499429f62a6Scgd 				_kvm_syserr(kd, kd->program, "kvm_read");
500ea0119dbScgd 				break;
501ea0119dbScgd 			}
5027b1fbb1cSpk 			/*
503429f62a6Scgd 			 * If kvm_kvatop returns a bogus value or our core
504429f62a6Scgd 			 * file is truncated, we might wind up seeking beyond
505429f62a6Scgd 			 * the end of the core file in which case the read will
506429f62a6Scgd 			 * return 0 (EOF).
5077b1fbb1cSpk 			 */
508429f62a6Scgd 			if (cc == 0)
509429f62a6Scgd 				break;
510429f62a6Scgd 			(char *)cp += cc;
511429f62a6Scgd 			kva += cc;
512429f62a6Scgd 			len -= cc;
513429f62a6Scgd 		}
514429f62a6Scgd 		return ((char *)cp - (char *)buf);
515429f62a6Scgd 	}
516429f62a6Scgd 	/* NOTREACHED */
517429f62a6Scgd }
5187b1fbb1cSpk 
519429f62a6Scgd ssize_t
520429f62a6Scgd kvm_write(kd, kva, buf, len)
521429f62a6Scgd 	kvm_t *kd;
522429f62a6Scgd 	register u_long kva;
523429f62a6Scgd 	register const void *buf;
524429f62a6Scgd 	register size_t len;
525429f62a6Scgd {
526429f62a6Scgd 	register int cc;
5277b1fbb1cSpk 
528429f62a6Scgd 	if (ISALIVE(kd)) {
5297b1fbb1cSpk 		/*
530429f62a6Scgd 		 * Just like kvm_read, only we write.
5317b1fbb1cSpk 		 */
532429f62a6Scgd 		errno = 0;
533429f62a6Scgd 		if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
534429f62a6Scgd 			_kvm_err(kd, 0, "invalid address (%x)", kva);
535429f62a6Scgd 			return (0);
5367b1fbb1cSpk 		}
537429f62a6Scgd 		cc = write(kd->vmfd, buf, len);
538429f62a6Scgd 		if (cc < 0) {
539429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_write");
540429f62a6Scgd 			return (0);
541429f62a6Scgd 		} else if (cc < len)
542429f62a6Scgd 			_kvm_err(kd, kd->program, "short write");
543429f62a6Scgd 		return (cc);
544429f62a6Scgd 	} else {
545429f62a6Scgd 		_kvm_err(kd, kd->program,
546429f62a6Scgd 		    "kvm_write not implemented for dead kernels");
547429f62a6Scgd 		return (0);
5487b1fbb1cSpk 	}
549429f62a6Scgd 	/* NOTREACHED */
55061f28255Scgd }
551