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 49429f62a6Scgd #include <vm/vm.h> 50429f62a6Scgd #include <vm/vm_param.h> 51429f62a6Scgd #include <vm/swap_pager.h> 52429f62a6Scgd 5361f28255Scgd #include <machine/vmparam.h> 54429f62a6Scgd 55429f62a6Scgd #include <ctype.h> 56429f62a6Scgd #include <db.h> 5761f28255Scgd #include <fcntl.h> 5861f28255Scgd #include <kvm.h> 5961f28255Scgd #include <limits.h> 60429f62a6Scgd #include <nlist.h> 6161f28255Scgd #include <paths.h> 6261f28255Scgd #include <stdio.h> 63429f62a6Scgd #include <stdlib.h> 6461f28255Scgd #include <string.h> 65429f62a6Scgd #include <unistd.h> 6661f28255Scgd 67429f62a6Scgd #include "kvm_private.h" 6861f28255Scgd 69429f62a6Scgd static int kvm_dbopen __P((kvm_t *, const char *)); 70ea0119dbScgd 71429f62a6Scgd char * 72429f62a6Scgd kvm_geterr(kd) 73429f62a6Scgd kvm_t *kd; 7461f28255Scgd { 75429f62a6Scgd return (kd->errbuf); 76429f62a6Scgd } 7761f28255Scgd 78429f62a6Scgd #if __STDC__ 79429f62a6Scgd #include <stdarg.h> 80429f62a6Scgd #else 81429f62a6Scgd #include <varargs.h> 82429f62a6Scgd #endif 83429f62a6Scgd 84429f62a6Scgd /* 85429f62a6Scgd * Report an error using printf style arguments. "program" is kd->program 86429f62a6Scgd * on hard errors, and 0 on soft errors, so that under sun error emulation, 87429f62a6Scgd * only hard errors are printed out (otherwise, programs like gdb will 88429f62a6Scgd * generate tons of error messages when trying to access bogus pointers). 89429f62a6Scgd */ 90429f62a6Scgd void 91429f62a6Scgd #if __STDC__ 92429f62a6Scgd _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 93429f62a6Scgd #else 94429f62a6Scgd _kvm_err(kd, program, fmt, va_alist) 95429f62a6Scgd kvm_t *kd; 96429f62a6Scgd char *program, *fmt; 97429f62a6Scgd va_dcl 98429f62a6Scgd #endif 99429f62a6Scgd { 100429f62a6Scgd va_list ap; 101429f62a6Scgd 102429f62a6Scgd #ifdef __STDC__ 103429f62a6Scgd va_start(ap, fmt); 104429f62a6Scgd #else 105429f62a6Scgd va_start(ap); 106429f62a6Scgd #endif 107429f62a6Scgd if (program != NULL) { 108429f62a6Scgd (void)fprintf(stderr, "%s: ", program); 109429f62a6Scgd (void)vfprintf(stderr, fmt, ap); 110429f62a6Scgd (void)fputc('\n', stderr); 111429f62a6Scgd } else 112429f62a6Scgd (void)vsnprintf(kd->errbuf, 113429f62a6Scgd sizeof(kd->errbuf), (char *)fmt, ap); 114429f62a6Scgd 115429f62a6Scgd va_end(ap); 11661f28255Scgd } 117429f62a6Scgd 118429f62a6Scgd void 119429f62a6Scgd #if __STDC__ 120429f62a6Scgd _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 121429f62a6Scgd #else 122429f62a6Scgd _kvm_syserr(kd, program, fmt, va_alist) 123429f62a6Scgd kvm_t *kd; 124429f62a6Scgd char *program, *fmt; 125429f62a6Scgd va_dcl 126429f62a6Scgd #endif 127429f62a6Scgd { 128429f62a6Scgd va_list ap; 129429f62a6Scgd register int n; 130429f62a6Scgd 131429f62a6Scgd #if __STDC__ 132429f62a6Scgd va_start(ap, fmt); 133429f62a6Scgd #else 134429f62a6Scgd va_start(ap); 135429f62a6Scgd #endif 136429f62a6Scgd if (program != NULL) { 137429f62a6Scgd (void)fprintf(stderr, "%s: ", program); 138429f62a6Scgd (void)vfprintf(stderr, fmt, ap); 139429f62a6Scgd (void)fprintf(stderr, ": %s\n", strerror(errno)); 14061f28255Scgd } else { 141429f62a6Scgd register char *cp = kd->errbuf; 142429f62a6Scgd 143429f62a6Scgd (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 144429f62a6Scgd n = strlen(cp); 145429f62a6Scgd (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 146429f62a6Scgd strerror(errno)); 147429f62a6Scgd } 148429f62a6Scgd va_end(ap); 149429f62a6Scgd } 150429f62a6Scgd 151429f62a6Scgd void * 152429f62a6Scgd _kvm_malloc(kd, n) 153429f62a6Scgd register kvm_t *kd; 154429f62a6Scgd register size_t n; 155429f62a6Scgd { 156429f62a6Scgd void *p; 157429f62a6Scgd 158429f62a6Scgd if ((p = malloc(n)) == NULL) 159429f62a6Scgd _kvm_err(kd, kd->program, strerror(errno)); 160429f62a6Scgd return (p); 161429f62a6Scgd } 162429f62a6Scgd 163429f62a6Scgd static kvm_t * 164429f62a6Scgd _kvm_open(kd, uf, mf, sf, flag, errout) 165429f62a6Scgd register kvm_t *kd; 166429f62a6Scgd const char *uf; 167429f62a6Scgd const char *mf; 168429f62a6Scgd const char *sf; 169429f62a6Scgd int flag; 170429f62a6Scgd char *errout; 171429f62a6Scgd { 172429f62a6Scgd struct stat st; 173429f62a6Scgd 174c3049714Smycroft kd->db = 0; 175429f62a6Scgd kd->pmfd = -1; 176c3049714Smycroft kd->vmfd = -1; 177429f62a6Scgd kd->swfd = -1; 178429f62a6Scgd kd->nlfd = -1; 179429f62a6Scgd kd->procbase = 0; 180b707f8aaSmycroft kd->nbpg = getpagesize(); 181b707f8aaSmycroft kd->swapspc = 0; 182429f62a6Scgd kd->argspc = 0; 183*6506fa2bSmycroft kd->argbuf = 0; 184429f62a6Scgd kd->argv = 0; 185c3049714Smycroft kd->vmst = 0; 186c3049714Smycroft kd->vm_page_buckets = 0; 187429f62a6Scgd 188429f62a6Scgd if (uf == 0) 189429f62a6Scgd uf = _PATH_UNIX; 190429f62a6Scgd else if (strlen(uf) >= MAXPATHLEN) { 191429f62a6Scgd _kvm_err(kd, kd->program, "exec file name too long"); 19261f28255Scgd goto failed; 19361f28255Scgd } 194429f62a6Scgd if (flag & ~O_RDWR) { 195429f62a6Scgd _kvm_err(kd, kd->program, "bad flags arg"); 196429f62a6Scgd goto failed; 197429f62a6Scgd } 198429f62a6Scgd if (mf == 0) 199429f62a6Scgd mf = _PATH_MEM; 200429f62a6Scgd if (sf == 0) 201429f62a6Scgd sf = _PATH_DRUM; 202429f62a6Scgd 203429f62a6Scgd if ((kd->pmfd = open(mf, flag, 0)) < 0) { 204429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", mf); 205429f62a6Scgd goto failed; 206429f62a6Scgd } 207429f62a6Scgd if (fstat(kd->pmfd, &st) < 0) { 208429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", mf); 209429f62a6Scgd goto failed; 210429f62a6Scgd } 211429f62a6Scgd if (S_ISCHR(st.st_mode)) { 21261f28255Scgd /* 213429f62a6Scgd * If this is a character special device, then check that 214429f62a6Scgd * it's /dev/mem. If so, open kmem too. (Maybe we should 215429f62a6Scgd * make it work for either /dev/mem or /dev/kmem -- in either 216429f62a6Scgd * case you're working with a live kernel.) 21761f28255Scgd */ 218429f62a6Scgd if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */ 219429f62a6Scgd _kvm_err(kd, kd->program, 220429f62a6Scgd "%s: not physical memory device", mf); 22161f28255Scgd goto failed; 22261f28255Scgd } 223429f62a6Scgd if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 224429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 225429f62a6Scgd goto failed; 226429f62a6Scgd } 227429f62a6Scgd if ((kd->swfd = open(sf, flag, 0)) < 0) { 228429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", sf); 229429f62a6Scgd goto failed; 230429f62a6Scgd } 231429f62a6Scgd /* 232429f62a6Scgd * Open kvm nlist database. We go ahead and do this 233429f62a6Scgd * here so that we don't have to hold on to the vmunix 234429f62a6Scgd * path name. Since a kvm application will surely do 235429f62a6Scgd * a kvm_nlist(), this probably won't be a wasted effort. 236429f62a6Scgd * If the database cannot be opened, open the namelist 237429f62a6Scgd * argument so we revert to slow nlist() calls. 238429f62a6Scgd */ 239429f62a6Scgd if (kvm_dbopen(kd, uf) < 0 && 240429f62a6Scgd (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 241429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", uf); 242429f62a6Scgd goto failed; 243429f62a6Scgd } 244429f62a6Scgd } else { 245429f62a6Scgd /* 246429f62a6Scgd * This is a crash dump. 247429f62a6Scgd * Initalize the virtual address translation machinery, 248429f62a6Scgd * but first setup the namelist fd. 249429f62a6Scgd */ 250429f62a6Scgd if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 251429f62a6Scgd _kvm_syserr(kd, kd->program, "%s", uf); 252429f62a6Scgd goto failed; 253429f62a6Scgd } 254429f62a6Scgd if (_kvm_initvtop(kd) < 0) 255429f62a6Scgd goto failed; 256429f62a6Scgd } 257429f62a6Scgd return (kd); 25861f28255Scgd failed: 259429f62a6Scgd /* 260429f62a6Scgd * Copy out the error if doing sane error semantics. 261429f62a6Scgd */ 262429f62a6Scgd if (errout != 0) 263429f62a6Scgd strcpy(errout, kd->errbuf); 264429f62a6Scgd (void)kvm_close(kd); 265429f62a6Scgd return (0); 26661f28255Scgd } 26761f28255Scgd 268429f62a6Scgd kvm_t * 269429f62a6Scgd kvm_openfiles(uf, mf, sf, flag, errout) 270429f62a6Scgd const char *uf; 271429f62a6Scgd const char *mf; 272429f62a6Scgd const char *sf; 273429f62a6Scgd int flag; 274429f62a6Scgd char *errout; 27561f28255Scgd { 276429f62a6Scgd register kvm_t *kd; 277429f62a6Scgd 278429f62a6Scgd if ((kd = malloc(sizeof(*kd))) == NULL) { 279429f62a6Scgd (void)strcpy(errout, strerror(errno)); 280429f62a6Scgd return (0); 281429f62a6Scgd } 282429f62a6Scgd kd->program = 0; 283429f62a6Scgd return (_kvm_open(kd, uf, mf, sf, flag, errout)); 284429f62a6Scgd } 285429f62a6Scgd 286429f62a6Scgd kvm_t * 287429f62a6Scgd kvm_open(uf, mf, sf, flag, program) 288429f62a6Scgd const char *uf; 289429f62a6Scgd const char *mf; 290429f62a6Scgd const char *sf; 291429f62a6Scgd int flag; 292429f62a6Scgd const char *program; 293429f62a6Scgd { 294429f62a6Scgd register kvm_t *kd; 295429f62a6Scgd 296429f62a6Scgd if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) { 297429f62a6Scgd (void)fprintf(stderr, "%s: %s\n", strerror(errno)); 298429f62a6Scgd return (0); 299429f62a6Scgd } 300429f62a6Scgd kd->program = program; 301429f62a6Scgd return (_kvm_open(kd, uf, mf, sf, flag, NULL)); 302429f62a6Scgd } 303429f62a6Scgd 304429f62a6Scgd int 305429f62a6Scgd kvm_close(kd) 306429f62a6Scgd kvm_t *kd; 307429f62a6Scgd { 308429f62a6Scgd register int error = 0; 309429f62a6Scgd 310429f62a6Scgd if (kd->pmfd >= 0) 311429f62a6Scgd error |= close(kd->pmfd); 312429f62a6Scgd if (kd->vmfd >= 0) 313429f62a6Scgd error |= close(kd->vmfd); 314429f62a6Scgd if (kd->nlfd >= 0) 315429f62a6Scgd error |= close(kd->nlfd); 316429f62a6Scgd if (kd->swfd >= 0) 317429f62a6Scgd error |= close(kd->swfd); 318429f62a6Scgd if (kd->db != 0) 319429f62a6Scgd error |= (kd->db->close)(kd->db); 320429f62a6Scgd if (kd->vmst) 321429f62a6Scgd _kvm_freevtop(kd); 322429f62a6Scgd if (kd->procbase != 0) 323429f62a6Scgd free((void *)kd->procbase); 324b707f8aaSmycroft if (kd->swapspc != 0) 325b707f8aaSmycroft free((void *)kd->swapspc); 326b707f8aaSmycroft if (kd->argspc != 0) 327b707f8aaSmycroft free((void *)kd->argspc); 328*6506fa2bSmycroft if (kd->argbuf != 0) 329*6506fa2bSmycroft free((void *)kd->argbuf); 330429f62a6Scgd if (kd->argv != 0) 331429f62a6Scgd free((void *)kd->argv); 332429f62a6Scgd free((void *)kd); 33361f28255Scgd 33461f28255Scgd return (0); 33561f28255Scgd } 33661f28255Scgd 337429f62a6Scgd /* 338429f62a6Scgd * Set up state necessary to do queries on the kernel namelist 339429f62a6Scgd * data base. If the data base is out-of-data/incompatible with 340429f62a6Scgd * given executable, set up things so we revert to standard nlist call. 341429f62a6Scgd * Only called for live kernels. Return 0 on success, -1 on failure. 342429f62a6Scgd */ 343429f62a6Scgd static int 344429f62a6Scgd kvm_dbopen(kd, uf) 345429f62a6Scgd kvm_t *kd; 346429f62a6Scgd const char *uf; 34761f28255Scgd { 348429f62a6Scgd char *cp; 349429f62a6Scgd DBT rec; 350429f62a6Scgd int dbversionlen; 351429f62a6Scgd struct nlist nitem; 35261f28255Scgd char dbversion[_POSIX2_LINE_MAX]; 35361f28255Scgd char kversion[_POSIX2_LINE_MAX]; 354429f62a6Scgd char dbname[MAXPATHLEN]; 35561f28255Scgd 356429f62a6Scgd if ((cp = rindex(uf, '/')) != 0) 357429f62a6Scgd uf = cp + 1; 358429f62a6Scgd 359429f62a6Scgd (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); 360429f62a6Scgd kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); 361429f62a6Scgd if (kd->db == 0) 36261f28255Scgd return (-1); 36361f28255Scgd /* 36461f28255Scgd * read version out of database 36561f28255Scgd */ 366429f62a6Scgd rec.data = VRS_KEY; 367429f62a6Scgd rec.size = sizeof(VRS_KEY) - 1; 368429f62a6Scgd if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 369429f62a6Scgd goto close; 370429f62a6Scgd if (rec.data == 0 || rec.size > sizeof(dbversion)) 371429f62a6Scgd goto close; 372429f62a6Scgd 373429f62a6Scgd bcopy(rec.data, dbversion, rec.size); 374429f62a6Scgd dbversionlen = rec.size; 37561f28255Scgd /* 376429f62a6Scgd * Read version string from kernel memory. 377429f62a6Scgd * Since we are dealing with a live kernel, we can call kvm_read() 378429f62a6Scgd * at this point. 37961f28255Scgd */ 380429f62a6Scgd rec.data = VRS_SYM; 381429f62a6Scgd rec.size = sizeof(VRS_SYM) - 1; 382429f62a6Scgd if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 383429f62a6Scgd goto close; 384429f62a6Scgd if (rec.data == 0 || rec.size != sizeof(struct nlist)) 385429f62a6Scgd goto close; 386429f62a6Scgd bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem)); 387429f62a6Scgd if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) != 388429f62a6Scgd dbversionlen) 389429f62a6Scgd goto close; 39061f28255Scgd /* 391429f62a6Scgd * If they match, we win - otherwise clear out kd->db so 392429f62a6Scgd * we revert to slow nlist(). 39361f28255Scgd */ 394429f62a6Scgd if (bcmp(dbversion, kversion, dbversionlen) == 0) 395429f62a6Scgd return (0); 396429f62a6Scgd close: 397429f62a6Scgd (void)(kd->db->close)(kd->db); 398429f62a6Scgd kd->db = 0; 399429f62a6Scgd 40061f28255Scgd return (-1); 40161f28255Scgd } 40261f28255Scgd 4035089c413Scgd int 404429f62a6Scgd kvm_nlist(kd, nl) 405429f62a6Scgd kvm_t *kd; 406429f62a6Scgd struct nlist *nl; 4075089c413Scgd { 408429f62a6Scgd register struct nlist *p; 409429f62a6Scgd register int nvalid; 4105089c413Scgd 411429f62a6Scgd /* 412429f62a6Scgd * If we can't use the data base, revert to the 413429f62a6Scgd * slow library call. 414429f62a6Scgd */ 415429f62a6Scgd if (kd->db == 0) 416429f62a6Scgd return (__fdnlist(kd->nlfd, nl)); 4175089c413Scgd 418429f62a6Scgd /* 419429f62a6Scgd * We can use the kvm data base. Go through each nlist entry 420429f62a6Scgd * and look it up with a db query. 421429f62a6Scgd */ 422429f62a6Scgd nvalid = 0; 423429f62a6Scgd for (p = nl; p->n_name && p->n_name[0]; ++p) { 424429f62a6Scgd register int len; 425429f62a6Scgd DBT rec; 4265089c413Scgd 427429f62a6Scgd if ((len = strlen(p->n_name)) > 4096) { 428429f62a6Scgd /* sanity */ 429429f62a6Scgd _kvm_err(kd, kd->program, "symbol too large"); 430429f62a6Scgd return (-1); 43122eaa1f2Smycroft } 432429f62a6Scgd rec.data = p->n_name; 433429f62a6Scgd rec.size = len; 434429f62a6Scgd if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0)) 435429f62a6Scgd continue; 436429f62a6Scgd if (rec.data == 0 || rec.size != sizeof(struct nlist)) 437429f62a6Scgd continue; 438429f62a6Scgd ++nvalid; 439429f62a6Scgd /* 440429f62a6Scgd * Avoid alignment issues. 441429f62a6Scgd */ 442429f62a6Scgd bcopy((char *)&((struct nlist *)rec.data)->n_type, 443429f62a6Scgd (char *)&p->n_type, 444429f62a6Scgd sizeof(p->n_type)); 445429f62a6Scgd bcopy((char *)&((struct nlist *)rec.data)->n_value, 446429f62a6Scgd (char *)&p->n_value, 447429f62a6Scgd sizeof(p->n_value)); 4485089c413Scgd } 449429f62a6Scgd /* 450429f62a6Scgd * Return the number of entries that weren't found. 451429f62a6Scgd */ 452429f62a6Scgd return ((p - nl) - nvalid); 453db3323c9Smycroft } 4545089c413Scgd 455429f62a6Scgd ssize_t 456429f62a6Scgd kvm_read(kd, kva, buf, len) 457429f62a6Scgd kvm_t *kd; 458429f62a6Scgd register u_long kva; 459429f62a6Scgd register void *buf; 460429f62a6Scgd register size_t len; 4615089c413Scgd { 462429f62a6Scgd register int cc; 463429f62a6Scgd register void *cp; 4645089c413Scgd 465429f62a6Scgd if (ISALIVE(kd)) { 466429f62a6Scgd /* 467429f62a6Scgd * We're using /dev/kmem. Just read straight from the 468429f62a6Scgd * device and let the active kernel do the address translation. 469429f62a6Scgd */ 470429f62a6Scgd errno = 0; 471429f62a6Scgd if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 472429f62a6Scgd _kvm_err(kd, 0, "invalid address (%x)", kva); 47361f28255Scgd return (0); 47461f28255Scgd } 475429f62a6Scgd cc = read(kd->vmfd, buf, len); 476429f62a6Scgd if (cc < 0) { 477429f62a6Scgd _kvm_syserr(kd, 0, "kvm_read"); 478429f62a6Scgd return (0); 479429f62a6Scgd } else if (cc < len) 480429f62a6Scgd _kvm_err(kd, kd->program, "short read"); 481429f62a6Scgd return (cc); 482429f62a6Scgd } else { 483429f62a6Scgd cp = buf; 484429f62a6Scgd while (len > 0) { 485429f62a6Scgd u_long pa; 48661f28255Scgd 487429f62a6Scgd cc = _kvm_kvatop(kd, kva, &pa); 488429f62a6Scgd if (cc == 0) 489429f62a6Scgd return (0); 490429f62a6Scgd if (cc > len) 491429f62a6Scgd cc = len; 492429f62a6Scgd errno = 0; 493429f62a6Scgd if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) { 494429f62a6Scgd _kvm_syserr(kd, 0, _PATH_MEM); 495ea0119dbScgd break; 496669b9e50Smycroft } 497429f62a6Scgd cc = read(kd->pmfd, cp, cc); 498429f62a6Scgd if (cc < 0) { 499429f62a6Scgd _kvm_syserr(kd, kd->program, "kvm_read"); 500ea0119dbScgd break; 501ea0119dbScgd } 5027b1fbb1cSpk /* 503429f62a6Scgd * If kvm_kvatop returns a bogus value or our core 504429f62a6Scgd * file is truncated, we might wind up seeking beyond 505429f62a6Scgd * the end of the core file in which case the read will 506429f62a6Scgd * return 0 (EOF). 5077b1fbb1cSpk */ 508429f62a6Scgd if (cc == 0) 509429f62a6Scgd break; 510429f62a6Scgd (char *)cp += cc; 511429f62a6Scgd kva += cc; 512429f62a6Scgd len -= cc; 513429f62a6Scgd } 514429f62a6Scgd return ((char *)cp - (char *)buf); 515429f62a6Scgd } 516429f62a6Scgd /* NOTREACHED */ 517429f62a6Scgd } 5187b1fbb1cSpk 519429f62a6Scgd ssize_t 520429f62a6Scgd kvm_write(kd, kva, buf, len) 521429f62a6Scgd kvm_t *kd; 522429f62a6Scgd register u_long kva; 523429f62a6Scgd register const void *buf; 524429f62a6Scgd register size_t len; 525429f62a6Scgd { 526429f62a6Scgd register int cc; 5277b1fbb1cSpk 528429f62a6Scgd if (ISALIVE(kd)) { 5297b1fbb1cSpk /* 530429f62a6Scgd * Just like kvm_read, only we write. 5317b1fbb1cSpk */ 532429f62a6Scgd errno = 0; 533429f62a6Scgd if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 534429f62a6Scgd _kvm_err(kd, 0, "invalid address (%x)", kva); 535429f62a6Scgd return (0); 5367b1fbb1cSpk } 537429f62a6Scgd cc = write(kd->vmfd, buf, len); 538429f62a6Scgd if (cc < 0) { 539429f62a6Scgd _kvm_syserr(kd, 0, "kvm_write"); 540429f62a6Scgd return (0); 541429f62a6Scgd } else if (cc < len) 542429f62a6Scgd _kvm_err(kd, kd->program, "short write"); 543429f62a6Scgd return (cc); 544429f62a6Scgd } else { 545429f62a6Scgd _kvm_err(kd, kd->program, 546429f62a6Scgd "kvm_write not implemented for dead kernels"); 547429f62a6Scgd return (0); 5487b1fbb1cSpk } 549429f62a6Scgd /* NOTREACHED */ 55061f28255Scgd } 551