xref: /netbsd-src/lib/libkvm/kvm.c (revision be74d305c7848fc595b829b30bd6b97c6a190534)
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 
499c2128ecSleo #include <sys/core.h>
509c2128ecSleo #include <sys/exec_aout.h>
519c2128ecSleo #include <sys/kcore.h>
529c2128ecSleo 
53429f62a6Scgd #include <vm/vm.h>
54429f62a6Scgd #include <vm/vm_param.h>
55429f62a6Scgd #include <vm/swap_pager.h>
56429f62a6Scgd 
5761f28255Scgd #include <machine/vmparam.h>
589c2128ecSleo #include <machine/kcore.h>
59429f62a6Scgd 
60429f62a6Scgd #include <ctype.h>
61429f62a6Scgd #include <db.h>
6261f28255Scgd #include <fcntl.h>
6361f28255Scgd #include <limits.h>
64429f62a6Scgd #include <nlist.h>
6561f28255Scgd #include <paths.h>
6661f28255Scgd #include <stdio.h>
67429f62a6Scgd #include <stdlib.h>
6861f28255Scgd #include <string.h>
69429f62a6Scgd #include <unistd.h>
70*be74d305Sleo #include <kvm.h>
7161f28255Scgd 
72429f62a6Scgd #include "kvm_private.h"
7361f28255Scgd 
74429f62a6Scgd static int	kvm_dbopen __P((kvm_t *, const char *));
759c2128ecSleo static int	_kvm_get_header __P((kvm_t *));
7600fd6050Scgd static kvm_t	*_kvm_open __P((kvm_t *, const char *, const char *,
7700fd6050Scgd 		    const char *, int, char *));
789c2128ecSleo static int	clear_gap __P((kvm_t *, FILE *, int));
799c2128ecSleo static off_t	Lseek __P((kvm_t *, int, off_t, int));
809c2128ecSleo static ssize_t	Read __P(( kvm_t *, int, void *, size_t));
81ea0119dbScgd 
82429f62a6Scgd char *
83429f62a6Scgd kvm_geterr(kd)
84429f62a6Scgd 	kvm_t *kd;
8561f28255Scgd {
86429f62a6Scgd 	return (kd->errbuf);
87429f62a6Scgd }
8861f28255Scgd 
89429f62a6Scgd #if __STDC__
90429f62a6Scgd #include <stdarg.h>
91429f62a6Scgd #else
92429f62a6Scgd #include <varargs.h>
93429f62a6Scgd #endif
94429f62a6Scgd 
95429f62a6Scgd /*
96429f62a6Scgd  * Report an error using printf style arguments.  "program" is kd->program
97429f62a6Scgd  * on hard errors, and 0 on soft errors, so that under sun error emulation,
98429f62a6Scgd  * only hard errors are printed out (otherwise, programs like gdb will
99429f62a6Scgd  * generate tons of error messages when trying to access bogus pointers).
100429f62a6Scgd  */
101429f62a6Scgd void
102429f62a6Scgd #if __STDC__
103429f62a6Scgd _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
104429f62a6Scgd #else
105429f62a6Scgd _kvm_err(kd, program, fmt, va_alist)
106429f62a6Scgd 	kvm_t *kd;
107429f62a6Scgd 	char *program, *fmt;
108429f62a6Scgd 	va_dcl
109429f62a6Scgd #endif
110429f62a6Scgd {
111429f62a6Scgd 	va_list ap;
112429f62a6Scgd 
113429f62a6Scgd #ifdef __STDC__
114429f62a6Scgd 	va_start(ap, fmt);
115429f62a6Scgd #else
116429f62a6Scgd 	va_start(ap);
117429f62a6Scgd #endif
118429f62a6Scgd 	if (program != NULL) {
119429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
120429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
121429f62a6Scgd 		(void)fputc('\n', stderr);
122429f62a6Scgd 	} else
123429f62a6Scgd 		(void)vsnprintf(kd->errbuf,
124429f62a6Scgd 		    sizeof(kd->errbuf), (char *)fmt, ap);
125429f62a6Scgd 
126429f62a6Scgd 	va_end(ap);
12761f28255Scgd }
128429f62a6Scgd 
129429f62a6Scgd void
130429f62a6Scgd #if __STDC__
131429f62a6Scgd _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
132429f62a6Scgd #else
133429f62a6Scgd _kvm_syserr(kd, program, fmt, va_alist)
134429f62a6Scgd 	kvm_t *kd;
135429f62a6Scgd 	char *program, *fmt;
136429f62a6Scgd 	va_dcl
137429f62a6Scgd #endif
138429f62a6Scgd {
139429f62a6Scgd 	va_list ap;
140429f62a6Scgd 	register int n;
141429f62a6Scgd 
142429f62a6Scgd #if __STDC__
143429f62a6Scgd 	va_start(ap, fmt);
144429f62a6Scgd #else
145429f62a6Scgd 	va_start(ap);
146429f62a6Scgd #endif
147429f62a6Scgd 	if (program != NULL) {
148429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
149429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
150429f62a6Scgd 		(void)fprintf(stderr, ": %s\n", strerror(errno));
15161f28255Scgd 	} else {
152429f62a6Scgd 		register char *cp = kd->errbuf;
153429f62a6Scgd 
154429f62a6Scgd 		(void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap);
155429f62a6Scgd 		n = strlen(cp);
156429f62a6Scgd 		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
157429f62a6Scgd 		    strerror(errno));
158429f62a6Scgd 	}
159429f62a6Scgd 	va_end(ap);
160429f62a6Scgd }
161429f62a6Scgd 
162429f62a6Scgd void *
163429f62a6Scgd _kvm_malloc(kd, n)
164429f62a6Scgd 	register kvm_t *kd;
165429f62a6Scgd 	register size_t n;
166429f62a6Scgd {
167429f62a6Scgd 	void *p;
168429f62a6Scgd 
169429f62a6Scgd 	if ((p = malloc(n)) == NULL)
170429f62a6Scgd 		_kvm_err(kd, kd->program, strerror(errno));
171429f62a6Scgd 	return (p);
172429f62a6Scgd }
173429f62a6Scgd 
1749c2128ecSleo /*
1759c2128ecSleo  * Wrappers for Lseek/Read system calls.  They check for errors and
1769c2128ecSleo  * call _kvm_syserr() if appropriate.
1779c2128ecSleo  */
1789c2128ecSleo static off_t
1799c2128ecSleo Lseek(kd, fd, offset, whence)
1809c2128ecSleo 	kvm_t	*kd;
1819c2128ecSleo 	int	fd, whence;
1829c2128ecSleo 	off_t	offset;
1839c2128ecSleo {
1849c2128ecSleo 	off_t	off;
1859c2128ecSleo 
1869c2128ecSleo 	errno = 0;
1879c2128ecSleo 	if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) {
1889c2128ecSleo 		_kvm_syserr(kd, kd->program, "Lseek");
1899c2128ecSleo 		return (-1);
1909c2128ecSleo 	}
1919c2128ecSleo 	return (off);
1929c2128ecSleo }
1939c2128ecSleo 
1949c2128ecSleo static ssize_t
1959c2128ecSleo Read(kd, fd, buf, nbytes)
1969c2128ecSleo 	kvm_t	*kd;
1979c2128ecSleo 	int	fd;
1989c2128ecSleo 	void	*buf;
1999c2128ecSleo 	size_t	nbytes;
2009c2128ecSleo {
2019c2128ecSleo 	ssize_t	rv;
2029c2128ecSleo 
2039c2128ecSleo 	errno = 0;
2049c2128ecSleo 
2059c2128ecSleo 	if ((rv = read(fd, buf, nbytes)) != nbytes && errno != 0)
2069c2128ecSleo 		_kvm_syserr(kd, kd->program, "Read");
2079c2128ecSleo 	return (rv);
2089c2128ecSleo }
2099c2128ecSleo 
210429f62a6Scgd static kvm_t *
211429f62a6Scgd _kvm_open(kd, uf, mf, sf, flag, errout)
212429f62a6Scgd 	register kvm_t *kd;
213429f62a6Scgd 	const char *uf;
214429f62a6Scgd 	const char *mf;
215429f62a6Scgd 	const char *sf;
216429f62a6Scgd 	int flag;
217429f62a6Scgd 	char *errout;
218429f62a6Scgd {
219429f62a6Scgd 	struct stat st;
220429f62a6Scgd 
221c3049714Smycroft 	kd->db = 0;
222429f62a6Scgd 	kd->pmfd = -1;
223c3049714Smycroft 	kd->vmfd = -1;
224429f62a6Scgd 	kd->swfd = -1;
225429f62a6Scgd 	kd->nlfd = -1;
226429f62a6Scgd 	kd->procbase = 0;
227b707f8aaSmycroft 	kd->nbpg = getpagesize();
228b707f8aaSmycroft 	kd->swapspc = 0;
229429f62a6Scgd 	kd->argspc = 0;
2306506fa2bSmycroft 	kd->argbuf = 0;
231429f62a6Scgd 	kd->argv = 0;
232c3049714Smycroft 	kd->vmst = 0;
233c3049714Smycroft 	kd->vm_page_buckets = 0;
2349c2128ecSleo 	kd->kcore_hdr = 0;
2359c2128ecSleo 	kd->cpu_hdr = 0;
2369c2128ecSleo 	kd->dump_off = 0;
237429f62a6Scgd 
238429f62a6Scgd 	if (uf == 0)
239429f62a6Scgd 		uf = _PATH_UNIX;
240429f62a6Scgd 	else if (strlen(uf) >= MAXPATHLEN) {
241429f62a6Scgd 		_kvm_err(kd, kd->program, "exec file name too long");
24261f28255Scgd 		goto failed;
24361f28255Scgd 	}
244429f62a6Scgd 	if (flag & ~O_RDWR) {
245429f62a6Scgd 		_kvm_err(kd, kd->program, "bad flags arg");
246429f62a6Scgd 		goto failed;
247429f62a6Scgd 	}
248429f62a6Scgd 	if (mf == 0)
249429f62a6Scgd 		mf = _PATH_MEM;
250429f62a6Scgd 	if (sf == 0)
251429f62a6Scgd 		sf = _PATH_DRUM;
252429f62a6Scgd 
253429f62a6Scgd 	if ((kd->pmfd = open(mf, flag, 0)) < 0) {
254429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
255429f62a6Scgd 		goto failed;
256429f62a6Scgd 	}
257429f62a6Scgd 	if (fstat(kd->pmfd, &st) < 0) {
258429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
259429f62a6Scgd 		goto failed;
260429f62a6Scgd 	}
261429f62a6Scgd 	if (S_ISCHR(st.st_mode)) {
26261f28255Scgd 		/*
263429f62a6Scgd 		 * If this is a character special device, then check that
264429f62a6Scgd 		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
265429f62a6Scgd 		 * make it work for either /dev/mem or /dev/kmem -- in either
266429f62a6Scgd 		 * case you're working with a live kernel.)
26761f28255Scgd 		 */
268429f62a6Scgd 		if (strcmp(mf, _PATH_MEM) != 0) {	/* XXX */
269429f62a6Scgd 			_kvm_err(kd, kd->program,
270429f62a6Scgd 				 "%s: not physical memory device", mf);
27161f28255Scgd 			goto failed;
27261f28255Scgd 		}
273429f62a6Scgd 		if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
274429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
275429f62a6Scgd 			goto failed;
276429f62a6Scgd 		}
277429f62a6Scgd 		if ((kd->swfd = open(sf, flag, 0)) < 0) {
278429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", sf);
279429f62a6Scgd 			goto failed;
280429f62a6Scgd 		}
281429f62a6Scgd 		/*
282429f62a6Scgd 		 * Open kvm nlist database.  We go ahead and do this
283429f62a6Scgd 		 * here so that we don't have to hold on to the vmunix
284429f62a6Scgd 		 * path name.  Since a kvm application will surely do
285429f62a6Scgd 		 * a kvm_nlist(), this probably won't be a wasted effort.
286429f62a6Scgd 		 * If the database cannot be opened, open the namelist
287429f62a6Scgd 		 * argument so we revert to slow nlist() calls.
288429f62a6Scgd 		 */
289429f62a6Scgd 		if (kvm_dbopen(kd, uf) < 0 &&
290429f62a6Scgd 		    (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
291429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", uf);
292429f62a6Scgd 			goto failed;
293429f62a6Scgd 		}
294429f62a6Scgd 	} else {
295429f62a6Scgd 		/*
296429f62a6Scgd 		 * This is a crash dump.
297429f62a6Scgd 		 * Initalize the virtual address translation machinery,
298429f62a6Scgd 		 * but first setup the namelist fd.
299429f62a6Scgd 		 */
300429f62a6Scgd 		if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
301429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", uf);
302429f62a6Scgd 			goto failed;
303429f62a6Scgd 		}
3049c2128ecSleo 
3059c2128ecSleo 		/*
3069c2128ecSleo 		 * If there is no valid core header, fail silently here.
3079c2128ecSleo 		 * The address translations however will fail without
3089c2128ecSleo 		 * header. Things can be made to run by calling
3099c2128ecSleo 		 * kvm_dump_mkheader() before doing any translation.
3109c2128ecSleo 		 */
3119c2128ecSleo 		if (_kvm_get_header(kd) == 0) {
312429f62a6Scgd 			if (_kvm_initvtop(kd) < 0)
313429f62a6Scgd 				goto failed;
314429f62a6Scgd 		}
3159c2128ecSleo 	}
316429f62a6Scgd 	return (kd);
31761f28255Scgd failed:
318429f62a6Scgd 	/*
319429f62a6Scgd 	 * Copy out the error if doing sane error semantics.
320429f62a6Scgd 	 */
321429f62a6Scgd 	if (errout != 0)
322429f62a6Scgd 		strcpy(errout, kd->errbuf);
323429f62a6Scgd 	(void)kvm_close(kd);
324429f62a6Scgd 	return (0);
32561f28255Scgd }
32661f28255Scgd 
3279c2128ecSleo static int
3289c2128ecSleo _kvm_get_header(kd)
3299c2128ecSleo kvm_t	*kd;
3309c2128ecSleo {
3319c2128ecSleo 	cpu_kcore_hdr_t	ckhdr;
3329c2128ecSleo 	kcore_hdr_t	khdr;
3339c2128ecSleo 	kcore_seg_t	seghdr;
3349c2128ecSleo 	off_t		offset;
3359c2128ecSleo 
3369c2128ecSleo 	if (Lseek(kd, kd->pmfd, (off_t)0, SEEK_SET) == -1)
3379c2128ecSleo 		return (-1);
3389c2128ecSleo 
3399c2128ecSleo 	if (Read(kd, kd->pmfd, &khdr, sizeof(khdr)) != sizeof(khdr))
3409c2128ecSleo 		return (-1);
3419c2128ecSleo 	offset = khdr.c_hdrsize;
3429c2128ecSleo 
3439c2128ecSleo 	/*
3449c2128ecSleo 	 * Currently, we only support dump-files made by the current
3459c2128ecSleo 	 * architecture...
3469c2128ecSleo 	 */
3479c2128ecSleo 	if ((CORE_GETMAGIC(khdr) != KCORE_MAGIC)
3489c2128ecSleo 	     || ((CORE_GETMID(khdr) != MID_MACHINE)))
3499c2128ecSleo 			return (-1);
3509c2128ecSleo 
3519c2128ecSleo 	/*
3529c2128ecSleo 	 * Currently, we only support exactly 2 segments: cpu-segment
3539c2128ecSleo 	 * and data-segment in exactly that order.
3549c2128ecSleo 	 */
3559c2128ecSleo 	if (khdr.c_nseg != 2)
3569c2128ecSleo 		return (-1);
3579c2128ecSleo 
3589c2128ecSleo 	/*
3599c2128ecSleo 	 * Read the next segment header: cpu segment
3609c2128ecSleo 	 */
3619c2128ecSleo 	if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1)
3629c2128ecSleo 		return (-1);
3639c2128ecSleo 	if (Read(kd, kd->pmfd, &seghdr, sizeof(seghdr)) != sizeof(seghdr))
3649c2128ecSleo 		return (-1);
3659c2128ecSleo 	if (CORE_GETMAGIC(seghdr) != KCORESEG_MAGIC
3669c2128ecSleo 		|| CORE_GETFLAG(seghdr) != CORE_CPU)
3679c2128ecSleo 		return (-1);
3689c2128ecSleo 	offset += khdr.c_seghdrsize;
3699c2128ecSleo 	if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1)
3709c2128ecSleo 		return (-1);
3719c2128ecSleo 	if (Read(kd, kd->pmfd, &ckhdr, sizeof(ckhdr)) != sizeof(ckhdr))
3729c2128ecSleo 		return (-1);
3739c2128ecSleo 	offset += seghdr.c_size;
3749c2128ecSleo 
3759c2128ecSleo 	/*
3769c2128ecSleo 	 * Read the next segment header: data segment
3779c2128ecSleo 	 */
3789c2128ecSleo 	if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1)
3799c2128ecSleo 		return (-1);
3809c2128ecSleo 	if (Read(kd, kd->pmfd, &seghdr, sizeof(seghdr)) != sizeof(seghdr))
3819c2128ecSleo 		return (-1);
3829c2128ecSleo 	offset += khdr.c_seghdrsize;
3839c2128ecSleo 
3849c2128ecSleo 	if (CORE_GETMAGIC(seghdr) != KCORESEG_MAGIC
3859c2128ecSleo 		|| CORE_GETFLAG(seghdr) != CORE_DATA)
3869c2128ecSleo 		return (-1);
3879c2128ecSleo 
3889c2128ecSleo 	kd->kcore_hdr = (kcore_hdr_t *)_kvm_malloc(kd, sizeof(*kd->kcore_hdr));
3899c2128ecSleo 	if (kd->kcore_hdr == NULL)
3909c2128ecSleo 		return (-1);
3919c2128ecSleo 	kd->cpu_hdr = (cpu_kcore_hdr_t *)_kvm_malloc(kd, sizeof(*kd->cpu_hdr));
3929c2128ecSleo 	if (kd->cpu_hdr == NULL) {
3939c2128ecSleo 		free((void *)kd->kcore_hdr);
3949c2128ecSleo 		kd->kcore_hdr = NULL;
3959c2128ecSleo 		return (-1);
3969c2128ecSleo 	}
3979c2128ecSleo 
3989c2128ecSleo 	*kd->kcore_hdr = khdr;
3999c2128ecSleo 	*kd->cpu_hdr   = ckhdr;
4009c2128ecSleo 	kd->dump_off   = offset;
4019c2128ecSleo 	return (0);
4029c2128ecSleo }
4039c2128ecSleo 
4049c2128ecSleo /*
4059c2128ecSleo  * Translate a physical address to a file-offset in the crash-dump.
4069c2128ecSleo  */
4079c2128ecSleo off_t
4089c2128ecSleo _kvm_pa2off(kd, pa)
4099c2128ecSleo 	kvm_t	*kd;
4109c2128ecSleo 	u_long	pa;
4119c2128ecSleo {
4129c2128ecSleo 	off_t		off;
4139c2128ecSleo 	phys_ram_seg_t	*rsp;
4149c2128ecSleo 
4159c2128ecSleo 	off = 0;
4169c2128ecSleo 	for (rsp = kd->cpu_hdr->ram_segs; rsp->size; rsp++) {
4179c2128ecSleo 		if (pa >= rsp->start && pa < rsp->start + rsp->size) {
4189c2128ecSleo 			pa -= rsp->start;
4199c2128ecSleo 			break;
4209c2128ecSleo 		}
4219c2128ecSleo 		off += rsp->size;
4229c2128ecSleo 	}
4239c2128ecSleo 	return(pa + off + kd->dump_off);
4249c2128ecSleo }
4259c2128ecSleo 
4269c2128ecSleo int
427*be74d305Sleo kvm_dump_mkheader(kd, dump_off)
428*be74d305Sleo kvm_t	*kd;
4299c2128ecSleo off_t	dump_off;
4309c2128ecSleo {
4319c2128ecSleo 	kcore_hdr_t	kch;
4329c2128ecSleo 	kcore_seg_t	kseg;
4339c2128ecSleo 	cpu_kcore_hdr_t	ckhdr;
4349c2128ecSleo 	int		hdr_size;
4359c2128ecSleo 
4369c2128ecSleo 	hdr_size = 0;
437*be74d305Sleo 	if (kd->kcore_hdr != NULL) {
438*be74d305Sleo 	    _kvm_err(kd, kd->program, "already has a dump header");
4399c2128ecSleo 	    return (-1);
4409c2128ecSleo 	}
441*be74d305Sleo 	if (ISALIVE(kd)) {
442*be74d305Sleo 		_kvm_err(kd, kd->program, "don't use on live kernel");
4439c2128ecSleo 		return (-1);
4449c2128ecSleo 	}
4459c2128ecSleo 
4469c2128ecSleo 	/*
4479c2128ecSleo 	 * Check for new format crash dump
4489c2128ecSleo 	 */
449*be74d305Sleo 	if (Lseek(kd, kd->pmfd, dump_off, SEEK_SET) == -1)
4509c2128ecSleo 		return (-1);
451*be74d305Sleo 	if (Read(kd, kd->pmfd, &kseg, sizeof(kseg)) != sizeof(kseg))
4529c2128ecSleo 		return (-1);
4539c2128ecSleo 	if ((CORE_GETMAGIC(kseg) == KCORE_MAGIC)
4549c2128ecSleo 	     && ((CORE_GETMID(kseg) == MID_MACHINE))) {
4559c2128ecSleo 		hdr_size += ALIGN(sizeof(kcore_seg_t));
456*be74d305Sleo 		if (Lseek(kd, kd->pmfd, dump_off+hdr_size, SEEK_SET) == -1)
4579c2128ecSleo 			return (-1);
458*be74d305Sleo 		if (Read(kd, kd->pmfd, &ckhdr, sizeof(ckhdr)) != sizeof(ckhdr))
4599c2128ecSleo 			return (-1);
4609c2128ecSleo 		hdr_size += kseg.c_size;
461*be74d305Sleo 		if (Lseek(kd, kd->pmfd, dump_off+hdr_size, SEEK_SET) == -1)
4629c2128ecSleo 			return (-1);
463*be74d305Sleo 		kd->cpu_hdr = (cpu_kcore_hdr_t *)
464*be74d305Sleo 				_kvm_malloc(kd, sizeof(cpu_kcore_hdr_t));
465*be74d305Sleo 		*kd->cpu_hdr = ckhdr;
4669c2128ecSleo 	}
4679c2128ecSleo 
4689c2128ecSleo 	/*
4699c2128ecSleo 	 * Create a kcore_hdr.
4709c2128ecSleo 	 */
471*be74d305Sleo 	kd->kcore_hdr = (kcore_hdr_t *) _kvm_malloc(kd, sizeof(kcore_hdr_t));
472*be74d305Sleo 	if (kd->kcore_hdr == NULL) {
473*be74d305Sleo 		if (kd->cpu_hdr != NULL) {
474*be74d305Sleo 			free((void *)kd->cpu_hdr);
475*be74d305Sleo 			kd->cpu_hdr = NULL;
4769c2128ecSleo 		}
4779c2128ecSleo 		return (-1);
4789c2128ecSleo 	}
4799c2128ecSleo 
480*be74d305Sleo 	kd->kcore_hdr->c_hdrsize    = ALIGN(sizeof(kcore_hdr_t));
481*be74d305Sleo 	kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t));
482*be74d305Sleo 	kd->kcore_hdr->c_nseg       = 2;
483*be74d305Sleo 	CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0);
4849c2128ecSleo 
4859c2128ecSleo 	/*
4869c2128ecSleo 	 * If there is no cpu_hdr at this point, we probably have an
4879c2128ecSleo 	 * old format crash dump.....bail out
4889c2128ecSleo 	 */
489*be74d305Sleo 	if (kd->cpu_hdr == NULL) {
490*be74d305Sleo 		free((void *)kd->kcore_hdr);
491*be74d305Sleo 		kd->kcore_hdr = NULL;
492*be74d305Sleo 		_kvm_err(kd, kd->program, "invalid dump");
4939c2128ecSleo 	}
4949c2128ecSleo 
495*be74d305Sleo 	kd->dump_off  = dump_off + hdr_size;
4969c2128ecSleo 
4979c2128ecSleo 	/*
4989c2128ecSleo 	 * Now that we have a valid header, enable translations.
4999c2128ecSleo 	 */
500*be74d305Sleo 	_kvm_initvtop(kd);
5019c2128ecSleo 
5029c2128ecSleo 	return(hdr_size);
5039c2128ecSleo }
5049c2128ecSleo 
5059c2128ecSleo static int
5069c2128ecSleo clear_gap(kd, fp, size)
5079c2128ecSleo kvm_t	*kd;
5089c2128ecSleo FILE	*fp;
5099c2128ecSleo int	size;
5109c2128ecSleo {
5119c2128ecSleo 	if (size <= 0) /* XXX - < 0 should never happen */
5129c2128ecSleo 		return (0);
5139c2128ecSleo 	while (size-- > 0) {
5149c2128ecSleo 		if (fputc(0, fp) == EOF) {
5159c2128ecSleo 			_kvm_syserr(kd, kd->program, "clear_gap");
5169c2128ecSleo 			return (-1);
5179c2128ecSleo 		}
5189c2128ecSleo 	}
5199c2128ecSleo 	return (0);
5209c2128ecSleo }
5219c2128ecSleo 
5229c2128ecSleo /*
5239c2128ecSleo  * Write the dump header info to 'fp'. Note that we can't use fseek(3) here
5249c2128ecSleo  * because 'fp' might be a file pointer obtained by zopen().
5259c2128ecSleo  */
5269c2128ecSleo int
5279c2128ecSleo kvm_dump_wrtheader(kd, fp, dumpsize)
5289c2128ecSleo kvm_t	*kd;
5299c2128ecSleo FILE	*fp;
5309c2128ecSleo int	dumpsize;
5319c2128ecSleo {
5329c2128ecSleo 	kcore_seg_t	seghdr;
5339c2128ecSleo 	long		offset;
5349c2128ecSleo 	int		gap;
5359c2128ecSleo 
5369c2128ecSleo 	if (kd->kcore_hdr == NULL || kd->cpu_hdr == NULL) {
5379c2128ecSleo 		_kvm_err(kd, kd->program, "no valid dump header(s)");
5389c2128ecSleo 		return (-1);
5399c2128ecSleo 	}
5409c2128ecSleo 
5419c2128ecSleo 	/*
5429c2128ecSleo 	 * Write the generic header
5439c2128ecSleo 	 */
5449c2128ecSleo 	offset = 0;
5459c2128ecSleo 	if (fwrite((void*)kd->kcore_hdr, sizeof(kcore_hdr_t), 1, fp) <= 0) {
5469c2128ecSleo 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5479c2128ecSleo 		return (-1);
5489c2128ecSleo 	}
5499c2128ecSleo 	offset += kd->kcore_hdr->c_hdrsize;
5509c2128ecSleo 	gap     = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t);
5519c2128ecSleo 	if (clear_gap(kd, fp, gap) == -1)
5529c2128ecSleo 		return (-1);
5539c2128ecSleo 
5549c2128ecSleo 	/*
5559c2128ecSleo 	 * Write the cpu header
5569c2128ecSleo 	 */
5579c2128ecSleo 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU);
5589c2128ecSleo 	seghdr.c_size = ALIGN(sizeof(cpu_kcore_hdr_t));
5599c2128ecSleo 	if (fwrite((void*)&seghdr, sizeof(seghdr), 1, fp) <= 0) {
5609c2128ecSleo 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5619c2128ecSleo 		return (-1);
5629c2128ecSleo 	}
5639c2128ecSleo 	offset += kd->kcore_hdr->c_seghdrsize;
5649c2128ecSleo 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
5659c2128ecSleo 	if (clear_gap(kd, fp, gap) == -1)
5669c2128ecSleo 		return (-1);
5679c2128ecSleo 
5689c2128ecSleo 	if (fwrite((void*)kd->cpu_hdr, sizeof(cpu_kcore_hdr_t), 1, fp) <= 0) {
5699c2128ecSleo 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5709c2128ecSleo 		return (-1);
5719c2128ecSleo 	}
5729c2128ecSleo 	offset += seghdr.c_size;
5739c2128ecSleo 	gap     = seghdr.c_size - sizeof(cpu_kcore_hdr_t);
5749c2128ecSleo 	if (clear_gap(kd, fp, gap) == -1)
5759c2128ecSleo 		return (-1);
5769c2128ecSleo 
5779c2128ecSleo 	/*
5789c2128ecSleo 	 * Write the actual dump data segment header
5799c2128ecSleo 	 */
5809c2128ecSleo 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA);
5819c2128ecSleo 	seghdr.c_size = dumpsize;
5829c2128ecSleo 	if (fwrite((void*)&seghdr, sizeof(seghdr), 1, fp) <= 0) {
5839c2128ecSleo 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5849c2128ecSleo 		return (-1);
5859c2128ecSleo 	}
5869c2128ecSleo 	offset += kd->kcore_hdr->c_seghdrsize;
5879c2128ecSleo 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
5889c2128ecSleo 	if (clear_gap(kd, fp, gap) == -1)
5899c2128ecSleo 		return (-1);
5909c2128ecSleo 
5919c2128ecSleo 	return (offset);
5929c2128ecSleo }
5939c2128ecSleo 
594429f62a6Scgd kvm_t *
595429f62a6Scgd kvm_openfiles(uf, mf, sf, flag, errout)
596429f62a6Scgd 	const char *uf;
597429f62a6Scgd 	const char *mf;
598429f62a6Scgd 	const char *sf;
599429f62a6Scgd 	int flag;
600429f62a6Scgd 	char *errout;
60161f28255Scgd {
602429f62a6Scgd 	register kvm_t *kd;
603429f62a6Scgd 
604429f62a6Scgd 	if ((kd = malloc(sizeof(*kd))) == NULL) {
605429f62a6Scgd 		(void)strcpy(errout, strerror(errno));
606429f62a6Scgd 		return (0);
607429f62a6Scgd 	}
608429f62a6Scgd 	kd->program = 0;
609429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, errout));
610429f62a6Scgd }
611429f62a6Scgd 
612429f62a6Scgd kvm_t *
613429f62a6Scgd kvm_open(uf, mf, sf, flag, program)
614429f62a6Scgd 	const char *uf;
615429f62a6Scgd 	const char *mf;
616429f62a6Scgd 	const char *sf;
617429f62a6Scgd 	int flag;
618429f62a6Scgd 	const char *program;
619429f62a6Scgd {
620429f62a6Scgd 	register kvm_t *kd;
621429f62a6Scgd 
622429f62a6Scgd 	if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) {
623429f62a6Scgd 		(void)fprintf(stderr, "%s: %s\n", strerror(errno));
624429f62a6Scgd 		return (0);
625429f62a6Scgd 	}
626429f62a6Scgd 	kd->program = program;
627429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
628429f62a6Scgd }
629429f62a6Scgd 
630429f62a6Scgd int
631429f62a6Scgd kvm_close(kd)
632429f62a6Scgd 	kvm_t *kd;
633429f62a6Scgd {
634429f62a6Scgd 	register int error = 0;
635429f62a6Scgd 
636429f62a6Scgd 	if (kd->pmfd >= 0)
637429f62a6Scgd 		error |= close(kd->pmfd);
638429f62a6Scgd 	if (kd->vmfd >= 0)
639429f62a6Scgd 		error |= close(kd->vmfd);
640429f62a6Scgd 	if (kd->nlfd >= 0)
641429f62a6Scgd 		error |= close(kd->nlfd);
642429f62a6Scgd 	if (kd->swfd >= 0)
643429f62a6Scgd 		error |= close(kd->swfd);
644429f62a6Scgd 	if (kd->db != 0)
645429f62a6Scgd 		error |= (kd->db->close)(kd->db);
646429f62a6Scgd 	if (kd->vmst)
647429f62a6Scgd 		_kvm_freevtop(kd);
6489c2128ecSleo 	if (kd->cpu_hdr != NULL)
6499c2128ecSleo 		free((void *)kd->cpu_hdr);
6509c2128ecSleo 	if (kd->kcore_hdr != NULL)
6519c2128ecSleo 		free((void *)kd->kcore_hdr);
652429f62a6Scgd 	if (kd->procbase != 0)
653429f62a6Scgd 		free((void *)kd->procbase);
654b707f8aaSmycroft 	if (kd->swapspc != 0)
655b707f8aaSmycroft 		free((void *)kd->swapspc);
656b707f8aaSmycroft 	if (kd->argspc != 0)
657b707f8aaSmycroft 		free((void *)kd->argspc);
6586506fa2bSmycroft 	if (kd->argbuf != 0)
6596506fa2bSmycroft 		free((void *)kd->argbuf);
660429f62a6Scgd 	if (kd->argv != 0)
661429f62a6Scgd 		free((void *)kd->argv);
662429f62a6Scgd 	free((void *)kd);
66361f28255Scgd 
66461f28255Scgd 	return (0);
66561f28255Scgd }
66661f28255Scgd 
667429f62a6Scgd /*
668429f62a6Scgd  * Set up state necessary to do queries on the kernel namelist
669429f62a6Scgd  * data base.  If the data base is out-of-data/incompatible with
670429f62a6Scgd  * given executable, set up things so we revert to standard nlist call.
671429f62a6Scgd  * Only called for live kernels.  Return 0 on success, -1 on failure.
672429f62a6Scgd  */
673429f62a6Scgd static int
674429f62a6Scgd kvm_dbopen(kd, uf)
675429f62a6Scgd 	kvm_t *kd;
676429f62a6Scgd 	const char *uf;
67761f28255Scgd {
678429f62a6Scgd 	char *cp;
679429f62a6Scgd 	DBT rec;
680429f62a6Scgd 	int dbversionlen;
681429f62a6Scgd 	struct nlist nitem;
68261f28255Scgd 	char dbversion[_POSIX2_LINE_MAX];
68361f28255Scgd 	char kversion[_POSIX2_LINE_MAX];
684429f62a6Scgd 	char dbname[MAXPATHLEN];
68561f28255Scgd 
686429f62a6Scgd 	if ((cp = rindex(uf, '/')) != 0)
687429f62a6Scgd 		uf = cp + 1;
688429f62a6Scgd 
689429f62a6Scgd 	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
690429f62a6Scgd 	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
691429f62a6Scgd 	if (kd->db == 0)
69261f28255Scgd 		return (-1);
69361f28255Scgd 	/*
69461f28255Scgd 	 * read version out of database
69561f28255Scgd 	 */
696429f62a6Scgd 	rec.data = VRS_KEY;
697429f62a6Scgd 	rec.size = sizeof(VRS_KEY) - 1;
698429f62a6Scgd 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
699429f62a6Scgd 		goto close;
700429f62a6Scgd 	if (rec.data == 0 || rec.size > sizeof(dbversion))
701429f62a6Scgd 		goto close;
702429f62a6Scgd 
703429f62a6Scgd 	bcopy(rec.data, dbversion, rec.size);
704429f62a6Scgd 	dbversionlen = rec.size;
70561f28255Scgd 	/*
706429f62a6Scgd 	 * Read version string from kernel memory.
707429f62a6Scgd 	 * Since we are dealing with a live kernel, we can call kvm_read()
708429f62a6Scgd 	 * at this point.
70961f28255Scgd 	 */
710429f62a6Scgd 	rec.data = VRS_SYM;
711429f62a6Scgd 	rec.size = sizeof(VRS_SYM) - 1;
712429f62a6Scgd 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
713429f62a6Scgd 		goto close;
714429f62a6Scgd 	if (rec.data == 0 || rec.size != sizeof(struct nlist))
715429f62a6Scgd 		goto close;
716429f62a6Scgd 	bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
717429f62a6Scgd 	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
718429f62a6Scgd 	    dbversionlen)
719429f62a6Scgd 		goto close;
72061f28255Scgd 	/*
721429f62a6Scgd 	 * If they match, we win - otherwise clear out kd->db so
722429f62a6Scgd 	 * we revert to slow nlist().
72361f28255Scgd 	 */
724429f62a6Scgd 	if (bcmp(dbversion, kversion, dbversionlen) == 0)
725429f62a6Scgd 		return (0);
726429f62a6Scgd close:
727429f62a6Scgd 	(void)(kd->db->close)(kd->db);
728429f62a6Scgd 	kd->db = 0;
729429f62a6Scgd 
73061f28255Scgd 	return (-1);
73161f28255Scgd }
73261f28255Scgd 
7335089c413Scgd int
734429f62a6Scgd kvm_nlist(kd, nl)
735429f62a6Scgd 	kvm_t *kd;
736429f62a6Scgd 	struct nlist *nl;
7375089c413Scgd {
738429f62a6Scgd 	register struct nlist *p;
739429f62a6Scgd 	register int nvalid;
7405089c413Scgd 
741429f62a6Scgd 	/*
742429f62a6Scgd 	 * If we can't use the data base, revert to the
743429f62a6Scgd 	 * slow library call.
744429f62a6Scgd 	 */
745429f62a6Scgd 	if (kd->db == 0)
746429f62a6Scgd 		return (__fdnlist(kd->nlfd, nl));
7475089c413Scgd 
748429f62a6Scgd 	/*
749429f62a6Scgd 	 * We can use the kvm data base.  Go through each nlist entry
750429f62a6Scgd 	 * and look it up with a db query.
751429f62a6Scgd 	 */
752429f62a6Scgd 	nvalid = 0;
753429f62a6Scgd 	for (p = nl; p->n_name && p->n_name[0]; ++p) {
754429f62a6Scgd 		register int len;
755429f62a6Scgd 		DBT rec;
7565089c413Scgd 
757429f62a6Scgd 		if ((len = strlen(p->n_name)) > 4096) {
758429f62a6Scgd 			/* sanity */
759429f62a6Scgd 			_kvm_err(kd, kd->program, "symbol too large");
760429f62a6Scgd 			return (-1);
76122eaa1f2Smycroft 		}
762429f62a6Scgd 		rec.data = p->n_name;
763429f62a6Scgd 		rec.size = len;
7649c2128ecSleo 
7659c2128ecSleo 		/*
7669c2128ecSleo 		 * Make sure that n_value = 0 when the symbol isn't found
7679c2128ecSleo 		 */
7689c2128ecSleo 		p->n_value = 0;
7699c2128ecSleo 
770429f62a6Scgd 		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
771429f62a6Scgd 			continue;
772429f62a6Scgd 		if (rec.data == 0 || rec.size != sizeof(struct nlist))
773429f62a6Scgd 			continue;
774429f62a6Scgd 		++nvalid;
775429f62a6Scgd 		/*
776429f62a6Scgd 		 * Avoid alignment issues.
777429f62a6Scgd 		 */
778429f62a6Scgd 		bcopy((char *)&((struct nlist *)rec.data)->n_type,
779429f62a6Scgd 		      (char *)&p->n_type,
780429f62a6Scgd 		      sizeof(p->n_type));
781429f62a6Scgd 		bcopy((char *)&((struct nlist *)rec.data)->n_value,
782429f62a6Scgd 		      (char *)&p->n_value,
783429f62a6Scgd 		      sizeof(p->n_value));
7845089c413Scgd 	}
785429f62a6Scgd 	/*
786429f62a6Scgd 	 * Return the number of entries that weren't found.
787429f62a6Scgd 	 */
788429f62a6Scgd 	return ((p - nl) - nvalid);
789db3323c9Smycroft }
7905089c413Scgd 
7919c2128ecSleo int kvm_dump_inval(kd)
7929c2128ecSleo kvm_t	*kd;
7939c2128ecSleo {
7949c2128ecSleo 	struct nlist	nlist[2];
7959c2128ecSleo 	u_long		pa;
7969c2128ecSleo 
7979c2128ecSleo 	if (ISALIVE(kd)) {
7989c2128ecSleo 		_kvm_err(kd, kd->program, "clearing dump on live kernel");
7999c2128ecSleo 		return (-1);
8009c2128ecSleo 	}
8019c2128ecSleo 	nlist[0].n_name = "_dumpmag";
8029c2128ecSleo 	nlist[1].n_name = NULL;
8039c2128ecSleo 
8049c2128ecSleo 	if (kvm_nlist(kd, nlist) == -1) {
8059c2128ecSleo 		_kvm_err(kd, 0, "bad namelist");
8069c2128ecSleo 		return (-1);
8079c2128ecSleo 	}
8089c2128ecSleo 	if (_kvm_kvatop(kd, (u_long)nlist[0].n_value, &pa) == 0)
8099c2128ecSleo 		return (-1);
8109c2128ecSleo 
8119c2128ecSleo 	errno = 0;
8129c2128ecSleo 	if (lseek(kd->pmfd, _kvm_pa2off(kd, pa), SEEK_SET) == -1
8139c2128ecSleo 		&& errno != 0) {
8149c2128ecSleo 		_kvm_err(kd, 0, "cannot invalidate dump - lseek");
8159c2128ecSleo 		return (-1);
8169c2128ecSleo 	}
8179c2128ecSleo 	pa = 0;
8189c2128ecSleo 	if (write(kd->pmfd, &pa, sizeof(pa)) != sizeof(pa)) {
8199c2128ecSleo 		_kvm_err(kd, 0, "cannot invalidate dump - write");
8209c2128ecSleo 		return (-1);
8219c2128ecSleo 	}
8229c2128ecSleo 	return (0);
8239c2128ecSleo }
8249c2128ecSleo 
825429f62a6Scgd ssize_t
826429f62a6Scgd kvm_read(kd, kva, buf, len)
827429f62a6Scgd 	kvm_t *kd;
828429f62a6Scgd 	register u_long kva;
829429f62a6Scgd 	register void *buf;
830429f62a6Scgd 	register size_t len;
8315089c413Scgd {
832429f62a6Scgd 	register int cc;
833429f62a6Scgd 	register void *cp;
8345089c413Scgd 
835429f62a6Scgd 	if (ISALIVE(kd)) {
836429f62a6Scgd 		/*
837429f62a6Scgd 		 * We're using /dev/kmem.  Just read straight from the
838429f62a6Scgd 		 * device and let the active kernel do the address translation.
839429f62a6Scgd 		 */
840429f62a6Scgd 		errno = 0;
8419c2128ecSleo 		if (lseek(kd->vmfd, (off_t)kva, SEEK_SET) == -1
8429c2128ecSleo 			&& errno != 0) {
843429f62a6Scgd 			_kvm_err(kd, 0, "invalid address (%x)", kva);
84461f28255Scgd 			return (0);
84561f28255Scgd 		}
846429f62a6Scgd 		cc = read(kd->vmfd, buf, len);
847429f62a6Scgd 		if (cc < 0) {
848429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_read");
849429f62a6Scgd 			return (0);
850429f62a6Scgd 		} else if (cc < len)
851429f62a6Scgd 			_kvm_err(kd, kd->program, "short read");
852429f62a6Scgd 		return (cc);
853429f62a6Scgd 	} else {
8549c2128ecSleo 		if ((kd->kcore_hdr == NULL) || (kd->cpu_hdr == NULL)) {
8559c2128ecSleo 			_kvm_err(kd, kd->program, "no valid dump header");
8569c2128ecSleo 			return (0);
8579c2128ecSleo 		}
858429f62a6Scgd 		cp = buf;
859429f62a6Scgd 		while (len > 0) {
860429f62a6Scgd 			u_long	pa;
8619c2128ecSleo 			off_t	foff;
86261f28255Scgd 
863429f62a6Scgd 			cc = _kvm_kvatop(kd, kva, &pa);
864429f62a6Scgd 			if (cc == 0)
865429f62a6Scgd 				return (0);
866429f62a6Scgd 			if (cc > len)
867429f62a6Scgd 				cc = len;
8689c2128ecSleo 			foff = _kvm_pa2off(kd, pa);
869429f62a6Scgd 			errno = 0;
8709c2128ecSleo 			if (lseek(kd->pmfd, foff, SEEK_SET) == -1
8719c2128ecSleo 				&& errno != 0) {
872429f62a6Scgd 				_kvm_syserr(kd, 0, _PATH_MEM);
873ea0119dbScgd 				break;
874669b9e50Smycroft 			}
875429f62a6Scgd 			cc = read(kd->pmfd, cp, cc);
876429f62a6Scgd 			if (cc < 0) {
877429f62a6Scgd 				_kvm_syserr(kd, kd->program, "kvm_read");
878ea0119dbScgd 				break;
879ea0119dbScgd 			}
8807b1fbb1cSpk 			/*
881429f62a6Scgd 			 * If kvm_kvatop returns a bogus value or our core
882429f62a6Scgd 			 * file is truncated, we might wind up seeking beyond
883429f62a6Scgd 			 * the end of the core file in which case the read will
884429f62a6Scgd 			 * return 0 (EOF).
8857b1fbb1cSpk 			 */
886429f62a6Scgd 			if (cc == 0)
887429f62a6Scgd 				break;
88800fd6050Scgd 			cp = (char *)cp + cc;
889429f62a6Scgd 			kva += cc;
890429f62a6Scgd 			len -= cc;
891429f62a6Scgd 		}
892429f62a6Scgd 		return ((char *)cp - (char *)buf);
893429f62a6Scgd 	}
894429f62a6Scgd 	/* NOTREACHED */
895429f62a6Scgd }
8967b1fbb1cSpk 
897429f62a6Scgd ssize_t
898429f62a6Scgd kvm_write(kd, kva, buf, len)
899429f62a6Scgd 	kvm_t *kd;
900429f62a6Scgd 	register u_long kva;
901429f62a6Scgd 	register const void *buf;
902429f62a6Scgd 	register size_t len;
903429f62a6Scgd {
904429f62a6Scgd 	register int cc;
9057b1fbb1cSpk 
906429f62a6Scgd 	if (ISALIVE(kd)) {
9077b1fbb1cSpk 		/*
908429f62a6Scgd 		 * Just like kvm_read, only we write.
9097b1fbb1cSpk 		 */
910429f62a6Scgd 		errno = 0;
9119c2128ecSleo 		if (lseek(kd->vmfd, (off_t)kva, SEEK_SET) == -1
9129c2128ecSleo 			&& errno != 0) {
913429f62a6Scgd 			_kvm_err(kd, 0, "invalid address (%x)", kva);
914429f62a6Scgd 			return (0);
9157b1fbb1cSpk 		}
916429f62a6Scgd 		cc = write(kd->vmfd, buf, len);
917429f62a6Scgd 		if (cc < 0) {
918429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_write");
919429f62a6Scgd 			return (0);
920429f62a6Scgd 		} else if (cc < len)
921429f62a6Scgd 			_kvm_err(kd, kd->program, "short write");
922429f62a6Scgd 		return (cc);
923429f62a6Scgd 	} else {
924429f62a6Scgd 		_kvm_err(kd, kd->program,
925429f62a6Scgd 		    "kvm_write not implemented for dead kernels");
926429f62a6Scgd 		return (0);
9277b1fbb1cSpk 	}
928429f62a6Scgd 	/* NOTREACHED */
92961f28255Scgd }
930