xref: /openbsd-src/lib/libkvm/kvm.c (revision 4ec73a122782516ae2bc361388b0dd1a22baff3a)
1*4ec73a12Sderaadt /*	$OpenBSD: kvm.c,v 1.72 2022/02/22 17:35:01 deraadt Exp $ */
25a9ac2daSderaadt /*	$NetBSD: kvm.c,v 1.43 1996/05/05 04:31:59 gwr Exp $	*/
33fbbad10Sniklas 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1989, 1992, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software developed by the Computer Systems
9df930be7Sderaadt  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
10df930be7Sderaadt  * BG 91-66 and contributed to Berkeley.
11df930be7Sderaadt  *
12df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
13df930be7Sderaadt  * modification, are permitted provided that the following conditions
14df930be7Sderaadt  * are met:
15df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
16df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
17df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
18df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
19df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
206580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
21df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
22df930be7Sderaadt  *    without specific prior written permission.
23df930be7Sderaadt  *
24df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df930be7Sderaadt  * SUCH DAMAGE.
35df930be7Sderaadt  */
36df930be7Sderaadt 
37*4ec73a12Sderaadt #include <sys/param.h>	/* MID_MACHINE */
38*4ec73a12Sderaadt #include <sys/types.h>
393736a0a0Sderaadt #include <sys/signal.h>
40df930be7Sderaadt #include <sys/proc.h>
41df930be7Sderaadt #include <sys/ioctl.h>
42df930be7Sderaadt #include <sys/stat.h>
43df930be7Sderaadt #include <sys/sysctl.h>
44df930be7Sderaadt 
453fbbad10Sniklas #include <sys/core.h>
46d335c2c7Sderaadt #include <sys/exec.h>
473fbbad10Sniklas #include <sys/kcore.h>
483fbbad10Sniklas 
4950e7fddbStedu #include <stddef.h>
5001002944Sderaadt #include <errno.h>
51df930be7Sderaadt #include <ctype.h>
52df930be7Sderaadt #include <db.h>
53df930be7Sderaadt #include <fcntl.h>
548142bab5Smillert #include <libgen.h>
55df930be7Sderaadt #include <limits.h>
56df930be7Sderaadt #include <nlist.h>
57df930be7Sderaadt #include <paths.h>
58df930be7Sderaadt #include <stdio.h>
59df930be7Sderaadt #include <stdlib.h>
60df930be7Sderaadt #include <string.h>
61df930be7Sderaadt #include <unistd.h>
6215f0ebb0Sderaadt #include <kvm.h>
63e7beb4a7Smillert #include <stdarg.h>
64df930be7Sderaadt 
65df930be7Sderaadt #include "kvm_private.h"
66df930be7Sderaadt 
67b7e5637aSmiod extern int __fdnlist(int, struct nlist *);
68b7e5637aSmiod 
69c72b5b24Smillert static int	kvm_dbopen(kvm_t *, const char *);
700205f8e6Sguenther static int	kvm_opennamelist(kvm_t *, const char *);
71c72b5b24Smillert static int	_kvm_get_header(kvm_t *);
72f3c3a9c6Smillert static kvm_t	*_kvm_open(kvm_t *, const char *, const char *, const char *,
73f3c3a9c6Smillert 		     int, char *);
74c72b5b24Smillert static int	clear_gap(kvm_t *, FILE *, int);
75df930be7Sderaadt 
76df930be7Sderaadt char *
kvm_geterr(kvm_t * kd)7799c66d6aSguenther kvm_geterr(kvm_t *kd)
78df930be7Sderaadt {
79df930be7Sderaadt 	return (kd->errbuf);
80df930be7Sderaadt }
81df930be7Sderaadt 
82df930be7Sderaadt /*
83b662a545Sart  * Wrapper around pread.
84b662a545Sart  */
85b662a545Sart ssize_t
_kvm_pread(kvm_t * kd,int fd,void * buf,size_t nbytes,off_t offset)86b662a545Sart _kvm_pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset)
87b662a545Sart {
88b662a545Sart 	ssize_t rval;
89b662a545Sart 
90b662a545Sart 	errno = 0;
91b662a545Sart 	rval = pread(fd, buf, nbytes, offset);
92b662a545Sart 	if (rval == -1 || errno != 0) {
93b662a545Sart 		_kvm_syserr(kd, kd->program, "pread");
94b662a545Sart 	}
95b662a545Sart 	return (rval);
96b662a545Sart }
97b662a545Sart 
98b662a545Sart /*
99b662a545Sart  * Wrapper around pwrite.
100b662a545Sart  */
101b662a545Sart ssize_t
_kvm_pwrite(kvm_t * kd,int fd,const void * buf,size_t nbytes,off_t offset)1029db2f38bSderaadt _kvm_pwrite(kvm_t *kd, int fd, const void *buf, size_t nbytes, off_t offset)
103b662a545Sart {
104b662a545Sart 	ssize_t rval;
105b662a545Sart 
106b662a545Sart 	errno = 0;
107b662a545Sart 	rval = pwrite(fd, buf, nbytes, offset);
108b662a545Sart 	if (rval == -1 || errno != 0) {
109b662a545Sart 		_kvm_syserr(kd, kd->program, "pwrite");
110b662a545Sart 	}
111b662a545Sart 	return (rval);
112b662a545Sart }
113b662a545Sart 
114b662a545Sart /*
115df930be7Sderaadt  * Report an error using printf style arguments.  "program" is kd->program
116df930be7Sderaadt  * on hard errors, and 0 on soft errors, so that under sun error emulation,
117df930be7Sderaadt  * only hard errors are printed out (otherwise, programs like gdb will
118df930be7Sderaadt  * generate tons of error messages when trying to access bogus pointers).
119df930be7Sderaadt  */
120df930be7Sderaadt void
_kvm_err(kvm_t * kd,const char * program,const char * fmt,...)121df930be7Sderaadt _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
122df930be7Sderaadt {
123df930be7Sderaadt 	va_list ap;
124df930be7Sderaadt 
125df930be7Sderaadt 	va_start(ap, fmt);
126df930be7Sderaadt 	if (program != NULL) {
127df930be7Sderaadt 		(void)fprintf(stderr, "%s: ", program);
128df930be7Sderaadt 		(void)vfprintf(stderr, fmt, ap);
129df930be7Sderaadt 		(void)fputc('\n', stderr);
130df930be7Sderaadt 	} else
131df930be7Sderaadt 		(void)vsnprintf(kd->errbuf,
1329db2f38bSderaadt 		    sizeof(kd->errbuf), fmt, ap);
133df930be7Sderaadt 
134df930be7Sderaadt 	va_end(ap);
135df930be7Sderaadt }
136df930be7Sderaadt 
137df930be7Sderaadt void
_kvm_syserr(kvm_t * kd,const char * program,const char * fmt,...)138df930be7Sderaadt _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
139df930be7Sderaadt {
140df930be7Sderaadt 	va_list ap;
1419db2f38bSderaadt 	size_t n;
142df930be7Sderaadt 
143df930be7Sderaadt 	va_start(ap, fmt);
144df930be7Sderaadt 	if (program != NULL) {
145df930be7Sderaadt 		(void)fprintf(stderr, "%s: ", program);
146df930be7Sderaadt 		(void)vfprintf(stderr, fmt, ap);
147df930be7Sderaadt 		(void)fprintf(stderr, ": %s\n", strerror(errno));
148df930be7Sderaadt 	} else {
149551fad64Sderaadt 		char *cp = kd->errbuf;
150df930be7Sderaadt 
1519db2f38bSderaadt 		(void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap);
152df930be7Sderaadt 		n = strlen(cp);
153df930be7Sderaadt 		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
154df930be7Sderaadt 		    strerror(errno));
155df930be7Sderaadt 	}
156df930be7Sderaadt 	va_end(ap);
157df930be7Sderaadt }
158df930be7Sderaadt 
159df930be7Sderaadt void *
_kvm_malloc(kvm_t * kd,size_t n)160551fad64Sderaadt _kvm_malloc(kvm_t *kd, size_t n)
161df930be7Sderaadt {
162df930be7Sderaadt 	void *p;
163df930be7Sderaadt 
164df930be7Sderaadt 	if ((p = malloc(n)) == NULL)
16577c3406fSaaron 		_kvm_err(kd, kd->program, "%s", strerror(errno));
166df930be7Sderaadt 	return (p);
167df930be7Sderaadt }
168df930be7Sderaadt 
16953e67138Sdlg void *
_kvm_realloc(kvm_t * kd,void * p,size_t n)17053e67138Sdlg _kvm_realloc(kvm_t *kd, void *p, size_t n)
17153e67138Sdlg {
17253e67138Sdlg 	if ((p = realloc(p, n)) == NULL)
17353e67138Sdlg 		_kvm_err(kd, kd->program, "%s", strerror(errno));
17453e67138Sdlg 	return (p);
17553e67138Sdlg }
17653e67138Sdlg 
177df930be7Sderaadt static kvm_t *
_kvm_open(kvm_t * kd,const char * uf,const char * mf,const char * sf,int flag,char * errout)178551fad64Sderaadt _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf,
179551fad64Sderaadt     int flag, char *errout)
180df930be7Sderaadt {
181df930be7Sderaadt 	struct stat st;
182df930be7Sderaadt 
183df930be7Sderaadt 	kd->db = 0;
184df930be7Sderaadt 	kd->pmfd = -1;
185df930be7Sderaadt 	kd->vmfd = -1;
186df930be7Sderaadt 	kd->swfd = -1;
187df930be7Sderaadt 	kd->nlfd = -1;
1882d420eafSart 	kd->alive = 0;
189a6b19e38Sdlg 	kd->filebase = NULL;
19058b561c5Sdlg 	kd->procbase = NULL;
191df930be7Sderaadt 	kd->nbpg = getpagesize();
192df930be7Sderaadt 	kd->swapspc = 0;
193df930be7Sderaadt 	kd->argspc = 0;
194df930be7Sderaadt 	kd->argbuf = 0;
195df930be7Sderaadt 	kd->argv = 0;
19659133b9fSzhuk 	kd->envspc = 0;
19759133b9fSzhuk 	kd->envbuf = 0;
19859133b9fSzhuk 	kd->envp = 0;
199551fad64Sderaadt 	kd->vmst = NULL;
200df930be7Sderaadt 	kd->vm_page_buckets = 0;
2013fbbad10Sniklas 	kd->kcore_hdr = 0;
2025a9ac2daSderaadt 	kd->cpu_dsize = 0;
2035a9ac2daSderaadt 	kd->cpu_data = 0;
2043fbbad10Sniklas 	kd->dump_off = 0;
205df930be7Sderaadt 
2062d420eafSart 	if (flag & KVM_NO_FILES) {
2072d420eafSart 		kd->alive = 1;
2082d420eafSart 		return (kd);
2092d420eafSart 	}
2102d420eafSart 
211aea60beeSderaadt 	if (uf && strlen(uf) >= PATH_MAX) {
212df930be7Sderaadt 		_kvm_err(kd, kd->program, "exec file name too long");
213df930be7Sderaadt 		goto failed;
214df930be7Sderaadt 	}
215dc519336Sguenther 	if (flag != O_RDONLY && flag != O_WRONLY && flag != O_RDWR) {
216df930be7Sderaadt 		_kvm_err(kd, kd->program, "bad flags arg");
217df930be7Sderaadt 		goto failed;
218df930be7Sderaadt 	}
2190205f8e6Sguenther 	flag |= O_CLOEXEC;
2200205f8e6Sguenther 
22150500a5fSderaadt 	if (mf == NULL)
222df930be7Sderaadt 		mf = _PATH_MEM;
223df930be7Sderaadt 
224df69c215Sderaadt 	if ((kd->pmfd = open(mf, flag)) == -1) {
225df930be7Sderaadt 		_kvm_syserr(kd, kd->program, "%s", mf);
226df930be7Sderaadt 		goto failed;
227df930be7Sderaadt 	}
228df69c215Sderaadt 	if (fstat(kd->pmfd, &st) == -1) {
229df930be7Sderaadt 		_kvm_syserr(kd, kd->program, "%s", mf);
230df930be7Sderaadt 		goto failed;
231df930be7Sderaadt 	}
232df930be7Sderaadt 	if (S_ISCHR(st.st_mode)) {
233df930be7Sderaadt 		/*
234df930be7Sderaadt 		 * If this is a character special device, then check that
235df930be7Sderaadt 		 * it's /dev/mem.  If so, open kmem too.  (Maybe we should
236df930be7Sderaadt 		 * make it work for either /dev/mem or /dev/kmem -- in either
237df930be7Sderaadt 		 * case you're working with a live kernel.)
238df930be7Sderaadt 		 */
239df930be7Sderaadt 		if (strcmp(mf, _PATH_MEM) != 0) {	/* XXX */
240df930be7Sderaadt 			_kvm_err(kd, kd->program,
241df930be7Sderaadt 				 "%s: not physical memory device", mf);
242df930be7Sderaadt 			goto failed;
243df930be7Sderaadt 		}
244df69c215Sderaadt 		if ((kd->vmfd = open(_PATH_KMEM, flag)) == -1) {
245df930be7Sderaadt 			_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
246df930be7Sderaadt 			goto failed;
247df930be7Sderaadt 		}
2482d420eafSart 		kd->alive = 1;
249df69c215Sderaadt 		if (sf != NULL && (kd->swfd = open(sf, flag)) == -1) {
250df930be7Sderaadt 			_kvm_syserr(kd, kd->program, "%s", sf);
251df930be7Sderaadt 			goto failed;
252df930be7Sderaadt 		}
253df930be7Sderaadt 		/*
2542df3f125Sgrr 		 * Open kvm nlist database.  We only try to use
2552df3f125Sgrr 		 * the pre-built database if the namelist file name
2562df3f125Sgrr 		 * pointer is NULL.  If the database cannot or should
2572df3f125Sgrr 		 * not be opened, open the namelist argument so we
2582df3f125Sgrr 		 * revert to slow nlist() calls.
2598142bab5Smillert 		 * If no file is specified, try opening _PATH_KSYMS and
2608142bab5Smillert 		 * fall back to _PATH_UNIX.
261df930be7Sderaadt 		 */
2628142bab5Smillert 		if (kvm_dbopen(kd, uf ? uf : _PATH_UNIX) == -1 &&
2630205f8e6Sguenther 		    kvm_opennamelist(kd, uf))
264df930be7Sderaadt 			goto failed;
265df930be7Sderaadt 	} else {
266df930be7Sderaadt 		/*
267df930be7Sderaadt 		 * This is a crash dump.
2688a344d77Stodd 		 * Initialize the virtual address translation machinery,
269df930be7Sderaadt 		 * but first setup the namelist fd.
2708142bab5Smillert 		 * If no file is specified, try opening _PATH_KSYMS and
2718142bab5Smillert 		 * fall back to _PATH_UNIX.
272df930be7Sderaadt 		 */
2730205f8e6Sguenther 		if (kvm_opennamelist(kd, uf))
274df930be7Sderaadt 			goto failed;
2753fbbad10Sniklas 
2763fbbad10Sniklas 		/*
2773fbbad10Sniklas 		 * If there is no valid core header, fail silently here.
2783fbbad10Sniklas 		 * The address translations however will fail without
2793fbbad10Sniklas 		 * header. Things can be made to run by calling
2803fbbad10Sniklas 		 * kvm_dump_mkheader() before doing any translation.
2813fbbad10Sniklas 		 */
2823fbbad10Sniklas 		if (_kvm_get_header(kd) == 0) {
283df930be7Sderaadt 			if (_kvm_initvtop(kd) < 0)
284df930be7Sderaadt 				goto failed;
285df930be7Sderaadt 		}
2863fbbad10Sniklas 	}
287df930be7Sderaadt 	return (kd);
288df930be7Sderaadt failed:
289df930be7Sderaadt 	/*
290df930be7Sderaadt 	 * Copy out the error if doing sane error semantics.
291df930be7Sderaadt 	 */
292df930be7Sderaadt 	if (errout != 0)
2936e5ccbbdStedu 		(void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
294df930be7Sderaadt 	(void)kvm_close(kd);
295df930be7Sderaadt 	return (0);
296df930be7Sderaadt }
297df930be7Sderaadt 
2980205f8e6Sguenther static int
kvm_opennamelist(kvm_t * kd,const char * uf)2990205f8e6Sguenther kvm_opennamelist(kvm_t *kd, const char *uf)
3000205f8e6Sguenther {
3010205f8e6Sguenther 	int fd;
3020205f8e6Sguenther 
3030205f8e6Sguenther 	if (uf != NULL)
3040205f8e6Sguenther 		fd = open(uf, O_RDONLY | O_CLOEXEC);
3050205f8e6Sguenther 	else {
3060205f8e6Sguenther 		fd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC);
3070205f8e6Sguenther 		uf = _PATH_UNIX;
3080205f8e6Sguenther 		if (fd == -1)
3090205f8e6Sguenther 			fd = open(uf, O_RDONLY | O_CLOEXEC);
3100205f8e6Sguenther 	}
3110205f8e6Sguenther 	if (fd == -1) {
3120205f8e6Sguenther 		_kvm_syserr(kd, kd->program, "%s", uf);
3130205f8e6Sguenther 		return (-1);
3140205f8e6Sguenther 	}
3150205f8e6Sguenther 
3160205f8e6Sguenther 	kd->nlfd = fd;
3170205f8e6Sguenther 	return (0);
3180205f8e6Sguenther }
3190205f8e6Sguenther 
3205a9ac2daSderaadt /*
3215a9ac2daSderaadt  * The kernel dump file (from savecore) contains:
3225a9ac2daSderaadt  *    kcore_hdr_t kcore_hdr;
3235a9ac2daSderaadt  *    kcore_seg_t cpu_hdr;
3245a9ac2daSderaadt  *    (opaque)    cpu_data; (size is cpu_hdr.c_size)
3255a9ac2daSderaadt  *    kcore_seg_t mem_hdr;
3265a9ac2daSderaadt  *    (memory)    mem_data; (size is mem_hdr.c_size)
3275a9ac2daSderaadt  *
3285a9ac2daSderaadt  * Note: khdr is padded to khdr.c_hdrsize;
3295a9ac2daSderaadt  * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize
3305a9ac2daSderaadt  */
3313fbbad10Sniklas static int
_kvm_get_header(kvm_t * kd)332551fad64Sderaadt _kvm_get_header(kvm_t *kd)
3333fbbad10Sniklas {
3345a9ac2daSderaadt 	kcore_hdr_t	kcore_hdr;
3355a9ac2daSderaadt 	kcore_seg_t	cpu_hdr;
3365a9ac2daSderaadt 	kcore_seg_t	mem_hdr;
3375a9ac2daSderaadt 	size_t		offset;
3385a9ac2daSderaadt 	ssize_t		sz;
3393fbbad10Sniklas 
3405a9ac2daSderaadt 	/*
3415a9ac2daSderaadt 	 * Read the kcore_hdr_t
3425a9ac2daSderaadt 	 */
343b662a545Sart 	sz = _kvm_pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0);
344b662a545Sart 	if (sz != sizeof(kcore_hdr)) {
3453fbbad10Sniklas 		return (-1);
346b662a545Sart 	}
3473fbbad10Sniklas 
3483fbbad10Sniklas 	/*
3493fbbad10Sniklas 	 * Currently, we only support dump-files made by the current
3503fbbad10Sniklas 	 * architecture...
3513fbbad10Sniklas 	 */
3525a9ac2daSderaadt 	if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) ||
3535a9ac2daSderaadt 	    (CORE_GETMID(kcore_hdr) != MID_MACHINE))
3543fbbad10Sniklas 		return (-1);
3553fbbad10Sniklas 
3563fbbad10Sniklas 	/*
3573fbbad10Sniklas 	 * Currently, we only support exactly 2 segments: cpu-segment
3583fbbad10Sniklas 	 * and data-segment in exactly that order.
3593fbbad10Sniklas 	 */
3605a9ac2daSderaadt 	if (kcore_hdr.c_nseg != 2)
3613fbbad10Sniklas 		return (-1);
3623fbbad10Sniklas 
3633fbbad10Sniklas 	/*
3645a9ac2daSderaadt 	 * Save away the kcore_hdr.  All errors after this
3655a9ac2daSderaadt 	 * should do a to "goto fail" to deallocate things.
3665a9ac2daSderaadt 	 */
3675a9ac2daSderaadt 	kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr));
36863753c7aSderaadt 	if (kd->kcore_hdr == NULL)
36963753c7aSderaadt 		goto fail;
3705a9ac2daSderaadt 	memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr));
3715a9ac2daSderaadt 	offset = kcore_hdr.c_hdrsize;
3725a9ac2daSderaadt 
3735a9ac2daSderaadt 	/*
3745a9ac2daSderaadt 	 * Read the CPU segment header
3753fbbad10Sniklas 	 */
376b662a545Sart 	sz = _kvm_pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset);
377b662a545Sart 	if (sz != sizeof(cpu_hdr)) {
3785a9ac2daSderaadt 		goto fail;
379b662a545Sart 	}
380b662a545Sart 
3815a9ac2daSderaadt 	if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) ||
3825a9ac2daSderaadt 	    (CORE_GETFLAG(cpu_hdr) != CORE_CPU))
3835a9ac2daSderaadt 		goto fail;
3845a9ac2daSderaadt 	offset += kcore_hdr.c_seghdrsize;
3855a9ac2daSderaadt 
3865a9ac2daSderaadt 	/*
3875a9ac2daSderaadt 	 * Read the CPU segment DATA.
3885a9ac2daSderaadt 	 */
3895a9ac2daSderaadt 	kd->cpu_dsize = cpu_hdr.c_size;
3909db2f38bSderaadt 	kd->cpu_data = _kvm_malloc(kd, (size_t)cpu_hdr.c_size);
3915a9ac2daSderaadt 	if (kd->cpu_data == NULL)
3925a9ac2daSderaadt 		goto fail;
393b662a545Sart 
3949db2f38bSderaadt 	sz = _kvm_pread(kd, kd->pmfd, kd->cpu_data, (size_t)cpu_hdr.c_size,
3959db2f38bSderaadt 	    (off_t)offset);
3969db2f38bSderaadt 	if (sz != (size_t)cpu_hdr.c_size) {
3975a9ac2daSderaadt 		goto fail;
398b662a545Sart 	}
399b662a545Sart 
4005a9ac2daSderaadt 	offset += cpu_hdr.c_size;
4013fbbad10Sniklas 
4023fbbad10Sniklas 	/*
4033fbbad10Sniklas 	 * Read the next segment header: data segment
4043fbbad10Sniklas 	 */
405b662a545Sart 	sz = _kvm_pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset);
406b662a545Sart 	if (sz != sizeof(mem_hdr)) {
4075a9ac2daSderaadt 		goto fail;
408b662a545Sart 	}
409b662a545Sart 
4105a9ac2daSderaadt 	offset += kcore_hdr.c_seghdrsize;
4113fbbad10Sniklas 
4125a9ac2daSderaadt 	if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) ||
4135a9ac2daSderaadt 	    (CORE_GETFLAG(mem_hdr) != CORE_DATA))
4145a9ac2daSderaadt 		goto fail;
4153fbbad10Sniklas 
4163fbbad10Sniklas 	kd->dump_off = offset;
4173fbbad10Sniklas 	return (0);
4185a9ac2daSderaadt 
4195a9ac2daSderaadt fail:
4205a9ac2daSderaadt 	free(kd->kcore_hdr);
4215a9ac2daSderaadt 	kd->kcore_hdr = NULL;
4225a9ac2daSderaadt 	if (kd->cpu_data != NULL) {
4235a9ac2daSderaadt 		free(kd->cpu_data);
4245a9ac2daSderaadt 		kd->cpu_data = NULL;
4255a9ac2daSderaadt 		kd->cpu_dsize = 0;
4265a9ac2daSderaadt 	}
4275a9ac2daSderaadt 
42863753c7aSderaadt 	return (-1);
4293fbbad10Sniklas }
4303fbbad10Sniklas 
4313fbbad10Sniklas /*
4325a9ac2daSderaadt  * The format while on the dump device is: (new format)
4335a9ac2daSderaadt  *    kcore_seg_t cpu_hdr;
4345a9ac2daSderaadt  *    (opaque)    cpu_data; (size is cpu_hdr.c_size)
4355a9ac2daSderaadt  *    kcore_seg_t mem_hdr;
4365a9ac2daSderaadt  *    (memory)    mem_data; (size is mem_hdr.c_size)
4373fbbad10Sniklas  */
4383fbbad10Sniklas int
kvm_dump_mkheader(kvm_t * kd,off_t dump_off)439551fad64Sderaadt kvm_dump_mkheader(kvm_t *kd, off_t dump_off)
4403fbbad10Sniklas {
4415a9ac2daSderaadt 	kcore_seg_t	cpu_hdr;
4429db2f38bSderaadt 	int	hdr_size;
4439db2f38bSderaadt 	ssize_t sz;
4443fbbad10Sniklas 
44515f0ebb0Sderaadt 	if (kd->kcore_hdr != NULL) {
44615f0ebb0Sderaadt 	    _kvm_err(kd, kd->program, "already has a dump header");
4473fbbad10Sniklas 	    return (-1);
4483fbbad10Sniklas 	}
44915f0ebb0Sderaadt 	if (ISALIVE(kd)) {
45015f0ebb0Sderaadt 		_kvm_err(kd, kd->program, "don't use on live kernel");
4513fbbad10Sniklas 		return (-1);
4523fbbad10Sniklas 	}
4533fbbad10Sniklas 
4543fbbad10Sniklas 	/*
4555a9ac2daSderaadt 	 * Validate new format crash dump
4563fbbad10Sniklas 	 */
457b662a545Sart 	sz = _kvm_pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)dump_off);
458b662a545Sart 	if (sz != sizeof(cpu_hdr)) {
4593fbbad10Sniklas 		return (-1);
460b662a545Sart 	}
4612df3f125Sgrr 	if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC)
4622df3f125Sgrr 		|| (CORE_GETMID(cpu_hdr) != MID_MACHINE)) {
4632df3f125Sgrr 		_kvm_err(kd, 0, "invalid magic in cpu_hdr");
46463753c7aSderaadt 		return (-1);
4652df3f125Sgrr 	}
466aa7e1cedSderaadt 	hdr_size = _ALIGN(sizeof(cpu_hdr));
4675a9ac2daSderaadt 
4685a9ac2daSderaadt 	/*
4695a9ac2daSderaadt 	 * Read the CPU segment.
4705a9ac2daSderaadt 	 */
4715a9ac2daSderaadt 	kd->cpu_dsize = cpu_hdr.c_size;
4725a9ac2daSderaadt 	kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize);
4735a9ac2daSderaadt 	if (kd->cpu_data == NULL)
4745a9ac2daSderaadt 		goto fail;
475b662a545Sart 
4769db2f38bSderaadt 	sz = _kvm_pread(kd, kd->pmfd, kd->cpu_data, (size_t)cpu_hdr.c_size,
477c996d303Sderaadt 	    (off_t)dump_off+hdr_size);
4789db2f38bSderaadt 	if (sz != (ssize_t)cpu_hdr.c_size) {
479f48de1b9Skstailey 		_kvm_err(kd, 0, "invalid size in cpu_hdr");
4805a9ac2daSderaadt 		goto fail;
481f48de1b9Skstailey 	}
4825a9ac2daSderaadt 	hdr_size += kd->cpu_dsize;
4835a9ac2daSderaadt 
4845a9ac2daSderaadt 	/*
4855a9ac2daSderaadt 	 * Leave phys mem pointer at beginning of memory data
4865a9ac2daSderaadt 	 */
4875a9ac2daSderaadt 	kd->dump_off = dump_off + hdr_size;
488b662a545Sart 	errno = 0;
489b662a545Sart 	if (lseek(kd->pmfd, kd->dump_off, SEEK_SET) != kd->dump_off && errno != 0) {
490b662a545Sart 		_kvm_err(kd, 0, "invalid dump offset - lseek");
4915a9ac2daSderaadt 		goto fail;
492f48de1b9Skstailey 	}
4933fbbad10Sniklas 
4943fbbad10Sniklas 	/*
4953fbbad10Sniklas 	 * Create a kcore_hdr.
4963fbbad10Sniklas 	 */
4975a9ac2daSderaadt 	kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t));
49863753c7aSderaadt 	if (kd->kcore_hdr == NULL)
4995a9ac2daSderaadt 		goto fail;
5003fbbad10Sniklas 
501aa7e1cedSderaadt 	kd->kcore_hdr->c_hdrsize    = _ALIGN(sizeof(kcore_hdr_t));
502aa7e1cedSderaadt 	kd->kcore_hdr->c_seghdrsize = _ALIGN(sizeof(kcore_seg_t));
50315f0ebb0Sderaadt 	kd->kcore_hdr->c_nseg       = 2;
50415f0ebb0Sderaadt 	CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0);
5053fbbad10Sniklas 
5063fbbad10Sniklas 	/*
5073fbbad10Sniklas 	 * Now that we have a valid header, enable translations.
5083fbbad10Sniklas 	 */
5092df3f125Sgrr 	if (_kvm_initvtop(kd) == 0)
5102df3f125Sgrr 		/* Success */
5113fbbad10Sniklas 		return (hdr_size);
5125a9ac2daSderaadt 
5135a9ac2daSderaadt fail:
5145a9ac2daSderaadt 	free(kd->kcore_hdr);
5155a9ac2daSderaadt 	kd->kcore_hdr = NULL;
5165a9ac2daSderaadt 	if (kd->cpu_data != NULL) {
5175a9ac2daSderaadt 		free(kd->cpu_data);
5185a9ac2daSderaadt 		kd->cpu_data = NULL;
5195a9ac2daSderaadt 		kd->cpu_dsize = 0;
5205a9ac2daSderaadt 	}
5215a9ac2daSderaadt 	return (-1);
5223fbbad10Sniklas }
5233fbbad10Sniklas 
5243fbbad10Sniklas static int
clear_gap(kvm_t * kd,FILE * fp,int size)525551fad64Sderaadt clear_gap(kvm_t *kd, FILE *fp, int size)
5263fbbad10Sniklas {
5273fbbad10Sniklas 	if (size <= 0) /* XXX - < 0 should never happen */
5283fbbad10Sniklas 		return (0);
5293fbbad10Sniklas 	while (size-- > 0) {
5303fbbad10Sniklas 		if (fputc(0, fp) == EOF) {
5313fbbad10Sniklas 			_kvm_syserr(kd, kd->program, "clear_gap");
5323fbbad10Sniklas 			return (-1);
5333fbbad10Sniklas 		}
5343fbbad10Sniklas 	}
5353fbbad10Sniklas 	return (0);
5363fbbad10Sniklas }
5373fbbad10Sniklas 
5383fbbad10Sniklas /*
5393fbbad10Sniklas  * Write the dump header info to 'fp'. Note that we can't use fseek(3) here
5403fbbad10Sniklas  * because 'fp' might be a file pointer obtained by zopen().
5413fbbad10Sniklas  */
5423fbbad10Sniklas int
kvm_dump_wrtheader(kvm_t * kd,FILE * fp,int dumpsize)543551fad64Sderaadt kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize)
5443fbbad10Sniklas {
5453fbbad10Sniklas 	kcore_seg_t	seghdr;
5463fbbad10Sniklas 	long		offset;
5473fbbad10Sniklas 	int		gap;
5483fbbad10Sniklas 
5495a9ac2daSderaadt 	if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) {
5503fbbad10Sniklas 		_kvm_err(kd, kd->program, "no valid dump header(s)");
5513fbbad10Sniklas 		return (-1);
5523fbbad10Sniklas 	}
5533fbbad10Sniklas 
5543fbbad10Sniklas 	/*
5553fbbad10Sniklas 	 * Write the generic header
5563fbbad10Sniklas 	 */
5573fbbad10Sniklas 	offset = 0;
5589db2f38bSderaadt 	if (fwrite(kd->kcore_hdr, sizeof(kcore_hdr_t), 1, fp) < 1) {
5593fbbad10Sniklas 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5603fbbad10Sniklas 		return (-1);
5613fbbad10Sniklas 	}
5623fbbad10Sniklas 	offset += kd->kcore_hdr->c_hdrsize;
5633fbbad10Sniklas 	gap     = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t);
5643fbbad10Sniklas 	if (clear_gap(kd, fp, gap) == -1)
5653fbbad10Sniklas 		return (-1);
5663fbbad10Sniklas 
5673fbbad10Sniklas 	/*
5683fbbad10Sniklas 	 * Write the cpu header
5693fbbad10Sniklas 	 */
5703fbbad10Sniklas 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU);
571aa7e1cedSderaadt 	seghdr.c_size = (u_long)_ALIGN(kd->cpu_dsize);
5729db2f38bSderaadt 	if (fwrite(&seghdr, sizeof(seghdr), 1, fp) < 1) {
5733fbbad10Sniklas 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5743fbbad10Sniklas 		return (-1);
5753fbbad10Sniklas 	}
5763fbbad10Sniklas 	offset += kd->kcore_hdr->c_seghdrsize;
5773fbbad10Sniklas 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
5783fbbad10Sniklas 	if (clear_gap(kd, fp, gap) == -1)
5793fbbad10Sniklas 		return (-1);
5803fbbad10Sniklas 
5819db2f38bSderaadt 	if (fwrite(kd->cpu_data, kd->cpu_dsize, 1, fp) < 1) {
5823fbbad10Sniklas 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5833fbbad10Sniklas 		return (-1);
5843fbbad10Sniklas 	}
5853fbbad10Sniklas 	offset += seghdr.c_size;
5865a9ac2daSderaadt 	gap     = seghdr.c_size - kd->cpu_dsize;
5873fbbad10Sniklas 	if (clear_gap(kd, fp, gap) == -1)
5883fbbad10Sniklas 		return (-1);
5893fbbad10Sniklas 
5903fbbad10Sniklas 	/*
5913fbbad10Sniklas 	 * Write the actual dump data segment header
5923fbbad10Sniklas 	 */
5933fbbad10Sniklas 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA);
5943fbbad10Sniklas 	seghdr.c_size = dumpsize;
5959db2f38bSderaadt 	if (fwrite(&seghdr, sizeof(seghdr), 1, fp) < 1) {
5963fbbad10Sniklas 		_kvm_syserr(kd, kd->program, "kvm_dump_wrtheader");
5973fbbad10Sniklas 		return (-1);
5983fbbad10Sniklas 	}
5993fbbad10Sniklas 	offset += kd->kcore_hdr->c_seghdrsize;
6003fbbad10Sniklas 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
6013fbbad10Sniklas 	if (clear_gap(kd, fp, gap) == -1)
6023fbbad10Sniklas 		return (-1);
6033fbbad10Sniklas 
6043fbbad10Sniklas 	return (offset);
6053fbbad10Sniklas }
6063fbbad10Sniklas 
607df930be7Sderaadt kvm_t *
kvm_openfiles(const char * uf,const char * mf,const char * sf,int flag,char * errout)608551fad64Sderaadt kvm_openfiles(const char *uf, const char *mf, const char *sf,
6094d25048fSderaadt     int flag, char *errout)
610df930be7Sderaadt {
611551fad64Sderaadt 	kvm_t *kd;
612df930be7Sderaadt 
613df930be7Sderaadt 	if ((kd = malloc(sizeof(*kd))) == NULL) {
6146e5ccbbdStedu 		(void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
6150c876ec5Sangelos 		return (0);
616df930be7Sderaadt 	}
617df930be7Sderaadt 	kd->program = 0;
618df930be7Sderaadt 	return (_kvm_open(kd, uf, mf, sf, flag, errout));
619df930be7Sderaadt }
620df930be7Sderaadt 
621df930be7Sderaadt kvm_t *
kvm_open(const char * uf,const char * mf,const char * sf,int flag,const char * program)622551fad64Sderaadt kvm_open(const char *uf, const char *mf, const char *sf, int flag,
623551fad64Sderaadt     const char *program)
624df930be7Sderaadt {
625551fad64Sderaadt 	kvm_t *kd;
626df930be7Sderaadt 
627df930be7Sderaadt 	if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) {
628e9a8c786Smiod 		(void)fprintf(stderr, "%s: %s\n", program, strerror(errno));
6290c876ec5Sangelos 		return (0);
630df930be7Sderaadt 	}
631df930be7Sderaadt 	kd->program = program;
632df930be7Sderaadt 	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
633df930be7Sderaadt }
634df930be7Sderaadt 
635df930be7Sderaadt int
kvm_close(kvm_t * kd)636551fad64Sderaadt kvm_close(kvm_t *kd)
637df930be7Sderaadt {
638551fad64Sderaadt 	int error = 0;
639df930be7Sderaadt 
640df930be7Sderaadt 	if (kd->pmfd >= 0)
641df930be7Sderaadt 		error |= close(kd->pmfd);
642df930be7Sderaadt 	if (kd->vmfd >= 0)
643df930be7Sderaadt 		error |= close(kd->vmfd);
6442d420eafSart 	kd->alive = 0;
645df930be7Sderaadt 	if (kd->nlfd >= 0)
646df930be7Sderaadt 		error |= close(kd->nlfd);
647df930be7Sderaadt 	if (kd->swfd >= 0)
648df930be7Sderaadt 		error |= close(kd->swfd);
649df930be7Sderaadt 	if (kd->db != 0)
650df930be7Sderaadt 		error |= (kd->db->close)(kd->db);
651df930be7Sderaadt 	if (kd->vmst)
652df930be7Sderaadt 		_kvm_freevtop(kd);
6535a9ac2daSderaadt 	kd->cpu_dsize = 0;
65432ac5daaSzhuk 	free(kd->cpu_data);
65532ac5daaSzhuk 	free(kd->kcore_hdr);
656a6b19e38Sdlg 	free(kd->filebase);
65758b561c5Sdlg 	free(kd->procbase);
65832ac5daaSzhuk 	free(kd->swapspc);
65932ac5daaSzhuk 	free(kd->argspc);
66032ac5daaSzhuk 	free(kd->argbuf);
66132ac5daaSzhuk 	free(kd->argv);
66232ac5daaSzhuk 	free(kd->envspc);
66332ac5daaSzhuk 	free(kd->envbuf);
66432ac5daaSzhuk 	free(kd->envp);
66532ac5daaSzhuk 	free(kd);
666df930be7Sderaadt 
66763753c7aSderaadt 	return (error);
668df930be7Sderaadt }
669cfd60b50Sguenther DEF(kvm_close);
670df930be7Sderaadt 
671df930be7Sderaadt /*
672df930be7Sderaadt  * Set up state necessary to do queries on the kernel namelist
673df930be7Sderaadt  * data base.  If the data base is out-of-data/incompatible with
674df930be7Sderaadt  * given executable, set up things so we revert to standard nlist call.
675df930be7Sderaadt  * Only called for live kernels.  Return 0 on success, -1 on failure.
676df930be7Sderaadt  */
677df930be7Sderaadt static int
kvm_dbopen(kvm_t * kd,const char * uf)678551fad64Sderaadt kvm_dbopen(kvm_t *kd, const char *uf)
679df930be7Sderaadt {
680551fad64Sderaadt 	char dbversion[_POSIX2_LINE_MAX], kversion[_POSIX2_LINE_MAX];
6814070ddb0Snaddy 	char dbname[PATH_MAX], ufbuf[PATH_MAX];
682551fad64Sderaadt 	struct nlist nitem;
6839db2f38bSderaadt 	size_t dbversionlen;
684551fad64Sderaadt 	DBT rec;
685df930be7Sderaadt 
6864070ddb0Snaddy 	strlcpy(ufbuf, uf, sizeof(ufbuf));
6874070ddb0Snaddy 	uf = basename(ufbuf);
6888142bab5Smillert 
6898142bab5Smillert 	(void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
6908142bab5Smillert 	kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
691c3685ac3Sderaadt 	if (kd->db == NULL) {
692c3685ac3Sderaadt 		switch (errno) {
69395079511Smillert 		case ENOENT:
69495079511Smillert 			/* No kvm_bsd.db, fall back to /bsd silently */
69595079511Smillert 			break;
6960c876ec5Sangelos 		case EFTYPE:
6970c876ec5Sangelos 			_kvm_err(kd, kd->program,
6988142bab5Smillert 			    "file %s is incorrectly formatted", dbname);
6990c876ec5Sangelos 			break;
7000c876ec5Sangelos 		case EINVAL:
7010c876ec5Sangelos 			_kvm_err(kd, kd->program,
7020c876ec5Sangelos 			    "invalid argument to dbopen()");
7030c876ec5Sangelos 			break;
7040c876ec5Sangelos 		default:
705c3685ac3Sderaadt 			_kvm_err(kd, kd->program, "unknown dbopen() error");
7060c876ec5Sangelos 			break;
7070c876ec5Sangelos 		}
708df930be7Sderaadt 		return (-1);
7090c876ec5Sangelos 	}
7100c876ec5Sangelos 
711df930be7Sderaadt 	/*
712df930be7Sderaadt 	 * read version out of database
713df930be7Sderaadt 	 */
714df930be7Sderaadt 	rec.data = VRS_KEY;
715df930be7Sderaadt 	rec.size = sizeof(VRS_KEY) - 1;
716df930be7Sderaadt 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
717df930be7Sderaadt 		goto close;
718df930be7Sderaadt 	if (rec.data == 0 || rec.size > sizeof(dbversion))
719df930be7Sderaadt 		goto close;
720df930be7Sderaadt 
721cd70aa85Skettenis 	bcopy(rec.data, dbversion, rec.size);
722df930be7Sderaadt 	dbversionlen = rec.size;
7239db2f38bSderaadt 
724df930be7Sderaadt 	/*
725df930be7Sderaadt 	 * Read version string from kernel memory.
726df930be7Sderaadt 	 * Since we are dealing with a live kernel, we can call kvm_read()
727df930be7Sderaadt 	 * at this point.
728df930be7Sderaadt 	 */
729df930be7Sderaadt 	rec.data = VRS_SYM;
730df930be7Sderaadt 	rec.size = sizeof(VRS_SYM) - 1;
731df930be7Sderaadt 	if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
732df930be7Sderaadt 		goto close;
733df930be7Sderaadt 	if (rec.data == 0 || rec.size != sizeof(struct nlist))
734df930be7Sderaadt 		goto close;
735cd70aa85Skettenis 	bcopy(rec.data, &nitem, sizeof(nitem));
736df930be7Sderaadt 	if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
737df930be7Sderaadt 	    dbversionlen)
738df930be7Sderaadt 		goto close;
739df930be7Sderaadt 	/*
740df930be7Sderaadt 	 * If they match, we win - otherwise clear out kd->db so
741df930be7Sderaadt 	 * we revert to slow nlist().
742df930be7Sderaadt 	 */
743df930be7Sderaadt 	if (bcmp(dbversion, kversion, dbversionlen) == 0)
744df930be7Sderaadt 		return (0);
745df930be7Sderaadt close:
746df930be7Sderaadt 	(void)(kd->db->close)(kd->db);
747df930be7Sderaadt 	kd->db = 0;
748df930be7Sderaadt 
749df930be7Sderaadt 	return (-1);
750df930be7Sderaadt }
751df930be7Sderaadt 
752df930be7Sderaadt int
kvm_nlist(kvm_t * kd,struct nlist * nl)753551fad64Sderaadt kvm_nlist(kvm_t *kd, struct nlist *nl)
754df930be7Sderaadt {
755551fad64Sderaadt 	struct nlist *p;
756551fad64Sderaadt 	int nvalid, rv;
757df930be7Sderaadt 
758df930be7Sderaadt 	/*
759df930be7Sderaadt 	 * If we can't use the data base, revert to the
760df930be7Sderaadt 	 * slow library call.
761df930be7Sderaadt 	 */
7622df3f125Sgrr 	if (kd->db == 0) {
7632df3f125Sgrr 		rv = __fdnlist(kd->nlfd, nl);
7642df3f125Sgrr 		if (rv == -1)
7652df3f125Sgrr 			_kvm_err(kd, 0, "bad namelist");
7662df3f125Sgrr 		return (rv);
7672df3f125Sgrr 	}
768df930be7Sderaadt 
769df930be7Sderaadt 	/*
770df930be7Sderaadt 	 * We can use the kvm data base.  Go through each nlist entry
771df930be7Sderaadt 	 * and look it up with a db query.
772df930be7Sderaadt 	 */
773df930be7Sderaadt 	nvalid = 0;
774df930be7Sderaadt 	for (p = nl; p->n_name && p->n_name[0]; ++p) {
7759db2f38bSderaadt 		size_t len;
776df930be7Sderaadt 		DBT rec;
777df930be7Sderaadt 
778df930be7Sderaadt 		if ((len = strlen(p->n_name)) > 4096) {
779df930be7Sderaadt 			/* sanity */
780df930be7Sderaadt 			_kvm_err(kd, kd->program, "symbol too large");
781df930be7Sderaadt 			return (-1);
782df930be7Sderaadt 		}
783df930be7Sderaadt 		rec.data = p->n_name;
784df930be7Sderaadt 		rec.size = len;
7853fbbad10Sniklas 
7863fbbad10Sniklas 		/*
7873fbbad10Sniklas 		 * Make sure that n_value = 0 when the symbol isn't found
7883fbbad10Sniklas 		 */
7893fbbad10Sniklas 		p->n_value = 0;
7903fbbad10Sniklas 
791df930be7Sderaadt 		if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
792df930be7Sderaadt 			continue;
793df930be7Sderaadt 		if (rec.data == 0 || rec.size != sizeof(struct nlist))
794df930be7Sderaadt 			continue;
795df930be7Sderaadt 		++nvalid;
796df930be7Sderaadt 		/*
797df930be7Sderaadt 		 * Avoid alignment issues.
798df930be7Sderaadt 		 */
79950e7fddbStedu 		bcopy((char *)rec.data + offsetof(struct nlist, n_type),
800cd70aa85Skettenis 		    &p->n_type, sizeof(p->n_type));
80150e7fddbStedu 		bcopy((char *)rec.data + offsetof(struct nlist, n_value),
802cd70aa85Skettenis 		    &p->n_value, sizeof(p->n_value));
803df930be7Sderaadt 	}
804df930be7Sderaadt 	/*
805df930be7Sderaadt 	 * Return the number of entries that weren't found.
806df930be7Sderaadt 	 */
807df930be7Sderaadt 	return ((p - nl) - nvalid);
808df930be7Sderaadt }
809cfd60b50Sguenther DEF(kvm_nlist);
810df930be7Sderaadt 
811551fad64Sderaadt int
kvm_dump_inval(kvm_t * kd)812551fad64Sderaadt kvm_dump_inval(kvm_t *kd)
8133fbbad10Sniklas {
8149db2f38bSderaadt 	struct nlist	nl[2];
815fdd3f45bSmickey 	u_long		x;
816fdd3f45bSmickey 	paddr_t		pa;
8173fbbad10Sniklas 
8183fbbad10Sniklas 	if (ISALIVE(kd)) {
8193fbbad10Sniklas 		_kvm_err(kd, kd->program, "clearing dump on live kernel");
8203fbbad10Sniklas 		return (-1);
8213fbbad10Sniklas 	}
8229db2f38bSderaadt 	nl[0].n_name = "_dumpmag";
8239db2f38bSderaadt 	nl[1].n_name = NULL;
8243fbbad10Sniklas 
8259db2f38bSderaadt 	if (kvm_nlist(kd, nl) == -1) {
8263fbbad10Sniklas 		_kvm_err(kd, 0, "bad namelist");
8273fbbad10Sniklas 		return (-1);
8283fbbad10Sniklas 	}
8293ad56321Smickey 
8309db2f38bSderaadt 	if (nl[0].n_value == 0) {
8319db2f38bSderaadt 		_kvm_err(kd, nl[0].n_name, "not in name list");
8323ad56321Smickey 		return (-1);
8333ad56321Smickey 	}
8343ad56321Smickey 
8359db2f38bSderaadt 	if (_kvm_kvatop(kd, (u_long)nl[0].n_value, &pa) == 0)
8363fbbad10Sniklas 		return (-1);
8373fbbad10Sniklas 
838d183d389Sdrahn 	x = 0;
839c996d303Sderaadt 	if (_kvm_pwrite(kd, kd->pmfd, &x, sizeof(x),
840c996d303Sderaadt 	    (off_t)_kvm_pa2off(kd, pa)) != sizeof(x)) {
841b662a545Sart 		_kvm_err(kd, 0, "cannot invalidate dump");
8423fbbad10Sniklas 		return (-1);
8433fbbad10Sniklas 	}
8443fbbad10Sniklas 	return (0);
8453fbbad10Sniklas }
8463fbbad10Sniklas 
847df930be7Sderaadt ssize_t
kvm_read(kvm_t * kd,u_long kva,void * buf,size_t len)848551fad64Sderaadt kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len)
849df930be7Sderaadt {
8509db2f38bSderaadt 	ssize_t cc;
851551fad64Sderaadt 	void *cp;
852df930be7Sderaadt 
853df930be7Sderaadt 	if (ISALIVE(kd)) {
854df930be7Sderaadt 		/*
855df930be7Sderaadt 		 * We're using /dev/kmem.  Just read straight from the
856df930be7Sderaadt 		 * device and let the active kernel do the address translation.
857df930be7Sderaadt 		 */
858b662a545Sart 		cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva);
8596c1c10d3Sderaadt 		if (cc == -1) {
860b662a545Sart 			_kvm_err(kd, 0, "invalid address (%lx)", kva);
861754791b3Sangelos 			return (-1);
862df930be7Sderaadt 		} else if (cc < len)
863df930be7Sderaadt 			_kvm_err(kd, kd->program, "short read");
864df930be7Sderaadt 		return (cc);
865df930be7Sderaadt 	} else {
8665a9ac2daSderaadt 		if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) {
8673fbbad10Sniklas 			_kvm_err(kd, kd->program, "no valid dump header");
868754791b3Sangelos 			return (-1);
8693fbbad10Sniklas 		}
870df930be7Sderaadt 		cp = buf;
871df930be7Sderaadt 		while (len > 0) {
872fdd3f45bSmickey 			paddr_t	pa;
873df930be7Sderaadt 
8740c876ec5Sangelos 			/* In case of error, _kvm_kvatop sets the err string */
875df930be7Sderaadt 			cc = _kvm_kvatop(kd, kva, &pa);
876df930be7Sderaadt 			if (cc == 0)
877479d44f2Sangelos 				return (-1);
878df930be7Sderaadt 			if (cc > len)
879df930be7Sderaadt 				cc = len;
8809db2f38bSderaadt 			cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc,
881c996d303Sderaadt 			    (off_t)_kvm_pa2off(kd, pa));
8826c1c10d3Sderaadt 			if (cc == -1) {
883b662a545Sart 				_kvm_syserr(kd, 0, _PATH_MEM);
884df930be7Sderaadt 				break;
885df930be7Sderaadt 			}
886df930be7Sderaadt 			/*
887df930be7Sderaadt 			 * If kvm_kvatop returns a bogus value or our core
888df930be7Sderaadt 			 * file is truncated, we might wind up seeking beyond
889df930be7Sderaadt 			 * the end of the core file in which case the read will
890df930be7Sderaadt 			 * return 0 (EOF).
891df930be7Sderaadt 			 */
892df930be7Sderaadt 			if (cc == 0)
893df930be7Sderaadt 				break;
894df930be7Sderaadt 			cp = (char *)cp + cc;
895df930be7Sderaadt 			kva += cc;
896df930be7Sderaadt 			len -= cc;
897df930be7Sderaadt 		}
898df930be7Sderaadt 		return ((char *)cp - (char *)buf);
899df930be7Sderaadt 	}
900df930be7Sderaadt 	/* NOTREACHED */
901df930be7Sderaadt }
902cfd60b50Sguenther DEF(kvm_read);
903df930be7Sderaadt 
904df930be7Sderaadt ssize_t
kvm_write(kvm_t * kd,u_long kva,const void * buf,size_t len)905551fad64Sderaadt kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
906df930be7Sderaadt {
907551fad64Sderaadt 	int cc;
908df930be7Sderaadt 
909df930be7Sderaadt 	if (ISALIVE(kd)) {
910df930be7Sderaadt 		/*
911df930be7Sderaadt 		 * Just like kvm_read, only we write.
912df930be7Sderaadt 		 */
9139db2f38bSderaadt 		cc = _kvm_pwrite(kd, kd->vmfd, buf, len, (off_t)kva);
9146c1c10d3Sderaadt 		if (cc == -1) {
915b662a545Sart 			_kvm_err(kd, 0, "invalid address (%lx)", kva);
916754791b3Sangelos 			return (-1);
917df930be7Sderaadt 		} else if (cc < len)
918df930be7Sderaadt 			_kvm_err(kd, kd->program, "short write");
919df930be7Sderaadt 		return (cc);
920df930be7Sderaadt 	} else {
921df930be7Sderaadt 		_kvm_err(kd, kd->program,
922df930be7Sderaadt 		    "kvm_write not implemented for dead kernels");
923754791b3Sangelos 		return (-1);
924df930be7Sderaadt 	}
925df930be7Sderaadt 	/* NOTREACHED */
926df930be7Sderaadt }
927