xref: /netbsd-src/lib/libkvm/kvm.c (revision 916b154777c03001385d7553acc2d6430fb1a919)
1*916b1547Srin /*	$NetBSD: kvm.c,v 1.111 2023/08/23 14:00:11 rin Exp $	*/
2346e67f8Sthorpej 
361f28255Scgd /*-
4429f62a6Scgd  * Copyright (c) 1989, 1992, 1993
5429f62a6Scgd  *	The Regents of the University of California.  All rights reserved.
6429f62a6Scgd  *
7429f62a6Scgd  * This code is derived from software developed by the Computer Systems
8429f62a6Scgd  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
9429f62a6Scgd  * BG 91-66 and contributed to Berkeley.
1061f28255Scgd  *
1161f28255Scgd  * Redistribution and use in source and binary forms, with or without
1261f28255Scgd  * modification, are permitted provided that the following conditions
1361f28255Scgd  * are met:
1461f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1561f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1661f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1761f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1861f28255Scgd  *    documentation and/or other materials provided with the distribution.
19eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
2061f28255Scgd  *    may be used to endorse or promote products derived from this software
2161f28255Scgd  *    without specific prior written permission.
2261f28255Scgd  *
2361f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2461f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2561f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2661f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2761f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2861f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2961f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3061f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3161f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3261f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3361f28255Scgd  * SUCH DAMAGE.
3461f28255Scgd  */
3561f28255Scgd 
36b4119f6bSmikel #include <sys/cdefs.h>
3761f28255Scgd #if defined(LIBC_SCCS) && !defined(lint)
38346e67f8Sthorpej #if 0
39429f62a6Scgd static char sccsid[] = "@(#)kvm.c	8.2 (Berkeley) 2/13/94";
40346e67f8Sthorpej #else
41*916b1547Srin __RCSID("$NetBSD: kvm.c,v 1.111 2023/08/23 14:00:11 rin Exp $");
42346e67f8Sthorpej #endif
4361f28255Scgd #endif /* LIBC_SCCS and not lint */
4461f28255Scgd 
4561f28255Scgd #include <sys/param.h>
46c62a74e6Sthorpej #include <sys/lwp.h>
4761f28255Scgd #include <sys/proc.h>
4861f28255Scgd #include <sys/ioctl.h>
49429f62a6Scgd #include <sys/stat.h>
50429f62a6Scgd #include <sys/sysctl.h>
5139cda398Schristos #include <sys/mman.h>
52429f62a6Scgd 
539c2128ecSleo #include <sys/core.h>
54f9dd8b23She #include <sys/exec.h>
559c2128ecSleo #include <sys/kcore.h>
56f08d6eb0Sragge #include <sys/ksyms.h>
57962a341dSjym #include <sys/types.h>
589c2128ecSleo 
593b8ac18dSmrg #include <uvm/uvm_extern.h>
60429f62a6Scgd 
6128f3a22aSatatat #include <machine/cpu.h>
6228f3a22aSatatat 
63429f62a6Scgd #include <ctype.h>
64060eacecSyamt #include <errno.h>
6561f28255Scgd #include <fcntl.h>
6661f28255Scgd #include <limits.h>
67429f62a6Scgd #include <nlist.h>
6861f28255Scgd #include <paths.h>
69effeef0dSwiz #include <stdarg.h>
7061f28255Scgd #include <stdio.h>
71429f62a6Scgd #include <stdlib.h>
7261f28255Scgd #include <string.h>
73429f62a6Scgd #include <unistd.h>
74be74d305Sleo #include <kvm.h>
7561f28255Scgd 
76429f62a6Scgd #include "kvm_private.h"
7761f28255Scgd 
784267598fSjoerg static int	_kvm_get_header(kvm_t *);
794267598fSjoerg static kvm_t	*_kvm_open(kvm_t *, const char *, const char *,
804267598fSjoerg 		    const char *, int, char *);
816475789bSjoerg static int	clear_gap(kvm_t *, bool (*)(void *, const void *, size_t),
826475789bSjoerg 		    void *, size_t);
834267598fSjoerg static off_t	Lseek(kvm_t *, int, off_t, int);
844267598fSjoerg static ssize_t	Pread(kvm_t *, int, void *, size_t, off_t);
85ea0119dbScgd 
86429f62a6Scgd char *
kvm_geterr(kvm_t * kd)874267598fSjoerg kvm_geterr(kvm_t *kd)
8861f28255Scgd {
89429f62a6Scgd 	return (kd->errbuf);
90429f62a6Scgd }
9161f28255Scgd 
92b8c5a244Schristos const char *
kvm_getkernelname(kvm_t * kd)93b8c5a244Schristos kvm_getkernelname(kvm_t *kd)
94b8c5a244Schristos {
95b8c5a244Schristos 	return kd->kernelname;
96b8c5a244Schristos }
97b8c5a244Schristos 
98429f62a6Scgd /*
99429f62a6Scgd  * Report an error using printf style arguments.  "program" is kd->program
100429f62a6Scgd  * on hard errors, and 0 on soft errors, so that under sun error emulation,
101429f62a6Scgd  * only hard errors are printed out (otherwise, programs like gdb will
102429f62a6Scgd  * generate tons of error messages when trying to access bogus pointers).
103429f62a6Scgd  */
104429f62a6Scgd void
_kvm_err(kvm_t * kd,const char * program,const char * fmt,...)105429f62a6Scgd _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
106429f62a6Scgd {
107429f62a6Scgd 	va_list ap;
108429f62a6Scgd 
109429f62a6Scgd 	va_start(ap, fmt);
110429f62a6Scgd 	if (program != NULL) {
111429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
112429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
113429f62a6Scgd 		(void)fputc('\n', stderr);
114429f62a6Scgd 	} else
115429f62a6Scgd 		(void)vsnprintf(kd->errbuf,
1169aae5a60Sthorpej 		    sizeof(kd->errbuf), fmt, ap);
117429f62a6Scgd 
118429f62a6Scgd 	va_end(ap);
11961f28255Scgd }
120429f62a6Scgd 
121429f62a6Scgd void
_kvm_syserr(kvm_t * kd,const char * program,const char * fmt,...)122429f62a6Scgd _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
123429f62a6Scgd {
124429f62a6Scgd 	va_list ap;
1259aae5a60Sthorpej 	size_t n;
126429f62a6Scgd 
127429f62a6Scgd 	va_start(ap, fmt);
128429f62a6Scgd 	if (program != NULL) {
129429f62a6Scgd 		(void)fprintf(stderr, "%s: ", program);
130429f62a6Scgd 		(void)vfprintf(stderr, fmt, ap);
131429f62a6Scgd 		(void)fprintf(stderr, ": %s\n", strerror(errno));
13261f28255Scgd 	} else {
1330b7831a3Sperry 		char *cp = kd->errbuf;
134429f62a6Scgd 
1359aae5a60Sthorpej 		(void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap);
136429f62a6Scgd 		n = strlen(cp);
137429f62a6Scgd 		(void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
138429f62a6Scgd 		    strerror(errno));
139429f62a6Scgd 	}
140429f62a6Scgd 	va_end(ap);
141429f62a6Scgd }
142429f62a6Scgd 
143429f62a6Scgd void *
_kvm_malloc(kvm_t * kd,size_t n)1444267598fSjoerg _kvm_malloc(kvm_t *kd, size_t n)
145429f62a6Scgd {
146429f62a6Scgd 	void *p;
147429f62a6Scgd 
148429f62a6Scgd 	if ((p = malloc(n)) == NULL)
149f9d3ae0fSsommerfeld 		_kvm_err(kd, kd->program, "%s", strerror(errno));
150429f62a6Scgd 	return (p);
151429f62a6Scgd }
152429f62a6Scgd 
1539c2128ecSleo /*
1545bc2ba5cSthorpej  * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us
1555bc2ba5cSthorpej  * in the event of emergency.
1569c2128ecSleo  */
1579c2128ecSleo static off_t
Lseek(kvm_t * kd,int fd,off_t offset,int whence)1584267598fSjoerg Lseek(kvm_t *kd, int fd, off_t offset, int whence)
1599c2128ecSleo {
1609c2128ecSleo 	off_t off;
1619c2128ecSleo 
1629c2128ecSleo 	errno = 0;
1635bc2ba5cSthorpej 
1649c2128ecSleo 	if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) {
1659c2128ecSleo 		_kvm_syserr(kd, kd->program, "Lseek");
1665bc2ba5cSthorpej 		return ((off_t)-1);
1679c2128ecSleo 	}
1689c2128ecSleo 	return (off);
1699c2128ecSleo }
1709c2128ecSleo 
171a7a2d171Sad ssize_t
_kvm_pread(kvm_t * kd,int fd,void * buf,size_t size,off_t off)172a7a2d171Sad _kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off)
173a7a2d171Sad {
174a7a2d171Sad 	ptrdiff_t moff;
175a7a2d171Sad 	void *newbuf;
176a7a2d171Sad 	size_t dsize;
177a7a2d171Sad 	ssize_t rv;
178a7a2d171Sad 	off_t doff;
179a7a2d171Sad 
1806b123e26Schristos 	if (kd->dump_mem != MAP_FAILED) {
1816b123e26Schristos 		if (size + off > kd->dump_size) {
1826b123e26Schristos 			errno = EINVAL;
1836b123e26Schristos 			return -1;
1846b123e26Schristos 		}
185db3eb68fSchristos 		memcpy(buf, (char *)kd->dump_mem + (size_t)off, size);
1866b123e26Schristos 		return size;
1876b123e26Schristos 	}
1886b123e26Schristos 
189a7a2d171Sad 	/* If aligned nothing to do. */
190a7a2d171Sad 	if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) {
191a7a2d171Sad 		return pread(fd, buf, size, off);
192a7a2d171Sad 	}
193a7a2d171Sad 
194a7a2d171Sad 	/*
195a7a2d171Sad 	 * Otherwise must buffer.  We can't tolerate short reads in this
196a7a2d171Sad 	 * case (lazy bum).
197a7a2d171Sad 	 */
198a7a2d171Sad 	moff = (ptrdiff_t)off % kd->fdalign;
199a7a2d171Sad 	doff = off - moff;
200a7a2d171Sad 	dsize = moff + size + kd->fdalign - 1;
201a7a2d171Sad 	dsize -= dsize % kd->fdalign;
202a7a2d171Sad 	if (kd->iobufsz < dsize) {
203a7a2d171Sad 		newbuf = realloc(kd->iobuf, dsize);
204a7a2d171Sad 		if (newbuf == NULL) {
205a7a2d171Sad 			_kvm_syserr(kd, 0, "cannot allocate I/O buffer");
206a7a2d171Sad 			return (-1);
207a7a2d171Sad 		}
208a7a2d171Sad 		kd->iobuf = newbuf;
209a7a2d171Sad 		kd->iobufsz = dsize;
210a7a2d171Sad 	}
211a7a2d171Sad 	rv = pread(fd, kd->iobuf, dsize, doff);
2127bede9adSstacktic 	if (rv < size + moff)
213a7a2d171Sad 		return -1;
214a7a2d171Sad 	memcpy(buf, kd->iobuf + moff, size);
215a7a2d171Sad 	return size;
216a7a2d171Sad }
217a7a2d171Sad 
21839cda398Schristos static ssize_t
_kvm_pwrite(kvm_t * kd,const void * buf,size_t size,off_t off)21939cda398Schristos _kvm_pwrite(kvm_t *kd, const void *buf, size_t size, off_t off)
22039cda398Schristos {
22139cda398Schristos 	char *mem = kd->dump_mem;
22239cda398Schristos 
22339cda398Schristos 	if (size + off > kd->dump_size) {
22439cda398Schristos 		errno = EINVAL;
22539cda398Schristos 		return -1;
22639cda398Schristos 	}
227db3eb68fSchristos 	memcpy(mem + (size_t)off, buf, size);
22839cda398Schristos 	return size;
22939cda398Schristos }
23039cda398Schristos 
2315bc2ba5cSthorpej /*
2325bc2ba5cSthorpej  * Wrapper around the pread(2) system call; calls _kvm_syserr() for us
2335bc2ba5cSthorpej  * in the event of emergency.
2345bc2ba5cSthorpej  */
2359c2128ecSleo static ssize_t
Pread(kvm_t * kd,int fd,void * buf,size_t nbytes,off_t offset)2364267598fSjoerg Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset)
2379c2128ecSleo {
2389c2128ecSleo 	ssize_t rv;
2399c2128ecSleo 
2409c2128ecSleo 	errno = 0;
2419c2128ecSleo 
242a7a2d171Sad 	if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes &&
2435bc2ba5cSthorpej 	    errno != 0)
2445bc2ba5cSthorpej 		_kvm_syserr(kd, kd->program, "Pread");
2459c2128ecSleo 	return (rv);
2469c2128ecSleo }
2479c2128ecSleo 
248429f62a6Scgd static kvm_t *
_kvm_open(kvm_t * kd,const char * uf,const char * mf,const char * sf,int flag,char * errout)2494267598fSjoerg _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag,
2504267598fSjoerg     char *errout)
251429f62a6Scgd {
252429f62a6Scgd 	struct stat st;
253e79d25e2Scgd 	int ufgiven;
254429f62a6Scgd 
255429f62a6Scgd 	kd->pmfd = -1;
256c3049714Smycroft 	kd->vmfd = -1;
257429f62a6Scgd 	kd->swfd = -1;
258429f62a6Scgd 	kd->nlfd = -1;
259a9f690aeSsimonb 	kd->alive = KVM_ALIVE_DEAD;
2600213791dSchristos 	kd->procbase = NULL;
2610213791dSchristos 	kd->procbase_len = 0;
2620213791dSchristos 	kd->procbase2 = NULL;
2630213791dSchristos 	kd->procbase2_len = 0;
2640213791dSchristos 	kd->lwpbase = NULL;
2650213791dSchristos 	kd->lwpbase_len = 0;
266b707f8aaSmycroft 	kd->nbpg = getpagesize();
2670213791dSchristos 	kd->swapspc = NULL;
2680213791dSchristos 	kd->argspc = NULL;
2690213791dSchristos 	kd->argspc_len = 0;
2700213791dSchristos 	kd->argbuf = NULL;
2710213791dSchristos 	kd->argv = NULL;
2720213791dSchristos 	kd->vmst = NULL;
2730213791dSchristos 	kd->vm_page_buckets = NULL;
2740213791dSchristos 	kd->kcore_hdr = NULL;
27582118b75Sgwr 	kd->cpu_dsize = 0;
2760213791dSchristos 	kd->cpu_data = NULL;
2779c2128ecSleo 	kd->dump_off = 0;
278a7a2d171Sad 	kd->fdalign = 1;
279a7a2d171Sad 	kd->iobuf = NULL;
280a7a2d171Sad 	kd->iobufsz = 0;
28119db2277Smrg 	kd->errbuf[0] = '\0';
28239cda398Schristos 	kd->dump_mem = MAP_FAILED;
28339cda398Schristos 	kd->dump_size = 0;
284429f62a6Scgd 
285a9f690aeSsimonb 	if (flag & KVM_NO_FILES) {
286a9f690aeSsimonb 		kd->alive = KVM_ALIVE_SYSCTL;
287a9f690aeSsimonb 		return(kd);
288a9f690aeSsimonb 	}
289a9f690aeSsimonb 
290ab2c3b01Sgwr 	/*
291ab2c3b01Sgwr 	 * Call the MD open hook.  This sets:
292104ea677Schristos 	 *	min_uva, max_uva
293ab2c3b01Sgwr 	 */
294ab2c3b01Sgwr 	if (_kvm_mdopen(kd)) {
295ab2c3b01Sgwr 		_kvm_err(kd, kd->program, "md init failed");
296ab2c3b01Sgwr 		goto failed;
297ab2c3b01Sgwr 	}
298ab2c3b01Sgwr 
299e79d25e2Scgd 	ufgiven = (uf != NULL);
30028f3a22aSatatat 	if (!ufgiven) {
30128f3a22aSatatat #ifdef CPU_BOOTED_KERNEL
30228f3a22aSatatat 		/* 130 is 128 + '/' + '\0' */
30328f3a22aSatatat 		static char booted_kernel[130];
30428f3a22aSatatat 		int mib[2], rc;
30528f3a22aSatatat 		size_t len;
30628f3a22aSatatat 
30728f3a22aSatatat 		mib[0] = CTL_MACHDEP;
30828f3a22aSatatat 		mib[1] = CPU_BOOTED_KERNEL;
30928f3a22aSatatat 		booted_kernel[0] = '/';
31028f3a22aSatatat 		booted_kernel[1] = '\0';
31128f3a22aSatatat 		len = sizeof(booted_kernel) - 2;
31228f3a22aSatatat 		rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0);
31328f3a22aSatatat 		booted_kernel[sizeof(booted_kernel) - 1] = '\0';
31428f3a22aSatatat 		uf = (booted_kernel[1] == '/') ?
31528f3a22aSatatat 		    &booted_kernel[1] : &booted_kernel[0];
31628f3a22aSatatat 		if (rc != -1)
31728f3a22aSatatat 			rc = stat(uf, &st);
31828f3a22aSatatat 		if (rc != -1 && !S_ISREG(st.st_mode))
31928f3a22aSatatat 			rc = -1;
32028f3a22aSatatat 		if (rc == -1)
32128f3a22aSatatat #endif /* CPU_BOOTED_KERNEL */
322429f62a6Scgd 			uf = _PATH_UNIX;
32328f3a22aSatatat 	}
324429f62a6Scgd 	else if (strlen(uf) >= MAXPATHLEN) {
325429f62a6Scgd 		_kvm_err(kd, kd->program, "exec file name too long");
32661f28255Scgd 		goto failed;
32761f28255Scgd 	}
328429f62a6Scgd 	if (flag & ~O_RDWR) {
329429f62a6Scgd 		_kvm_err(kd, kd->program, "bad flags arg");
330429f62a6Scgd 		goto failed;
331429f62a6Scgd 	}
332429f62a6Scgd 	if (mf == 0)
333429f62a6Scgd 		mf = _PATH_MEM;
334429f62a6Scgd 	if (sf == 0)
335429f62a6Scgd 		sf = _PATH_DRUM;
336429f62a6Scgd 
3378a61809cSapb 	/*
3388a61809cSapb 	 * Open the kernel namelist.  If /dev/ksyms doesn't
3398a61809cSapb 	 * exist, open the current kernel.
3408a61809cSapb 	 */
3418a61809cSapb 	if (ufgiven == 0)
3425305df22Schristos 		kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0);
3438a61809cSapb 	if (kd->nlfd < 0) {
3445305df22Schristos 		if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
3458a61809cSapb 			_kvm_syserr(kd, kd->program, "%s", uf);
3468a61809cSapb 			goto failed;
3478a61809cSapb 		}
348b8c5a244Schristos 		strlcpy(kd->kernelname, uf, sizeof(kd->kernelname));
3498a61809cSapb 	} else {
350b8c5a244Schristos 		strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname));
3518a61809cSapb 	}
3528a61809cSapb 
3535305df22Schristos 	if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) {
354429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
355429f62a6Scgd 		goto failed;
356429f62a6Scgd 	}
357429f62a6Scgd 	if (fstat(kd->pmfd, &st) < 0) {
358429f62a6Scgd 		_kvm_syserr(kd, kd->program, "%s", mf);
359429f62a6Scgd 		goto failed;
360429f62a6Scgd 	}
361a7a2d171Sad 	if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) {
36261f28255Scgd 		/*
363a7a2d171Sad 		 * If this is /dev/mem, open kmem too.  (Maybe we should
364429f62a6Scgd 		 * make it work for either /dev/mem or /dev/kmem -- in either
365429f62a6Scgd 		 * case you're working with a live kernel.)
36661f28255Scgd 		 */
3675305df22Schristos 		if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) {
368429f62a6Scgd 			_kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
369429f62a6Scgd 			goto failed;
370429f62a6Scgd 		}
371a9f690aeSsimonb 		kd->alive = KVM_ALIVE_FILES;
3725305df22Schristos 		if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) {
3736cae8c8dSyamt 			if (errno != ENXIO) {
374429f62a6Scgd 				_kvm_syserr(kd, kd->program, "%s", sf);
375429f62a6Scgd 				goto failed;
376429f62a6Scgd 			}
3776cae8c8dSyamt 			/* swap is not configured?  not fatal */
3786cae8c8dSyamt 		}
379429f62a6Scgd 	} else {
38029a37a72Schs 		if (S_ISCHR(st.st_mode)) {
38129a37a72Schs 			kd->fdalign = DEV_BSIZE;
38229a37a72Schs 		} else {
38329a37a72Schs 			kd->fdalign = 1;
38429a37a72Schs 		}
38529a37a72Schs 
386429f62a6Scgd 		/*
387429f62a6Scgd 		 * This is a crash dump.
3888a61809cSapb 		 * Initialize the virtual address translation machinery.
3898a61809cSapb 		 *
3909c2128ecSleo 		 * If there is no valid core header, fail silently here.
3919c2128ecSleo 		 * The address translations however will fail without
3929c2128ecSleo 		 * header. Things can be made to run by calling
3939c2128ecSleo 		 * kvm_dump_mkheader() before doing any translation.
3949c2128ecSleo 		 */
3959c2128ecSleo 		if (_kvm_get_header(kd) == 0) {
396429f62a6Scgd 			if (_kvm_initvtop(kd) < 0)
397429f62a6Scgd 				goto failed;
398429f62a6Scgd 		}
39939cda398Schristos 		kd->dump_size = (size_t)st.st_size;
40039cda398Schristos 		kd->dump_mem = mmap(NULL, kd->dump_size, PROT_READ|PROT_WRITE,
40139cda398Schristos 		    MAP_FILE|MAP_PRIVATE, kd->pmfd, 0);
4029c2128ecSleo 	}
403429f62a6Scgd 	return (kd);
40461f28255Scgd failed:
405429f62a6Scgd 	/*
406429f62a6Scgd 	 * Copy out the error if doing sane error semantics.
407429f62a6Scgd 	 */
408429f62a6Scgd 	if (errout != 0)
409d8cb639eSitojun 		(void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
410429f62a6Scgd 	(void)kvm_close(kd);
411429f62a6Scgd 	return (0);
41261f28255Scgd }
41361f28255Scgd 
41482118b75Sgwr /*
41582118b75Sgwr  * The kernel dump file (from savecore) contains:
41682118b75Sgwr  *    kcore_hdr_t kcore_hdr;
41782118b75Sgwr  *    kcore_seg_t cpu_hdr;
41882118b75Sgwr  *    (opaque)    cpu_data; (size is cpu_hdr.c_size)
41982118b75Sgwr  *	  kcore_seg_t mem_hdr;
42082118b75Sgwr  *    (memory)    mem_data; (size is mem_hdr.c_size)
42182118b75Sgwr  *
42282118b75Sgwr  * Note: khdr is padded to khdr.c_hdrsize;
42382118b75Sgwr  * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize
42482118b75Sgwr  */
4259c2128ecSleo static int
_kvm_get_header(kvm_t * kd)4264267598fSjoerg _kvm_get_header(kvm_t *kd)
4279c2128ecSleo {
42882118b75Sgwr 	kcore_hdr_t	kcore_hdr;
42982118b75Sgwr 	kcore_seg_t	cpu_hdr;
43082118b75Sgwr 	kcore_seg_t	mem_hdr;
43182118b75Sgwr 	size_t		offset;
43282118b75Sgwr 	ssize_t		sz;
4339c2128ecSleo 
43482118b75Sgwr 	/*
43582118b75Sgwr 	 * Read the kcore_hdr_t
43682118b75Sgwr 	 */
4375bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0);
43882118b75Sgwr 	if (sz != sizeof(kcore_hdr))
4399c2128ecSleo 		return (-1);
4409c2128ecSleo 
4419c2128ecSleo 	/*
4429c2128ecSleo 	 * Currently, we only support dump-files made by the current
4439c2128ecSleo 	 * architecture...
4449c2128ecSleo 	 */
44582118b75Sgwr 	if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) ||
44682118b75Sgwr 	    (CORE_GETMID(kcore_hdr) != MID_MACHINE))
4479c2128ecSleo 		return (-1);
4489c2128ecSleo 
4499c2128ecSleo 	/*
4509c2128ecSleo 	 * Currently, we only support exactly 2 segments: cpu-segment
4519c2128ecSleo 	 * and data-segment in exactly that order.
4529c2128ecSleo 	 */
45382118b75Sgwr 	if (kcore_hdr.c_nseg != 2)
4549c2128ecSleo 		return (-1);
4559c2128ecSleo 
4569c2128ecSleo 	/*
45782118b75Sgwr 	 * Save away the kcore_hdr.  All errors after this
45882118b75Sgwr 	 * should do a to "goto fail" to deallocate things.
45982118b75Sgwr 	 */
46082118b75Sgwr 	kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr));
46182118b75Sgwr 	memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr));
46282118b75Sgwr 	offset = kcore_hdr.c_hdrsize;
46382118b75Sgwr 
46482118b75Sgwr 	/*
46582118b75Sgwr 	 * Read the CPU segment header
4669c2128ecSleo 	 */
4675bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset);
46882118b75Sgwr 	if (sz != sizeof(cpu_hdr))
46982118b75Sgwr 		goto fail;
47082118b75Sgwr 	if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) ||
47182118b75Sgwr 	    (CORE_GETFLAG(cpu_hdr) != CORE_CPU))
47282118b75Sgwr 		goto fail;
47382118b75Sgwr 	offset += kcore_hdr.c_seghdrsize;
47482118b75Sgwr 
47582118b75Sgwr 	/*
47682118b75Sgwr 	 * Read the CPU segment DATA.
47782118b75Sgwr 	 */
47882118b75Sgwr 	kd->cpu_dsize = cpu_hdr.c_size;
47982118b75Sgwr 	kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size);
48082118b75Sgwr 	if (kd->cpu_data == NULL)
48182118b75Sgwr 		goto fail;
4825bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset);
48382118b75Sgwr 	if (sz != cpu_hdr.c_size)
48482118b75Sgwr 		goto fail;
48582118b75Sgwr 	offset += cpu_hdr.c_size;
4869c2128ecSleo 
4879c2128ecSleo 	/*
4889c2128ecSleo 	 * Read the next segment header: data segment
4899c2128ecSleo 	 */
4905bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset);
49182118b75Sgwr 	if (sz != sizeof(mem_hdr))
49282118b75Sgwr 		goto fail;
49382118b75Sgwr 	offset += kcore_hdr.c_seghdrsize;
4949c2128ecSleo 
49582118b75Sgwr 	if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) ||
49682118b75Sgwr 	    (CORE_GETFLAG(mem_hdr) != CORE_DATA))
49782118b75Sgwr 		goto fail;
4989c2128ecSleo 
4999c2128ecSleo 	kd->dump_off = offset;
5009c2128ecSleo 	return (0);
50182118b75Sgwr 
50282118b75Sgwr fail:
50382118b75Sgwr 	if (kd->kcore_hdr != NULL) {
50482118b75Sgwr 		free(kd->kcore_hdr);
50582118b75Sgwr 		kd->kcore_hdr = NULL;
50682118b75Sgwr 	}
50782118b75Sgwr 	if (kd->cpu_data != NULL) {
50882118b75Sgwr 		free(kd->cpu_data);
50982118b75Sgwr 		kd->cpu_data = NULL;
51082118b75Sgwr 		kd->cpu_dsize = 0;
51182118b75Sgwr 	}
512395c20eaSmrg 	return (-1);
5139c2128ecSleo }
5149c2128ecSleo 
5159c2128ecSleo /*
51682118b75Sgwr  * The format while on the dump device is: (new format)
51782118b75Sgwr  *	kcore_seg_t cpu_hdr;
51882118b75Sgwr  *	(opaque)    cpu_data; (size is cpu_hdr.c_size)
51982118b75Sgwr  *	kcore_seg_t mem_hdr;
52082118b75Sgwr  *	(memory)    mem_data; (size is mem_hdr.c_size)
5219c2128ecSleo  */
5229c2128ecSleo int
kvm_dump_mkheader(kvm_t * kd,off_t dump_off)5234267598fSjoerg kvm_dump_mkheader(kvm_t *kd, off_t dump_off)
5249c2128ecSleo {
52582118b75Sgwr 	kcore_seg_t	cpu_hdr;
5269aae5a60Sthorpej 	size_t hdr_size;
5279aae5a60Sthorpej 	ssize_t sz;
5289c2128ecSleo 
529be74d305Sleo 	if (kd->kcore_hdr != NULL) {
530be74d305Sleo 	    _kvm_err(kd, kd->program, "already has a dump header");
5319c2128ecSleo 	    return (-1);
5329c2128ecSleo 	}
533be74d305Sleo 	if (ISALIVE(kd)) {
534be74d305Sleo 		_kvm_err(kd, kd->program, "don't use on live kernel");
5359c2128ecSleo 		return (-1);
5369c2128ecSleo 	}
5379c2128ecSleo 
5389c2128ecSleo 	/*
53982118b75Sgwr 	 * Validate new format crash dump
5409c2128ecSleo 	 */
5415bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off);
54281d46640Smartin 	if (sz != sizeof(cpu_hdr)) {
54319cbd680Smrg 		if (sz == -1)
54419cbd680Smrg 			_kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64
54519cbd680Smrg 			    " for cpu_hdr failed: %s", sizeof(cpu_hdr),
54619cbd680Smrg 			    dump_off, strerror(errno));
54719cbd680Smrg 		else
54881d46640Smartin 			_kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64
54981d46640Smartin 			    " for cpu_hdr instead of requested %zu",
55081d46640Smartin 			    sz, dump_off, sizeof(cpu_hdr));
5519c2128ecSleo 		return (-1);
55281d46640Smartin 	}
553cca068a1Sleo 	if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC)
554cca068a1Sleo 		|| (CORE_GETMID(cpu_hdr) != MID_MACHINE)) {
555cca068a1Sleo 		_kvm_err(kd, 0, "invalid magic in cpu_hdr");
556fa721903Sleo 		return (0);
557cca068a1Sleo 	}
55882118b75Sgwr 	hdr_size = ALIGN(sizeof(cpu_hdr));
55982118b75Sgwr 
56082118b75Sgwr 	/*
56182118b75Sgwr 	 * Read the CPU segment.
56282118b75Sgwr 	 */
56382118b75Sgwr 	kd->cpu_dsize = cpu_hdr.c_size;
56482118b75Sgwr 	kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize);
56581d46640Smartin 	if (kd->cpu_data == NULL) {
56681d46640Smartin 		_kvm_err(kd, kd->program, "no cpu_data");
56782118b75Sgwr 		goto fail;
56881d46640Smartin 	}
5695bc2ba5cSthorpej 	sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size,
5705bc2ba5cSthorpej 	    dump_off + hdr_size);
57181d46640Smartin 	if (sz != cpu_hdr.c_size) {
57281d46640Smartin 		_kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %"PRIu32,
57381d46640Smartin 		    sz, cpu_hdr.c_size);
57482118b75Sgwr 		goto fail;
57581d46640Smartin 	}
57682118b75Sgwr 	hdr_size += kd->cpu_dsize;
57782118b75Sgwr 
57882118b75Sgwr 	/*
57982118b75Sgwr 	 * Leave phys mem pointer at beginning of memory data
58082118b75Sgwr 	 */
58182118b75Sgwr 	kd->dump_off = dump_off + hdr_size;
58281d46640Smartin 	if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) {
58381d46640Smartin 		_kvm_err(kd, kd->program, "failed to seek to %" PRId64,
58481d46640Smartin 		    (int64_t)kd->dump_off);
58582118b75Sgwr 		goto fail;
58681d46640Smartin 	}
5879c2128ecSleo 
5889c2128ecSleo 	/*
5899c2128ecSleo 	 * Create a kcore_hdr.
5909c2128ecSleo 	 */
59182118b75Sgwr 	kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t));
59281d46640Smartin 	if (kd->kcore_hdr == NULL) {
59381d46640Smartin 		_kvm_err(kd, kd->program, "failed to allocate header");
59482118b75Sgwr 		goto fail;
59581d46640Smartin 	}
5969c2128ecSleo 
597be74d305Sleo 	kd->kcore_hdr->c_hdrsize    = ALIGN(sizeof(kcore_hdr_t));
598be74d305Sleo 	kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t));
599be74d305Sleo 	kd->kcore_hdr->c_nseg       = 2;
600be74d305Sleo 	CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0);
6019c2128ecSleo 
6029c2128ecSleo 	/*
6039c2128ecSleo 	 * Now that we have a valid header, enable translations.
6049c2128ecSleo 	 */
605dbaf74aeSpk 	if (_kvm_initvtop(kd) == 0)
606dbaf74aeSpk 		/* Success */
6079c2128ecSleo 		return (hdr_size);
60882118b75Sgwr 
60982118b75Sgwr fail:
61082118b75Sgwr 	if (kd->kcore_hdr != NULL) {
61182118b75Sgwr 		free(kd->kcore_hdr);
61282118b75Sgwr 		kd->kcore_hdr = NULL;
61382118b75Sgwr 	}
61482118b75Sgwr 	if (kd->cpu_data != NULL) {
61582118b75Sgwr 		free(kd->cpu_data);
61682118b75Sgwr 		kd->cpu_data = NULL;
61782118b75Sgwr 		kd->cpu_dsize = 0;
61882118b75Sgwr 	}
61982118b75Sgwr 	return (-1);
6209c2128ecSleo }
6219c2128ecSleo 
6229c2128ecSleo static int
clear_gap(kvm_t * kd,bool (* write_buf)(void *,const void *,size_t),void * cookie,size_t size)6236475789bSjoerg clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t),
6246475789bSjoerg     void *cookie, size_t size)
6259c2128ecSleo {
6266475789bSjoerg 	char buf[1024];
6276475789bSjoerg 	size_t len;
6286475789bSjoerg 
6296475789bSjoerg 	(void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size);
6306475789bSjoerg 
6316475789bSjoerg 	while (size > 0) {
6326475789bSjoerg 		len = size > sizeof(buf) ? sizeof(buf) : size;
6336475789bSjoerg 		if (!(*write_buf)(cookie, buf, len)) {
6349c2128ecSleo 			_kvm_syserr(kd, kd->program, "clear_gap");
6356475789bSjoerg 			return -1;
6369c2128ecSleo 		}
6376475789bSjoerg 		size -= len;
6389c2128ecSleo 	}
6396475789bSjoerg 
6406475789bSjoerg 	return 0;
6419c2128ecSleo }
6429c2128ecSleo 
6439c2128ecSleo /*
6446475789bSjoerg  * Write the dump header by calling write_buf with cookie as first argument.
6459c2128ecSleo  */
6469c2128ecSleo int
kvm_dump_header(kvm_t * kd,bool (* write_buf)(void *,const void *,size_t),void * cookie,int dumpsize)6476475789bSjoerg kvm_dump_header(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t),
6486475789bSjoerg     void *cookie, int dumpsize)
6499c2128ecSleo {
6509c2128ecSleo 	kcore_seg_t	seghdr;
6519c2128ecSleo 	long		offset;
6526475789bSjoerg 	size_t		gap;
6539c2128ecSleo 
65482118b75Sgwr 	if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) {
6559c2128ecSleo 		_kvm_err(kd, kd->program, "no valid dump header(s)");
6569c2128ecSleo 		return (-1);
6579c2128ecSleo 	}
6589c2128ecSleo 
6599c2128ecSleo 	/*
6609c2128ecSleo 	 * Write the generic header
6619c2128ecSleo 	 */
6629c2128ecSleo 	offset = 0;
6636475789bSjoerg 	if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) {
6646475789bSjoerg 		_kvm_syserr(kd, kd->program, "kvm_dump_header");
6659c2128ecSleo 		return (-1);
6669c2128ecSleo 	}
6679c2128ecSleo 	offset += kd->kcore_hdr->c_hdrsize;
6689c2128ecSleo 	gap     = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t);
6696475789bSjoerg 	if (clear_gap(kd, write_buf, cookie, gap) == -1)
6709c2128ecSleo 		return (-1);
6719c2128ecSleo 
6729c2128ecSleo 	/*
673d20841bbSwiz 	 * Write the CPU header
6749c2128ecSleo 	 */
6759c2128ecSleo 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU);
67682118b75Sgwr 	seghdr.c_size = ALIGN(kd->cpu_dsize);
6776475789bSjoerg 	if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) {
6786475789bSjoerg 		_kvm_syserr(kd, kd->program, "kvm_dump_header");
6799c2128ecSleo 		return (-1);
6809c2128ecSleo 	}
6819c2128ecSleo 	offset += kd->kcore_hdr->c_seghdrsize;
6829c2128ecSleo 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
6836475789bSjoerg 	if (clear_gap(kd, write_buf, cookie, gap) == -1)
6849c2128ecSleo 		return (-1);
6859c2128ecSleo 
6866475789bSjoerg 	if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) {
6876475789bSjoerg 		_kvm_syserr(kd, kd->program, "kvm_dump_header");
6889c2128ecSleo 		return (-1);
6899c2128ecSleo 	}
6909c2128ecSleo 	offset += seghdr.c_size;
69182118b75Sgwr 	gap     = seghdr.c_size - kd->cpu_dsize;
692b9d83a24Sjoerg 	if (clear_gap(kd, write_buf, cookie, gap) == -1)
6939c2128ecSleo 		return (-1);
6949c2128ecSleo 
6959c2128ecSleo 	/*
6969c2128ecSleo 	 * Write the actual dump data segment header
6979c2128ecSleo 	 */
6989c2128ecSleo 	CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA);
6999c2128ecSleo 	seghdr.c_size = dumpsize;
7006475789bSjoerg 	if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) {
7016475789bSjoerg 		_kvm_syserr(kd, kd->program, "kvm_dump_header");
7029c2128ecSleo 		return (-1);
7039c2128ecSleo 	}
7049c2128ecSleo 	offset += kd->kcore_hdr->c_seghdrsize;
7059c2128ecSleo 	gap     = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
7066475789bSjoerg 	if (clear_gap(kd, write_buf, cookie, gap) == -1)
7079c2128ecSleo 		return (-1);
7089c2128ecSleo 
709cc7ffa0dSchristos 	return (int)offset;
7109c2128ecSleo }
7119c2128ecSleo 
7126475789bSjoerg static bool
kvm_dump_header_stdio(void * cookie,const void * buf,size_t len)7136475789bSjoerg kvm_dump_header_stdio(void *cookie, const void *buf, size_t len)
7146475789bSjoerg {
7156475789bSjoerg 	return fwrite(buf, len, 1, (FILE *)cookie) == 1;
7166475789bSjoerg }
7176475789bSjoerg 
7186475789bSjoerg int
kvm_dump_wrtheader(kvm_t * kd,FILE * fp,int dumpsize)7196475789bSjoerg kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize)
7206475789bSjoerg {
7216475789bSjoerg 	return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize);
7226475789bSjoerg }
7236475789bSjoerg 
724429f62a6Scgd kvm_t *
kvm_openfiles(const char * uf,const char * mf,const char * sf,int flag,char * errout)7254267598fSjoerg kvm_openfiles(const char *uf, const char *mf, const char *sf,
7264267598fSjoerg     int flag, char *errout)
72761f28255Scgd {
7280b7831a3Sperry 	kvm_t *kd;
729429f62a6Scgd 
730429f62a6Scgd 	if ((kd = malloc(sizeof(*kd))) == NULL) {
731d8cb639eSitojun 		(void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
732429f62a6Scgd 		return (0);
733429f62a6Scgd 	}
734429f62a6Scgd 	kd->program = 0;
735429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, errout));
736429f62a6Scgd }
737429f62a6Scgd 
738429f62a6Scgd kvm_t *
kvm_open(const char * uf,const char * mf,const char * sf,int flag,const char * program)7394267598fSjoerg kvm_open(const char *uf, const char *mf, const char *sf, int flag,
7404267598fSjoerg     const char *program)
741429f62a6Scgd {
7420b7831a3Sperry 	kvm_t *kd;
743429f62a6Scgd 
74417c25014Schristos 	if ((kd = malloc(sizeof(*kd))) == NULL) {
74517c25014Schristos 		(void)fprintf(stderr, "%s: %s\n",
74617c25014Schristos 		    program ? program : getprogname(), strerror(errno));
747429f62a6Scgd 		return (0);
748429f62a6Scgd 	}
749429f62a6Scgd 	kd->program = program;
750429f62a6Scgd 	return (_kvm_open(kd, uf, mf, sf, flag, NULL));
751429f62a6Scgd }
752429f62a6Scgd 
753429f62a6Scgd int
kvm_close(kvm_t * kd)7544267598fSjoerg kvm_close(kvm_t *kd)
755429f62a6Scgd {
7560b7831a3Sperry 	int error = 0;
757429f62a6Scgd 
758429f62a6Scgd 	if (kd->pmfd >= 0)
759429f62a6Scgd 		error |= close(kd->pmfd);
760429f62a6Scgd 	if (kd->vmfd >= 0)
761429f62a6Scgd 		error |= close(kd->vmfd);
762429f62a6Scgd 	if (kd->nlfd >= 0)
763429f62a6Scgd 		error |= close(kd->nlfd);
764429f62a6Scgd 	if (kd->swfd >= 0)
765429f62a6Scgd 		error |= close(kd->swfd);
766429f62a6Scgd 	if (kd->vmst)
767429f62a6Scgd 		_kvm_freevtop(kd);
76882118b75Sgwr 	kd->cpu_dsize = 0;
76982118b75Sgwr 	if (kd->cpu_data != NULL)
770a7a2d171Sad 		free(kd->cpu_data);
7719c2128ecSleo 	if (kd->kcore_hdr != NULL)
772a7a2d171Sad 		free(kd->kcore_hdr);
773429f62a6Scgd 	if (kd->procbase != 0)
774a7a2d171Sad 		free(kd->procbase);
775a9f690aeSsimonb 	if (kd->procbase2 != 0)
776a7a2d171Sad 		free(kd->procbase2);
777c62a74e6Sthorpej 	if (kd->lwpbase != 0)
778a7a2d171Sad 		free(kd->lwpbase);
779b707f8aaSmycroft 	if (kd->swapspc != 0)
780a7a2d171Sad 		free(kd->swapspc);
781b707f8aaSmycroft 	if (kd->argspc != 0)
782a7a2d171Sad 		free(kd->argspc);
7836506fa2bSmycroft 	if (kd->argbuf != 0)
784a7a2d171Sad 		free(kd->argbuf);
785429f62a6Scgd 	if (kd->argv != 0)
786a7a2d171Sad 		free(kd->argv);
787a7a2d171Sad 	if (kd->iobuf != 0)
788a7a2d171Sad 		free(kd->iobuf);
78939cda398Schristos 	if (kd->dump_mem != MAP_FAILED)
79039cda398Schristos 		munmap(kd->dump_mem, kd->dump_size);
791a7a2d171Sad 	free(kd);
79261f28255Scgd 
79301cef2d6Sdholland 	return (error);
79461f28255Scgd }
79561f28255Scgd 
7965089c413Scgd int
kvm_nlist(kvm_t * kd,struct nlist * nl)7974267598fSjoerg kvm_nlist(kvm_t *kd, struct nlist *nl)
7985089c413Scgd {
79926bc6e1cSmaxv 	int rv;
8005089c413Scgd 
801429f62a6Scgd 	/*
802f08d6eb0Sragge 	 * Call the nlist(3) routines to retrieve the given namelist.
803429f62a6Scgd 	 */
80426bc6e1cSmaxv 	rv = __fdnlist(kd->nlfd, nl);
805b9d0c518Scube 
8062af2958aScgd 	if (rv == -1)
8072af2958aScgd 		_kvm_err(kd, 0, "bad namelist");
808b9d0c518Scube 
8092af2958aScgd 	return (rv);
8102af2958aScgd }
8115089c413Scgd 
8124267598fSjoerg int
kvm_dump_inval(kvm_t * kd)8134267598fSjoerg kvm_dump_inval(kvm_t *kd)
8149c2128ecSleo {
8159aae5a60Sthorpej 	struct nlist	nl[2];
816962a341dSjym 	paddr_t		pa;
817eba222dfSad 	size_t		dsize;
818eba222dfSad 	off_t		doff;
819eba222dfSad 	void		*newbuf;
8209c2128ecSleo 
8219c2128ecSleo 	if (ISALIVE(kd)) {
8229c2128ecSleo 		_kvm_err(kd, kd->program, "clearing dump on live kernel");
8239c2128ecSleo 		return (-1);
8249c2128ecSleo 	}
8259aae5a60Sthorpej 	nl[0].n_name = "_dumpmag";
8269aae5a60Sthorpej 	nl[1].n_name = NULL;
8279c2128ecSleo 
8289aae5a60Sthorpej 	if (kvm_nlist(kd, nl) == -1) {
8299c2128ecSleo 		_kvm_err(kd, 0, "bad namelist");
8309c2128ecSleo 		return (-1);
8319c2128ecSleo 	}
832962a341dSjym 	if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0)
8339c2128ecSleo 		return (-1);
8349c2128ecSleo 
8359c2128ecSleo 	errno = 0;
836eba222dfSad 	dsize = MAX(kd->fdalign, sizeof(u_long));
837eba222dfSad 	if (kd->iobufsz < dsize) {
838eba222dfSad 		newbuf = realloc(kd->iobuf, dsize);
839eba222dfSad 		if (newbuf == NULL) {
840eba222dfSad 			_kvm_syserr(kd, 0, "cannot allocate I/O buffer");
841eba222dfSad 			return (-1);
842eba222dfSad 		}
843eba222dfSad 		kd->iobuf = newbuf;
844eba222dfSad 		kd->iobufsz = dsize;
845eba222dfSad 	}
846eba222dfSad 	memset(kd->iobuf, 0, dsize);
847eba222dfSad 	doff = _kvm_pa2off(kd, pa);
848eba222dfSad 	doff -= doff % kd->fdalign;
849eba222dfSad 	if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) {
85055c7ea7cSthorpej 		_kvm_syserr(kd, 0, "cannot invalidate dump - pwrite");
8519c2128ecSleo 		return (-1);
8529c2128ecSleo 	}
8539c2128ecSleo 	return (0);
8549c2128ecSleo }
8559c2128ecSleo 
856429f62a6Scgd ssize_t
kvm_read(kvm_t * kd,u_long kva,void * buf,size_t len)8574267598fSjoerg kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len)
8585089c413Scgd {
8590b7831a3Sperry 	int cc;
8600b7831a3Sperry 	void *cp;
8615089c413Scgd 
862a9f690aeSsimonb 	if (ISKMEM(kd)) {
863429f62a6Scgd 		/*
864429f62a6Scgd 		 * We're using /dev/kmem.  Just read straight from the
865429f62a6Scgd 		 * device and let the active kernel do the address translation.
866429f62a6Scgd 		 */
867429f62a6Scgd 		errno = 0;
868a7a2d171Sad 		cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva);
869429f62a6Scgd 		if (cc < 0) {
870429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_read");
8711666d376Smsaitoh 			return (-1);
872429f62a6Scgd 		} else if (cc < len)
873429f62a6Scgd 			_kvm_err(kd, kd->program, "short read");
874429f62a6Scgd 		return (cc);
875a9f690aeSsimonb 	} else if (ISSYSCTL(kd)) {
876a9f690aeSsimonb 		_kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, "
877a9f690aeSsimonb 		    "can't use kvm_read");
878a9f690aeSsimonb 		return (-1);
879429f62a6Scgd 	} else {
88082118b75Sgwr 		if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) {
8819c2128ecSleo 			_kvm_err(kd, kd->program, "no valid dump header");
8821666d376Smsaitoh 			return (-1);
8839c2128ecSleo 		}
884429f62a6Scgd 		cp = buf;
885429f62a6Scgd 		while (len > 0) {
886962a341dSjym 			paddr_t	pa;
8879c2128ecSleo 			off_t	foff;
88861f28255Scgd 
889962a341dSjym 			cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa);
89019db2277Smrg 			if (cc == 0) {
89119db2277Smrg 				_kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva);
8921666d376Smsaitoh 				return (-1);
89319db2277Smrg 			}
894429f62a6Scgd 			if (cc > len)
895429f62a6Scgd 				cc = len;
8969c2128ecSleo 			foff = _kvm_pa2off(kd, pa);
897429f62a6Scgd 			errno = 0;
898a7a2d171Sad 			cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff);
899429f62a6Scgd 			if (cc < 0) {
900429f62a6Scgd 				_kvm_syserr(kd, kd->program, "kvm_read");
901ea0119dbScgd 				break;
902ea0119dbScgd 			}
9037b1fbb1cSpk 			/*
904429f62a6Scgd 			 * If kvm_kvatop returns a bogus value or our core
905429f62a6Scgd 			 * file is truncated, we might wind up seeking beyond
906429f62a6Scgd 			 * the end of the core file in which case the read will
907429f62a6Scgd 			 * return 0 (EOF).
9087b1fbb1cSpk 			 */
909429f62a6Scgd 			if (cc == 0)
910429f62a6Scgd 				break;
91100fd6050Scgd 			cp = (char *)cp + cc;
912429f62a6Scgd 			kva += cc;
913429f62a6Scgd 			len -= cc;
914429f62a6Scgd 		}
915429f62a6Scgd 		return ((char *)cp - (char *)buf);
916429f62a6Scgd 	}
917429f62a6Scgd 	/* NOTREACHED */
918429f62a6Scgd }
9197b1fbb1cSpk 
920429f62a6Scgd ssize_t
kvm_write(kvm_t * kd,u_long kva,const void * buf,size_t len)9214267598fSjoerg kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
922429f62a6Scgd {
9230b7831a3Sperry 	int cc;
92439cda398Schristos 	const void *cp;
9257b1fbb1cSpk 
926a9f690aeSsimonb 	if (ISKMEM(kd)) {
9277b1fbb1cSpk 		/*
928429f62a6Scgd 		 * Just like kvm_read, only we write.
9297b1fbb1cSpk 		 */
930429f62a6Scgd 		errno = 0;
93155c7ea7cSthorpej 		cc = pwrite(kd->vmfd, buf, len, (off_t)kva);
932429f62a6Scgd 		if (cc < 0) {
933429f62a6Scgd 			_kvm_syserr(kd, 0, "kvm_write");
9341666d376Smsaitoh 			return (-1);
935429f62a6Scgd 		} else if (cc < len)
936429f62a6Scgd 			_kvm_err(kd, kd->program, "short write");
937429f62a6Scgd 		return (cc);
938a9f690aeSsimonb 	} else if (ISSYSCTL(kd)) {
939a9f690aeSsimonb 		_kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, "
940a9f690aeSsimonb 		    "can't use kvm_write");
941a9f690aeSsimonb 		return (-1);
942429f62a6Scgd 	} else {
94339cda398Schristos 		if (kd->dump_mem == MAP_FAILED) {
944429f62a6Scgd 			_kvm_err(kd, kd->program,
945429f62a6Scgd 			    "kvm_write not implemented for dead kernels");
9461666d376Smsaitoh 			return (-1);
9477b1fbb1cSpk 		}
94839cda398Schristos 		cp = buf;
94939cda398Schristos 		while (len > 0) {
95039cda398Schristos 			paddr_t	pa;
95139cda398Schristos 			off_t	foff;
95239cda398Schristos 
95339cda398Schristos 			cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa);
95439cda398Schristos 			if (cc == 0) {
95539cda398Schristos 				_kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva);
95639cda398Schristos 				return (-1);
95739cda398Schristos 			}
95839cda398Schristos 			if (cc > len)
95939cda398Schristos 				cc = len;
96039cda398Schristos 			foff = _kvm_pa2off(kd, pa);
96139cda398Schristos 			errno = 0;
96239cda398Schristos 			cc = _kvm_pwrite(kd, cp, (size_t)cc, foff);
96339cda398Schristos 			if (cc < 0) {
96439cda398Schristos 				_kvm_syserr(kd, kd->program, "kvm_pwrite");
96539cda398Schristos 				break;
96639cda398Schristos 			}
96739cda398Schristos 			/*
96839cda398Schristos 			 * If kvm_kvatop returns a bogus value or our core
96939cda398Schristos 			 * file is truncated, we might wind up seeking beyond
97039cda398Schristos 			 * the end of the core file in which case the read will
97139cda398Schristos 			 * return 0 (EOF).
97239cda398Schristos 			 */
97339cda398Schristos 			if (cc == 0)
97439cda398Schristos 				break;
97539cda398Schristos 			cp = (const char *)cp + cc;
97639cda398Schristos 			kva += cc;
97739cda398Schristos 			len -= cc;
97839cda398Schristos 		}
97939cda398Schristos 		return ((const char *)cp - (const char *)buf);
98039cda398Schristos 	}
981429f62a6Scgd 	/* NOTREACHED */
98261f28255Scgd }
983