1*15f0ebb0Sderaadt /* $OpenBSD: kvm.c,v 1.3 1996/05/05 14:56:42 deraadt Exp $ */ 2*15f0ebb0Sderaadt /* $NetBSD: kvm.c,v 1.42 1996/03/18 22:33:13 thorpej Exp $ */ 33fbbad10Sniklas 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1989, 1992, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software developed by the Computer Systems 9df930be7Sderaadt * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 10df930be7Sderaadt * BG 91-66 and contributed to Berkeley. 11df930be7Sderaadt * 12df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 13df930be7Sderaadt * modification, are permitted provided that the following conditions 14df930be7Sderaadt * are met: 15df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 16df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 17df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 18df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 19df930be7Sderaadt * documentation and/or other materials provided with the distribution. 20df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 21df930be7Sderaadt * must display the following acknowledgement: 22df930be7Sderaadt * This product includes software developed by the University of 23df930be7Sderaadt * California, Berkeley and its contributors. 24df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 25df930be7Sderaadt * may be used to endorse or promote products derived from this software 26df930be7Sderaadt * without specific prior written permission. 27df930be7Sderaadt * 28df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38df930be7Sderaadt * SUCH DAMAGE. 39df930be7Sderaadt */ 40df930be7Sderaadt 41df930be7Sderaadt #if defined(LIBC_SCCS) && !defined(lint) 42*15f0ebb0Sderaadt #if 0 43df930be7Sderaadt static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 44*15f0ebb0Sderaadt #else 45*15f0ebb0Sderaadt static char *rcsid = "$OpenBSD: kvm.c,v 1.3 1996/05/05 14:56:42 deraadt Exp $"; 46*15f0ebb0Sderaadt #endif 47df930be7Sderaadt #endif /* LIBC_SCCS and not lint */ 48df930be7Sderaadt 49df930be7Sderaadt #include <sys/param.h> 50df930be7Sderaadt #include <sys/user.h> 51df930be7Sderaadt #include <sys/proc.h> 52df930be7Sderaadt #include <sys/ioctl.h> 53df930be7Sderaadt #include <sys/stat.h> 54df930be7Sderaadt #include <sys/sysctl.h> 55df930be7Sderaadt 563fbbad10Sniklas #include <sys/core.h> 573fbbad10Sniklas #include <sys/exec_aout.h> 583fbbad10Sniklas #include <sys/kcore.h> 593fbbad10Sniklas 60df930be7Sderaadt #include <vm/vm.h> 61df930be7Sderaadt #include <vm/vm_param.h> 62df930be7Sderaadt #include <vm/swap_pager.h> 63df930be7Sderaadt 64df930be7Sderaadt #include <machine/vmparam.h> 653fbbad10Sniklas #include <machine/kcore.h> 66df930be7Sderaadt 67df930be7Sderaadt #include <ctype.h> 68df930be7Sderaadt #include <db.h> 69df930be7Sderaadt #include <fcntl.h> 70df930be7Sderaadt #include <limits.h> 71df930be7Sderaadt #include <nlist.h> 72df930be7Sderaadt #include <paths.h> 73df930be7Sderaadt #include <stdio.h> 74df930be7Sderaadt #include <stdlib.h> 75df930be7Sderaadt #include <string.h> 76df930be7Sderaadt #include <unistd.h> 77*15f0ebb0Sderaadt #include <kvm.h> 78df930be7Sderaadt 79df930be7Sderaadt #include "kvm_private.h" 80df930be7Sderaadt 81df930be7Sderaadt static int kvm_dbopen __P((kvm_t *, const char *)); 823fbbad10Sniklas static int _kvm_get_header __P((kvm_t *)); 83df930be7Sderaadt static kvm_t *_kvm_open __P((kvm_t *, const char *, const char *, 84df930be7Sderaadt const char *, int, char *)); 853fbbad10Sniklas static int clear_gap __P((kvm_t *, FILE *, int)); 863fbbad10Sniklas static off_t Lseek __P((kvm_t *, int, off_t, int)); 873fbbad10Sniklas static ssize_t Read __P(( kvm_t *, int, void *, size_t)); 88df930be7Sderaadt 89df930be7Sderaadt char * 90df930be7Sderaadt kvm_geterr(kd) 91df930be7Sderaadt kvm_t *kd; 92df930be7Sderaadt { 93df930be7Sderaadt return (kd->errbuf); 94df930be7Sderaadt } 95df930be7Sderaadt 96df930be7Sderaadt #if __STDC__ 97df930be7Sderaadt #include <stdarg.h> 98df930be7Sderaadt #else 99df930be7Sderaadt #include <varargs.h> 100df930be7Sderaadt #endif 101df930be7Sderaadt 102df930be7Sderaadt /* 103df930be7Sderaadt * Report an error using printf style arguments. "program" is kd->program 104df930be7Sderaadt * on hard errors, and 0 on soft errors, so that under sun error emulation, 105df930be7Sderaadt * only hard errors are printed out (otherwise, programs like gdb will 106df930be7Sderaadt * generate tons of error messages when trying to access bogus pointers). 107df930be7Sderaadt */ 108df930be7Sderaadt void 109df930be7Sderaadt #if __STDC__ 110df930be7Sderaadt _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 111df930be7Sderaadt #else 112df930be7Sderaadt _kvm_err(kd, program, fmt, va_alist) 113df930be7Sderaadt kvm_t *kd; 114df930be7Sderaadt char *program, *fmt; 115df930be7Sderaadt va_dcl 116df930be7Sderaadt #endif 117df930be7Sderaadt { 118df930be7Sderaadt va_list ap; 119df930be7Sderaadt 120df930be7Sderaadt #ifdef __STDC__ 121df930be7Sderaadt va_start(ap, fmt); 122df930be7Sderaadt #else 123df930be7Sderaadt va_start(ap); 124df930be7Sderaadt #endif 125df930be7Sderaadt if (program != NULL) { 126df930be7Sderaadt (void)fprintf(stderr, "%s: ", program); 127df930be7Sderaadt (void)vfprintf(stderr, fmt, ap); 128df930be7Sderaadt (void)fputc('\n', stderr); 129df930be7Sderaadt } else 130df930be7Sderaadt (void)vsnprintf(kd->errbuf, 131df930be7Sderaadt sizeof(kd->errbuf), (char *)fmt, ap); 132df930be7Sderaadt 133df930be7Sderaadt va_end(ap); 134df930be7Sderaadt } 135df930be7Sderaadt 136df930be7Sderaadt void 137df930be7Sderaadt #if __STDC__ 138df930be7Sderaadt _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 139df930be7Sderaadt #else 140df930be7Sderaadt _kvm_syserr(kd, program, fmt, va_alist) 141df930be7Sderaadt kvm_t *kd; 142df930be7Sderaadt char *program, *fmt; 143df930be7Sderaadt va_dcl 144df930be7Sderaadt #endif 145df930be7Sderaadt { 146df930be7Sderaadt va_list ap; 147df930be7Sderaadt register int n; 148df930be7Sderaadt 149df930be7Sderaadt #if __STDC__ 150df930be7Sderaadt va_start(ap, fmt); 151df930be7Sderaadt #else 152df930be7Sderaadt va_start(ap); 153df930be7Sderaadt #endif 154df930be7Sderaadt if (program != NULL) { 155df930be7Sderaadt (void)fprintf(stderr, "%s: ", program); 156df930be7Sderaadt (void)vfprintf(stderr, fmt, ap); 157df930be7Sderaadt (void)fprintf(stderr, ": %s\n", strerror(errno)); 158df930be7Sderaadt } else { 159df930be7Sderaadt register char *cp = kd->errbuf; 160df930be7Sderaadt 161df930be7Sderaadt (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 162df930be7Sderaadt n = strlen(cp); 163df930be7Sderaadt (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 164df930be7Sderaadt strerror(errno)); 165df930be7Sderaadt } 166df930be7Sderaadt va_end(ap); 167df930be7Sderaadt } 168df930be7Sderaadt 169df930be7Sderaadt void * 170df930be7Sderaadt _kvm_malloc(kd, n) 171df930be7Sderaadt register kvm_t *kd; 172df930be7Sderaadt register size_t n; 173df930be7Sderaadt { 174df930be7Sderaadt void *p; 175df930be7Sderaadt 176df930be7Sderaadt if ((p = malloc(n)) == NULL) 177df930be7Sderaadt _kvm_err(kd, kd->program, strerror(errno)); 178df930be7Sderaadt return (p); 179df930be7Sderaadt } 180df930be7Sderaadt 1813fbbad10Sniklas /* 1823fbbad10Sniklas * Wrappers for Lseek/Read system calls. They check for errors and 1833fbbad10Sniklas * call _kvm_syserr() if appropriate. 1843fbbad10Sniklas */ 1853fbbad10Sniklas static off_t 1863fbbad10Sniklas Lseek(kd, fd, offset, whence) 1873fbbad10Sniklas kvm_t *kd; 1883fbbad10Sniklas int fd, whence; 1893fbbad10Sniklas off_t offset; 1903fbbad10Sniklas { 1913fbbad10Sniklas off_t off; 1923fbbad10Sniklas 1933fbbad10Sniklas errno = 0; 1943fbbad10Sniklas if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) { 1953fbbad10Sniklas _kvm_syserr(kd, kd->program, "Lseek"); 1963fbbad10Sniklas return (-1); 1973fbbad10Sniklas } 1983fbbad10Sniklas return (off); 1993fbbad10Sniklas } 2003fbbad10Sniklas 2013fbbad10Sniklas static ssize_t 2023fbbad10Sniklas Read(kd, fd, buf, nbytes) 2033fbbad10Sniklas kvm_t *kd; 2043fbbad10Sniklas int fd; 2053fbbad10Sniklas void *buf; 2063fbbad10Sniklas size_t nbytes; 2073fbbad10Sniklas { 2083fbbad10Sniklas ssize_t rv; 2093fbbad10Sniklas 2103fbbad10Sniklas errno = 0; 2113fbbad10Sniklas 2123fbbad10Sniklas if ((rv = read(fd, buf, nbytes)) != nbytes && errno != 0) 2133fbbad10Sniklas _kvm_syserr(kd, kd->program, "Read"); 2143fbbad10Sniklas return (rv); 2153fbbad10Sniklas } 2163fbbad10Sniklas 217df930be7Sderaadt static kvm_t * 218df930be7Sderaadt _kvm_open(kd, uf, mf, sf, flag, errout) 219df930be7Sderaadt register kvm_t *kd; 220df930be7Sderaadt const char *uf; 221df930be7Sderaadt const char *mf; 222df930be7Sderaadt const char *sf; 223df930be7Sderaadt int flag; 224df930be7Sderaadt char *errout; 225df930be7Sderaadt { 226df930be7Sderaadt struct stat st; 227df930be7Sderaadt 228df930be7Sderaadt kd->db = 0; 229df930be7Sderaadt kd->pmfd = -1; 230df930be7Sderaadt kd->vmfd = -1; 231df930be7Sderaadt kd->swfd = -1; 232df930be7Sderaadt kd->nlfd = -1; 233df930be7Sderaadt kd->procbase = 0; 234df930be7Sderaadt kd->nbpg = getpagesize(); 235df930be7Sderaadt kd->swapspc = 0; 236df930be7Sderaadt kd->argspc = 0; 237df930be7Sderaadt kd->argbuf = 0; 238df930be7Sderaadt kd->argv = 0; 239df930be7Sderaadt kd->vmst = 0; 240df930be7Sderaadt kd->vm_page_buckets = 0; 2413fbbad10Sniklas kd->kcore_hdr = 0; 2423fbbad10Sniklas kd->cpu_hdr = 0; 2433fbbad10Sniklas kd->dump_off = 0; 244df930be7Sderaadt 245df930be7Sderaadt if (uf == 0) 246df930be7Sderaadt uf = _PATH_UNIX; 247df930be7Sderaadt else if (strlen(uf) >= MAXPATHLEN) { 248df930be7Sderaadt _kvm_err(kd, kd->program, "exec file name too long"); 249df930be7Sderaadt goto failed; 250df930be7Sderaadt } 251df930be7Sderaadt if (flag & ~O_RDWR) { 252df930be7Sderaadt _kvm_err(kd, kd->program, "bad flags arg"); 253df930be7Sderaadt goto failed; 254df930be7Sderaadt } 255df930be7Sderaadt if (mf == 0) 256df930be7Sderaadt mf = _PATH_MEM; 257df930be7Sderaadt if (sf == 0) 258df930be7Sderaadt sf = _PATH_DRUM; 259df930be7Sderaadt 260df930be7Sderaadt if ((kd->pmfd = open(mf, flag, 0)) < 0) { 261df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", mf); 262df930be7Sderaadt goto failed; 263df930be7Sderaadt } 264df930be7Sderaadt if (fstat(kd->pmfd, &st) < 0) { 265df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", mf); 266df930be7Sderaadt goto failed; 267df930be7Sderaadt } 268df930be7Sderaadt if (S_ISCHR(st.st_mode)) { 269df930be7Sderaadt /* 270df930be7Sderaadt * If this is a character special device, then check that 271df930be7Sderaadt * it's /dev/mem. If so, open kmem too. (Maybe we should 272df930be7Sderaadt * make it work for either /dev/mem or /dev/kmem -- in either 273df930be7Sderaadt * case you're working with a live kernel.) 274df930be7Sderaadt */ 275df930be7Sderaadt if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */ 276df930be7Sderaadt _kvm_err(kd, kd->program, 277df930be7Sderaadt "%s: not physical memory device", mf); 278df930be7Sderaadt goto failed; 279df930be7Sderaadt } 280df930be7Sderaadt if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 281df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 282df930be7Sderaadt goto failed; 283df930be7Sderaadt } 284df930be7Sderaadt if ((kd->swfd = open(sf, flag, 0)) < 0) { 285df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", sf); 286df930be7Sderaadt goto failed; 287df930be7Sderaadt } 288df930be7Sderaadt /* 289df930be7Sderaadt * Open kvm nlist database. We go ahead and do this 290df930be7Sderaadt * here so that we don't have to hold on to the vmunix 291df930be7Sderaadt * path name. Since a kvm application will surely do 292df930be7Sderaadt * a kvm_nlist(), this probably won't be a wasted effort. 293df930be7Sderaadt * If the database cannot be opened, open the namelist 294df930be7Sderaadt * argument so we revert to slow nlist() calls. 295df930be7Sderaadt */ 296df930be7Sderaadt if (kvm_dbopen(kd, uf) < 0 && 297df930be7Sderaadt (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 298df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", uf); 299df930be7Sderaadt goto failed; 300df930be7Sderaadt } 301df930be7Sderaadt } else { 302df930be7Sderaadt /* 303df930be7Sderaadt * This is a crash dump. 304df930be7Sderaadt * Initalize the virtual address translation machinery, 305df930be7Sderaadt * but first setup the namelist fd. 306df930be7Sderaadt */ 307df930be7Sderaadt if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 308df930be7Sderaadt _kvm_syserr(kd, kd->program, "%s", uf); 309df930be7Sderaadt goto failed; 310df930be7Sderaadt } 3113fbbad10Sniklas 3123fbbad10Sniklas /* 3133fbbad10Sniklas * If there is no valid core header, fail silently here. 3143fbbad10Sniklas * The address translations however will fail without 3153fbbad10Sniklas * header. Things can be made to run by calling 3163fbbad10Sniklas * kvm_dump_mkheader() before doing any translation. 3173fbbad10Sniklas */ 3183fbbad10Sniklas if (_kvm_get_header(kd) == 0) { 319df930be7Sderaadt if (_kvm_initvtop(kd) < 0) 320df930be7Sderaadt goto failed; 321df930be7Sderaadt } 3223fbbad10Sniklas } 323df930be7Sderaadt return (kd); 324df930be7Sderaadt failed: 325df930be7Sderaadt /* 326df930be7Sderaadt * Copy out the error if doing sane error semantics. 327df930be7Sderaadt */ 328df930be7Sderaadt if (errout != 0) 329df930be7Sderaadt strcpy(errout, kd->errbuf); 330df930be7Sderaadt (void)kvm_close(kd); 331df930be7Sderaadt return (0); 332df930be7Sderaadt } 333df930be7Sderaadt 3343fbbad10Sniklas static int 3353fbbad10Sniklas _kvm_get_header(kd) 3363fbbad10Sniklas kvm_t *kd; 3373fbbad10Sniklas { 3383fbbad10Sniklas cpu_kcore_hdr_t ckhdr; 3393fbbad10Sniklas kcore_hdr_t khdr; 3403fbbad10Sniklas kcore_seg_t seghdr; 3413fbbad10Sniklas off_t offset; 3423fbbad10Sniklas 3433fbbad10Sniklas if (Lseek(kd, kd->pmfd, (off_t)0, SEEK_SET) == -1) 3443fbbad10Sniklas return (-1); 3453fbbad10Sniklas 3463fbbad10Sniklas if (Read(kd, kd->pmfd, &khdr, sizeof(khdr)) != sizeof(khdr)) 3473fbbad10Sniklas return (-1); 3483fbbad10Sniklas offset = khdr.c_hdrsize; 3493fbbad10Sniklas 3503fbbad10Sniklas /* 3513fbbad10Sniklas * Currently, we only support dump-files made by the current 3523fbbad10Sniklas * architecture... 3533fbbad10Sniklas */ 3543fbbad10Sniklas if ((CORE_GETMAGIC(khdr) != KCORE_MAGIC) 3553fbbad10Sniklas || ((CORE_GETMID(khdr) != MID_MACHINE))) 3563fbbad10Sniklas return (-1); 3573fbbad10Sniklas 3583fbbad10Sniklas /* 3593fbbad10Sniklas * Currently, we only support exactly 2 segments: cpu-segment 3603fbbad10Sniklas * and data-segment in exactly that order. 3613fbbad10Sniklas */ 3623fbbad10Sniklas if (khdr.c_nseg != 2) 3633fbbad10Sniklas return (-1); 3643fbbad10Sniklas 3653fbbad10Sniklas /* 3663fbbad10Sniklas * Read the next segment header: cpu segment 3673fbbad10Sniklas */ 3683fbbad10Sniklas if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1) 3693fbbad10Sniklas return (-1); 3703fbbad10Sniklas if (Read(kd, kd->pmfd, &seghdr, sizeof(seghdr)) != sizeof(seghdr)) 3713fbbad10Sniklas return (-1); 3723fbbad10Sniklas if (CORE_GETMAGIC(seghdr) != KCORESEG_MAGIC 3733fbbad10Sniklas || CORE_GETFLAG(seghdr) != CORE_CPU) 3743fbbad10Sniklas return (-1); 3753fbbad10Sniklas offset += khdr.c_seghdrsize; 3763fbbad10Sniklas if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1) 3773fbbad10Sniklas return (-1); 3783fbbad10Sniklas if (Read(kd, kd->pmfd, &ckhdr, sizeof(ckhdr)) != sizeof(ckhdr)) 3793fbbad10Sniklas return (-1); 3803fbbad10Sniklas offset += seghdr.c_size; 3813fbbad10Sniklas 3823fbbad10Sniklas /* 3833fbbad10Sniklas * Read the next segment header: data segment 3843fbbad10Sniklas */ 3853fbbad10Sniklas if (Lseek(kd, kd->pmfd, (off_t)offset, SEEK_SET) == -1) 3863fbbad10Sniklas return (-1); 3873fbbad10Sniklas if (Read(kd, kd->pmfd, &seghdr, sizeof(seghdr)) != sizeof(seghdr)) 3883fbbad10Sniklas return (-1); 3893fbbad10Sniklas offset += khdr.c_seghdrsize; 3903fbbad10Sniklas 3913fbbad10Sniklas if (CORE_GETMAGIC(seghdr) != KCORESEG_MAGIC 3923fbbad10Sniklas || CORE_GETFLAG(seghdr) != CORE_DATA) 3933fbbad10Sniklas return (-1); 3943fbbad10Sniklas 3953fbbad10Sniklas kd->kcore_hdr = (kcore_hdr_t *)_kvm_malloc(kd, sizeof(*kd->kcore_hdr)); 3963fbbad10Sniklas if (kd->kcore_hdr == NULL) 3973fbbad10Sniklas return (-1); 3983fbbad10Sniklas kd->cpu_hdr = (cpu_kcore_hdr_t *)_kvm_malloc(kd, sizeof(*kd->cpu_hdr)); 3993fbbad10Sniklas if (kd->cpu_hdr == NULL) { 4003fbbad10Sniklas free((void *)kd->kcore_hdr); 4013fbbad10Sniklas kd->kcore_hdr = NULL; 4023fbbad10Sniklas return (-1); 4033fbbad10Sniklas } 4043fbbad10Sniklas 4053fbbad10Sniklas *kd->kcore_hdr = khdr; 4063fbbad10Sniklas *kd->cpu_hdr = ckhdr; 4073fbbad10Sniklas kd->dump_off = offset; 4083fbbad10Sniklas return (0); 4093fbbad10Sniklas } 4103fbbad10Sniklas 4113fbbad10Sniklas /* 4123fbbad10Sniklas * Translate a physical address to a file-offset in the crash-dump. 4133fbbad10Sniklas */ 4143fbbad10Sniklas off_t 4153fbbad10Sniklas _kvm_pa2off(kd, pa) 4163fbbad10Sniklas kvm_t *kd; 4173fbbad10Sniklas u_long pa; 4183fbbad10Sniklas { 4193fbbad10Sniklas off_t off; 4203fbbad10Sniklas phys_ram_seg_t *rsp; 4213fbbad10Sniklas 4223fbbad10Sniklas off = 0; 4233fbbad10Sniklas for (rsp = kd->cpu_hdr->ram_segs; rsp->size; rsp++) { 4243fbbad10Sniklas if (pa >= rsp->start && pa < rsp->start + rsp->size) { 4253fbbad10Sniklas pa -= rsp->start; 4263fbbad10Sniklas break; 4273fbbad10Sniklas } 4283fbbad10Sniklas off += rsp->size; 4293fbbad10Sniklas } 4303fbbad10Sniklas return(pa + off + kd->dump_off); 4313fbbad10Sniklas } 4323fbbad10Sniklas 4333fbbad10Sniklas int 434*15f0ebb0Sderaadt kvm_dump_mkheader(kd, dump_off) 435*15f0ebb0Sderaadt kvm_t *kd; 4363fbbad10Sniklas off_t dump_off; 4373fbbad10Sniklas { 4383fbbad10Sniklas kcore_hdr_t kch; 4393fbbad10Sniklas kcore_seg_t kseg; 4403fbbad10Sniklas cpu_kcore_hdr_t ckhdr; 4413fbbad10Sniklas int hdr_size; 4423fbbad10Sniklas 4433fbbad10Sniklas hdr_size = 0; 444*15f0ebb0Sderaadt if (kd->kcore_hdr != NULL) { 445*15f0ebb0Sderaadt _kvm_err(kd, kd->program, "already has a dump header"); 4463fbbad10Sniklas return (-1); 4473fbbad10Sniklas } 448*15f0ebb0Sderaadt if (ISALIVE(kd)) { 449*15f0ebb0Sderaadt _kvm_err(kd, kd->program, "don't use on live kernel"); 4503fbbad10Sniklas return (-1); 4513fbbad10Sniklas } 4523fbbad10Sniklas 4533fbbad10Sniklas /* 4543fbbad10Sniklas * Check for new format crash dump 4553fbbad10Sniklas */ 456*15f0ebb0Sderaadt if (Lseek(kd, kd->pmfd, dump_off, SEEK_SET) == -1) 4573fbbad10Sniklas return (-1); 458*15f0ebb0Sderaadt if (Read(kd, kd->pmfd, &kseg, sizeof(kseg)) != sizeof(kseg)) 4593fbbad10Sniklas return (-1); 4603fbbad10Sniklas if ((CORE_GETMAGIC(kseg) == KCORE_MAGIC) 4613fbbad10Sniklas && ((CORE_GETMID(kseg) == MID_MACHINE))) { 4623fbbad10Sniklas hdr_size += ALIGN(sizeof(kcore_seg_t)); 463*15f0ebb0Sderaadt if (Lseek(kd, kd->pmfd, dump_off+hdr_size, SEEK_SET) == -1) 4643fbbad10Sniklas return (-1); 465*15f0ebb0Sderaadt if (Read(kd, kd->pmfd, &ckhdr, sizeof(ckhdr)) != sizeof(ckhdr)) 4663fbbad10Sniklas return (-1); 4673fbbad10Sniklas hdr_size += kseg.c_size; 468*15f0ebb0Sderaadt if (Lseek(kd, kd->pmfd, dump_off+hdr_size, SEEK_SET) == -1) 4693fbbad10Sniklas return (-1); 470*15f0ebb0Sderaadt kd->cpu_hdr = (cpu_kcore_hdr_t *) 471*15f0ebb0Sderaadt _kvm_malloc(kd, sizeof(cpu_kcore_hdr_t)); 472*15f0ebb0Sderaadt *kd->cpu_hdr = ckhdr; 4733fbbad10Sniklas } 4743fbbad10Sniklas 4753fbbad10Sniklas /* 4763fbbad10Sniklas * Create a kcore_hdr. 4773fbbad10Sniklas */ 478*15f0ebb0Sderaadt kd->kcore_hdr = (kcore_hdr_t *) _kvm_malloc(kd, sizeof(kcore_hdr_t)); 479*15f0ebb0Sderaadt if (kd->kcore_hdr == NULL) { 480*15f0ebb0Sderaadt if (kd->cpu_hdr != NULL) { 481*15f0ebb0Sderaadt free((void *)kd->cpu_hdr); 482*15f0ebb0Sderaadt kd->cpu_hdr = NULL; 4833fbbad10Sniklas } 4843fbbad10Sniklas return (-1); 4853fbbad10Sniklas } 4863fbbad10Sniklas 487*15f0ebb0Sderaadt kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t)); 488*15f0ebb0Sderaadt kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t)); 489*15f0ebb0Sderaadt kd->kcore_hdr->c_nseg = 2; 490*15f0ebb0Sderaadt CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0); 4913fbbad10Sniklas 4923fbbad10Sniklas /* 4933fbbad10Sniklas * If there is no cpu_hdr at this point, we probably have an 4943fbbad10Sniklas * old format crash dump.....bail out 4953fbbad10Sniklas */ 496*15f0ebb0Sderaadt if (kd->cpu_hdr == NULL) { 497*15f0ebb0Sderaadt free((void *)kd->kcore_hdr); 498*15f0ebb0Sderaadt kd->kcore_hdr = NULL; 499*15f0ebb0Sderaadt _kvm_err(kd, kd->program, "invalid dump"); 5003fbbad10Sniklas } 5013fbbad10Sniklas 502*15f0ebb0Sderaadt kd->dump_off = dump_off + hdr_size; 5033fbbad10Sniklas 5043fbbad10Sniklas /* 5053fbbad10Sniklas * Now that we have a valid header, enable translations. 5063fbbad10Sniklas */ 507*15f0ebb0Sderaadt _kvm_initvtop(kd); 5083fbbad10Sniklas 5093fbbad10Sniklas return(hdr_size); 5103fbbad10Sniklas } 5113fbbad10Sniklas 5123fbbad10Sniklas static int 5133fbbad10Sniklas clear_gap(kd, fp, size) 5143fbbad10Sniklas kvm_t *kd; 5153fbbad10Sniklas FILE *fp; 5163fbbad10Sniklas int size; 5173fbbad10Sniklas { 5183fbbad10Sniklas if (size <= 0) /* XXX - < 0 should never happen */ 5193fbbad10Sniklas return (0); 5203fbbad10Sniklas while (size-- > 0) { 5213fbbad10Sniklas if (fputc(0, fp) == EOF) { 5223fbbad10Sniklas _kvm_syserr(kd, kd->program, "clear_gap"); 5233fbbad10Sniklas return (-1); 5243fbbad10Sniklas } 5253fbbad10Sniklas } 5263fbbad10Sniklas return (0); 5273fbbad10Sniklas } 5283fbbad10Sniklas 5293fbbad10Sniklas /* 5303fbbad10Sniklas * Write the dump header info to 'fp'. Note that we can't use fseek(3) here 5313fbbad10Sniklas * because 'fp' might be a file pointer obtained by zopen(). 5323fbbad10Sniklas */ 5333fbbad10Sniklas int 5343fbbad10Sniklas kvm_dump_wrtheader(kd, fp, dumpsize) 5353fbbad10Sniklas kvm_t *kd; 5363fbbad10Sniklas FILE *fp; 5373fbbad10Sniklas int dumpsize; 5383fbbad10Sniklas { 5393fbbad10Sniklas kcore_seg_t seghdr; 5403fbbad10Sniklas long offset; 5413fbbad10Sniklas int gap; 5423fbbad10Sniklas 5433fbbad10Sniklas if (kd->kcore_hdr == NULL || kd->cpu_hdr == NULL) { 5443fbbad10Sniklas _kvm_err(kd, kd->program, "no valid dump header(s)"); 5453fbbad10Sniklas return (-1); 5463fbbad10Sniklas } 5473fbbad10Sniklas 5483fbbad10Sniklas /* 5493fbbad10Sniklas * Write the generic header 5503fbbad10Sniklas */ 5513fbbad10Sniklas offset = 0; 5523fbbad10Sniklas if (fwrite((void*)kd->kcore_hdr, sizeof(kcore_hdr_t), 1, fp) <= 0) { 5533fbbad10Sniklas _kvm_syserr(kd, kd->program, "kvm_dump_wrtheader"); 5543fbbad10Sniklas return (-1); 5553fbbad10Sniklas } 5563fbbad10Sniklas offset += kd->kcore_hdr->c_hdrsize; 5573fbbad10Sniklas gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t); 5583fbbad10Sniklas if (clear_gap(kd, fp, gap) == -1) 5593fbbad10Sniklas return (-1); 5603fbbad10Sniklas 5613fbbad10Sniklas /* 5623fbbad10Sniklas * Write the cpu header 5633fbbad10Sniklas */ 5643fbbad10Sniklas CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU); 5653fbbad10Sniklas seghdr.c_size = ALIGN(sizeof(cpu_kcore_hdr_t)); 5663fbbad10Sniklas if (fwrite((void*)&seghdr, sizeof(seghdr), 1, fp) <= 0) { 5673fbbad10Sniklas _kvm_syserr(kd, kd->program, "kvm_dump_wrtheader"); 5683fbbad10Sniklas return (-1); 5693fbbad10Sniklas } 5703fbbad10Sniklas offset += kd->kcore_hdr->c_seghdrsize; 5713fbbad10Sniklas gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); 5723fbbad10Sniklas if (clear_gap(kd, fp, gap) == -1) 5733fbbad10Sniklas return (-1); 5743fbbad10Sniklas 5753fbbad10Sniklas if (fwrite((void*)kd->cpu_hdr, sizeof(cpu_kcore_hdr_t), 1, fp) <= 0) { 5763fbbad10Sniklas _kvm_syserr(kd, kd->program, "kvm_dump_wrtheader"); 5773fbbad10Sniklas return (-1); 5783fbbad10Sniklas } 5793fbbad10Sniklas offset += seghdr.c_size; 5803fbbad10Sniklas gap = seghdr.c_size - sizeof(cpu_kcore_hdr_t); 5813fbbad10Sniklas if (clear_gap(kd, fp, gap) == -1) 5823fbbad10Sniklas return (-1); 5833fbbad10Sniklas 5843fbbad10Sniklas /* 5853fbbad10Sniklas * Write the actual dump data segment header 5863fbbad10Sniklas */ 5873fbbad10Sniklas CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA); 5883fbbad10Sniklas seghdr.c_size = dumpsize; 5893fbbad10Sniklas if (fwrite((void*)&seghdr, sizeof(seghdr), 1, fp) <= 0) { 5903fbbad10Sniklas _kvm_syserr(kd, kd->program, "kvm_dump_wrtheader"); 5913fbbad10Sniklas return (-1); 5923fbbad10Sniklas } 5933fbbad10Sniklas offset += kd->kcore_hdr->c_seghdrsize; 5943fbbad10Sniklas gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); 5953fbbad10Sniklas if (clear_gap(kd, fp, gap) == -1) 5963fbbad10Sniklas return (-1); 5973fbbad10Sniklas 5983fbbad10Sniklas return (offset); 5993fbbad10Sniklas } 6003fbbad10Sniklas 601df930be7Sderaadt kvm_t * 602df930be7Sderaadt kvm_openfiles(uf, mf, sf, flag, errout) 603df930be7Sderaadt const char *uf; 604df930be7Sderaadt const char *mf; 605df930be7Sderaadt const char *sf; 606df930be7Sderaadt int flag; 607df930be7Sderaadt char *errout; 608df930be7Sderaadt { 609df930be7Sderaadt register kvm_t *kd; 610df930be7Sderaadt 611df930be7Sderaadt if ((kd = malloc(sizeof(*kd))) == NULL) { 612df930be7Sderaadt (void)strcpy(errout, strerror(errno)); 613df930be7Sderaadt return (0); 614df930be7Sderaadt } 615df930be7Sderaadt kd->program = 0; 616df930be7Sderaadt return (_kvm_open(kd, uf, mf, sf, flag, errout)); 617df930be7Sderaadt } 618df930be7Sderaadt 619df930be7Sderaadt kvm_t * 620df930be7Sderaadt kvm_open(uf, mf, sf, flag, program) 621df930be7Sderaadt const char *uf; 622df930be7Sderaadt const char *mf; 623df930be7Sderaadt const char *sf; 624df930be7Sderaadt int flag; 625df930be7Sderaadt const char *program; 626df930be7Sderaadt { 627df930be7Sderaadt register kvm_t *kd; 628df930be7Sderaadt 629df930be7Sderaadt if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) { 630df930be7Sderaadt (void)fprintf(stderr, "%s: %s\n", strerror(errno)); 631df930be7Sderaadt return (0); 632df930be7Sderaadt } 633df930be7Sderaadt kd->program = program; 634df930be7Sderaadt return (_kvm_open(kd, uf, mf, sf, flag, NULL)); 635df930be7Sderaadt } 636df930be7Sderaadt 637df930be7Sderaadt int 638df930be7Sderaadt kvm_close(kd) 639df930be7Sderaadt kvm_t *kd; 640df930be7Sderaadt { 641df930be7Sderaadt register int error = 0; 642df930be7Sderaadt 643df930be7Sderaadt if (kd->pmfd >= 0) 644df930be7Sderaadt error |= close(kd->pmfd); 645df930be7Sderaadt if (kd->vmfd >= 0) 646df930be7Sderaadt error |= close(kd->vmfd); 647df930be7Sderaadt if (kd->nlfd >= 0) 648df930be7Sderaadt error |= close(kd->nlfd); 649df930be7Sderaadt if (kd->swfd >= 0) 650df930be7Sderaadt error |= close(kd->swfd); 651df930be7Sderaadt if (kd->db != 0) 652df930be7Sderaadt error |= (kd->db->close)(kd->db); 653df930be7Sderaadt if (kd->vmst) 654df930be7Sderaadt _kvm_freevtop(kd); 6553fbbad10Sniklas if (kd->cpu_hdr != NULL) 6563fbbad10Sniklas free((void *)kd->cpu_hdr); 6573fbbad10Sniklas if (kd->kcore_hdr != NULL) 6583fbbad10Sniklas free((void *)kd->kcore_hdr); 659df930be7Sderaadt if (kd->procbase != 0) 660df930be7Sderaadt free((void *)kd->procbase); 661df930be7Sderaadt if (kd->swapspc != 0) 662df930be7Sderaadt free((void *)kd->swapspc); 663df930be7Sderaadt if (kd->argspc != 0) 664df930be7Sderaadt free((void *)kd->argspc); 665df930be7Sderaadt if (kd->argbuf != 0) 666df930be7Sderaadt free((void *)kd->argbuf); 667df930be7Sderaadt if (kd->argv != 0) 668df930be7Sderaadt free((void *)kd->argv); 669df930be7Sderaadt free((void *)kd); 670df930be7Sderaadt 671df930be7Sderaadt return (0); 672df930be7Sderaadt } 673df930be7Sderaadt 674df930be7Sderaadt /* 675df930be7Sderaadt * Set up state necessary to do queries on the kernel namelist 676df930be7Sderaadt * data base. If the data base is out-of-data/incompatible with 677df930be7Sderaadt * given executable, set up things so we revert to standard nlist call. 678df930be7Sderaadt * Only called for live kernels. Return 0 on success, -1 on failure. 679df930be7Sderaadt */ 680df930be7Sderaadt static int 681df930be7Sderaadt kvm_dbopen(kd, uf) 682df930be7Sderaadt kvm_t *kd; 683df930be7Sderaadt const char *uf; 684df930be7Sderaadt { 685df930be7Sderaadt char *cp; 686df930be7Sderaadt DBT rec; 687df930be7Sderaadt int dbversionlen; 688df930be7Sderaadt struct nlist nitem; 689df930be7Sderaadt char dbversion[_POSIX2_LINE_MAX]; 690df930be7Sderaadt char kversion[_POSIX2_LINE_MAX]; 691df930be7Sderaadt char dbname[MAXPATHLEN]; 692df930be7Sderaadt 693df930be7Sderaadt if ((cp = rindex(uf, '/')) != 0) 694df930be7Sderaadt uf = cp + 1; 695df930be7Sderaadt 696df930be7Sderaadt (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); 697df930be7Sderaadt kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); 698df930be7Sderaadt if (kd->db == 0) 699df930be7Sderaadt return (-1); 700df930be7Sderaadt /* 701df930be7Sderaadt * read version out of database 702df930be7Sderaadt */ 703df930be7Sderaadt rec.data = VRS_KEY; 704df930be7Sderaadt rec.size = sizeof(VRS_KEY) - 1; 705df930be7Sderaadt if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 706df930be7Sderaadt goto close; 707df930be7Sderaadt if (rec.data == 0 || rec.size > sizeof(dbversion)) 708df930be7Sderaadt goto close; 709df930be7Sderaadt 710df930be7Sderaadt bcopy(rec.data, dbversion, rec.size); 711df930be7Sderaadt dbversionlen = rec.size; 712df930be7Sderaadt /* 713df930be7Sderaadt * Read version string from kernel memory. 714df930be7Sderaadt * Since we are dealing with a live kernel, we can call kvm_read() 715df930be7Sderaadt * at this point. 716df930be7Sderaadt */ 717df930be7Sderaadt rec.data = VRS_SYM; 718df930be7Sderaadt rec.size = sizeof(VRS_SYM) - 1; 719df930be7Sderaadt if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 720df930be7Sderaadt goto close; 721df930be7Sderaadt if (rec.data == 0 || rec.size != sizeof(struct nlist)) 722df930be7Sderaadt goto close; 723df930be7Sderaadt bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem)); 724df930be7Sderaadt if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) != 725df930be7Sderaadt dbversionlen) 726df930be7Sderaadt goto close; 727df930be7Sderaadt /* 728df930be7Sderaadt * If they match, we win - otherwise clear out kd->db so 729df930be7Sderaadt * we revert to slow nlist(). 730df930be7Sderaadt */ 731df930be7Sderaadt if (bcmp(dbversion, kversion, dbversionlen) == 0) 732df930be7Sderaadt return (0); 733df930be7Sderaadt close: 734df930be7Sderaadt (void)(kd->db->close)(kd->db); 735df930be7Sderaadt kd->db = 0; 736df930be7Sderaadt 737df930be7Sderaadt return (-1); 738df930be7Sderaadt } 739df930be7Sderaadt 740df930be7Sderaadt int 741df930be7Sderaadt kvm_nlist(kd, nl) 742df930be7Sderaadt kvm_t *kd; 743df930be7Sderaadt struct nlist *nl; 744df930be7Sderaadt { 745df930be7Sderaadt register struct nlist *p; 746df930be7Sderaadt register int nvalid; 747df930be7Sderaadt 748df930be7Sderaadt /* 749df930be7Sderaadt * If we can't use the data base, revert to the 750df930be7Sderaadt * slow library call. 751df930be7Sderaadt */ 752df930be7Sderaadt if (kd->db == 0) 753df930be7Sderaadt return (__fdnlist(kd->nlfd, nl)); 754df930be7Sderaadt 755df930be7Sderaadt /* 756df930be7Sderaadt * We can use the kvm data base. Go through each nlist entry 757df930be7Sderaadt * and look it up with a db query. 758df930be7Sderaadt */ 759df930be7Sderaadt nvalid = 0; 760df930be7Sderaadt for (p = nl; p->n_name && p->n_name[0]; ++p) { 761df930be7Sderaadt register int len; 762df930be7Sderaadt DBT rec; 763df930be7Sderaadt 764df930be7Sderaadt if ((len = strlen(p->n_name)) > 4096) { 765df930be7Sderaadt /* sanity */ 766df930be7Sderaadt _kvm_err(kd, kd->program, "symbol too large"); 767df930be7Sderaadt return (-1); 768df930be7Sderaadt } 769df930be7Sderaadt rec.data = p->n_name; 770df930be7Sderaadt rec.size = len; 7713fbbad10Sniklas 7723fbbad10Sniklas /* 7733fbbad10Sniklas * Make sure that n_value = 0 when the symbol isn't found 7743fbbad10Sniklas */ 7753fbbad10Sniklas p->n_value = 0; 7763fbbad10Sniklas 777df930be7Sderaadt if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 778df930be7Sderaadt continue; 779df930be7Sderaadt if (rec.data == 0 || rec.size != sizeof(struct nlist)) 780df930be7Sderaadt continue; 781df930be7Sderaadt ++nvalid; 782df930be7Sderaadt /* 783df930be7Sderaadt * Avoid alignment issues. 784df930be7Sderaadt */ 785df930be7Sderaadt bcopy((char *)&((struct nlist *)rec.data)->n_type, 786df930be7Sderaadt (char *)&p->n_type, 787df930be7Sderaadt sizeof(p->n_type)); 788df930be7Sderaadt bcopy((char *)&((struct nlist *)rec.data)->n_value, 789df930be7Sderaadt (char *)&p->n_value, 790df930be7Sderaadt sizeof(p->n_value)); 791df930be7Sderaadt } 792df930be7Sderaadt /* 793df930be7Sderaadt * Return the number of entries that weren't found. 794df930be7Sderaadt */ 795df930be7Sderaadt return ((p - nl) - nvalid); 796df930be7Sderaadt } 797df930be7Sderaadt 7983fbbad10Sniklas int kvm_dump_inval(kd) 7993fbbad10Sniklas kvm_t *kd; 8003fbbad10Sniklas { 8013fbbad10Sniklas struct nlist nlist[2]; 8023fbbad10Sniklas u_long pa; 8033fbbad10Sniklas 8043fbbad10Sniklas if (ISALIVE(kd)) { 8053fbbad10Sniklas _kvm_err(kd, kd->program, "clearing dump on live kernel"); 8063fbbad10Sniklas return (-1); 8073fbbad10Sniklas } 8083fbbad10Sniklas nlist[0].n_name = "_dumpmag"; 8093fbbad10Sniklas nlist[1].n_name = NULL; 8103fbbad10Sniklas 8113fbbad10Sniklas if (kvm_nlist(kd, nlist) == -1) { 8123fbbad10Sniklas _kvm_err(kd, 0, "bad namelist"); 8133fbbad10Sniklas return (-1); 8143fbbad10Sniklas } 8153fbbad10Sniklas if (_kvm_kvatop(kd, (u_long)nlist[0].n_value, &pa) == 0) 8163fbbad10Sniklas return (-1); 8173fbbad10Sniklas 8183fbbad10Sniklas errno = 0; 8193fbbad10Sniklas if (lseek(kd->pmfd, _kvm_pa2off(kd, pa), SEEK_SET) == -1 8203fbbad10Sniklas && errno != 0) { 8213fbbad10Sniklas _kvm_err(kd, 0, "cannot invalidate dump - lseek"); 8223fbbad10Sniklas return (-1); 8233fbbad10Sniklas } 8243fbbad10Sniklas pa = 0; 8253fbbad10Sniklas if (write(kd->pmfd, &pa, sizeof(pa)) != sizeof(pa)) { 8263fbbad10Sniklas _kvm_err(kd, 0, "cannot invalidate dump - write"); 8273fbbad10Sniklas return (-1); 8283fbbad10Sniklas } 8293fbbad10Sniklas return (0); 8303fbbad10Sniklas } 8313fbbad10Sniklas 832df930be7Sderaadt ssize_t 833df930be7Sderaadt kvm_read(kd, kva, buf, len) 834df930be7Sderaadt kvm_t *kd; 835df930be7Sderaadt register u_long kva; 836df930be7Sderaadt register void *buf; 837df930be7Sderaadt register size_t len; 838df930be7Sderaadt { 839df930be7Sderaadt register int cc; 840df930be7Sderaadt register void *cp; 841df930be7Sderaadt 842df930be7Sderaadt if (ISALIVE(kd)) { 843df930be7Sderaadt /* 844df930be7Sderaadt * We're using /dev/kmem. Just read straight from the 845df930be7Sderaadt * device and let the active kernel do the address translation. 846df930be7Sderaadt */ 847df930be7Sderaadt errno = 0; 8483fbbad10Sniklas if (lseek(kd->vmfd, (off_t)kva, SEEK_SET) == -1 8493fbbad10Sniklas && errno != 0) { 850df930be7Sderaadt _kvm_err(kd, 0, "invalid address (%x)", kva); 851df930be7Sderaadt return (0); 852df930be7Sderaadt } 853df930be7Sderaadt cc = read(kd->vmfd, buf, len); 854df930be7Sderaadt if (cc < 0) { 855df930be7Sderaadt _kvm_syserr(kd, 0, "kvm_read"); 856df930be7Sderaadt return (0); 857df930be7Sderaadt } else if (cc < len) 858df930be7Sderaadt _kvm_err(kd, kd->program, "short read"); 859df930be7Sderaadt return (cc); 860df930be7Sderaadt } else { 8613fbbad10Sniklas if ((kd->kcore_hdr == NULL) || (kd->cpu_hdr == NULL)) { 8623fbbad10Sniklas _kvm_err(kd, kd->program, "no valid dump header"); 8633fbbad10Sniklas return (0); 8643fbbad10Sniklas } 865df930be7Sderaadt cp = buf; 866df930be7Sderaadt while (len > 0) { 867df930be7Sderaadt u_long pa; 8683fbbad10Sniklas off_t foff; 869df930be7Sderaadt 870df930be7Sderaadt cc = _kvm_kvatop(kd, kva, &pa); 871df930be7Sderaadt if (cc == 0) 872df930be7Sderaadt return (0); 873df930be7Sderaadt if (cc > len) 874df930be7Sderaadt cc = len; 8753fbbad10Sniklas foff = _kvm_pa2off(kd, pa); 876df930be7Sderaadt errno = 0; 8773fbbad10Sniklas if (lseek(kd->pmfd, foff, SEEK_SET) == -1 8783fbbad10Sniklas && errno != 0) { 879df930be7Sderaadt _kvm_syserr(kd, 0, _PATH_MEM); 880df930be7Sderaadt break; 881df930be7Sderaadt } 882df930be7Sderaadt cc = read(kd->pmfd, cp, cc); 883df930be7Sderaadt if (cc < 0) { 884df930be7Sderaadt _kvm_syserr(kd, kd->program, "kvm_read"); 885df930be7Sderaadt break; 886df930be7Sderaadt } 887df930be7Sderaadt /* 888df930be7Sderaadt * If kvm_kvatop returns a bogus value or our core 889df930be7Sderaadt * file is truncated, we might wind up seeking beyond 890df930be7Sderaadt * the end of the core file in which case the read will 891df930be7Sderaadt * return 0 (EOF). 892df930be7Sderaadt */ 893df930be7Sderaadt if (cc == 0) 894df930be7Sderaadt break; 895df930be7Sderaadt cp = (char *)cp + cc; 896df930be7Sderaadt kva += cc; 897df930be7Sderaadt len -= cc; 898df930be7Sderaadt } 899df930be7Sderaadt return ((char *)cp - (char *)buf); 900df930be7Sderaadt } 901df930be7Sderaadt /* NOTREACHED */ 902df930be7Sderaadt } 903df930be7Sderaadt 904df930be7Sderaadt ssize_t 905df930be7Sderaadt kvm_write(kd, kva, buf, len) 906df930be7Sderaadt kvm_t *kd; 907df930be7Sderaadt register u_long kva; 908df930be7Sderaadt register const void *buf; 909df930be7Sderaadt register size_t len; 910df930be7Sderaadt { 911df930be7Sderaadt register int cc; 912df930be7Sderaadt 913df930be7Sderaadt if (ISALIVE(kd)) { 914df930be7Sderaadt /* 915df930be7Sderaadt * Just like kvm_read, only we write. 916df930be7Sderaadt */ 917df930be7Sderaadt errno = 0; 9183fbbad10Sniklas if (lseek(kd->vmfd, (off_t)kva, SEEK_SET) == -1 9193fbbad10Sniklas && errno != 0) { 920df930be7Sderaadt _kvm_err(kd, 0, "invalid address (%x)", kva); 921df930be7Sderaadt return (0); 922df930be7Sderaadt } 923df930be7Sderaadt cc = write(kd->vmfd, buf, len); 924df930be7Sderaadt if (cc < 0) { 925df930be7Sderaadt _kvm_syserr(kd, 0, "kvm_write"); 926df930be7Sderaadt return (0); 927df930be7Sderaadt } else if (cc < len) 928df930be7Sderaadt _kvm_err(kd, kd->program, "short write"); 929df930be7Sderaadt return (cc); 930df930be7Sderaadt } else { 931df930be7Sderaadt _kvm_err(kd, kd->program, 932df930be7Sderaadt "kvm_write not implemented for dead kernels"); 933df930be7Sderaadt return (0); 934df930be7Sderaadt } 935df930be7Sderaadt /* NOTREACHED */ 936df930be7Sderaadt } 937