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