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