kvm.c revision 250230
1178173Simp/*- 2178173Simp * Copyright (c) 1989, 1992, 1993 3178173Simp * The Regents of the University of California. All rights reserved. 4178173Simp * 5178173Simp * This code is derived from software developed by the Computer Systems 6178173Simp * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7178173Simp * BG 91-66 and contributed to Berkeley. 8178173Simp * 9178173Simp * Redistribution and use in source and binary forms, with or without 10178173Simp * modification, are permitted provided that the following conditions 11178173Simp * are met: 12178173Simp * 1. Redistributions of source code must retain the above copyright 13178173Simp * notice, this list of conditions and the following disclaimer. 14178173Simp * 2. Redistributions in binary form must reproduce the above copyright 15178173Simp * notice, this list of conditions and the following disclaimer in the 16178173Simp * documentation and/or other materials provided with the distribution. 17178173Simp * 4. Neither the name of the University nor the names of its contributors 18178173Simp * may be used to endorse or promote products derived from this software 19178173Simp * without specific prior written permission. 20178173Simp * 21178173Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22178173Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178173Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178173Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25178173Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178173Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178173Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178173Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178173Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178173Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178173Simp * SUCH DAMAGE. 32178173Simp */ 33178173Simp 34178173Simp#include <sys/cdefs.h> 35178173Simp__FBSDID("$FreeBSD: head/lib/libkvm/kvm.c 250230 2013-05-04 09:47:51Z jilles $"); 36178173Simp 37178173Simp#if defined(LIBC_SCCS) && !defined(lint) 38178173Simp#if 0 39178173Simpstatic char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 40178173Simp#endif 41178173Simp#endif /* LIBC_SCCS and not lint */ 42178173Simp 43178173Simp#include <sys/param.h> 44178173Simp 45178173Simp#define _WANT_VNET 46178173Simp 47178173Simp#include <sys/user.h> 48178173Simp#include <sys/proc.h> 49178173Simp#include <sys/ioctl.h> 50178173Simp#include <sys/stat.h> 51178173Simp#include <sys/sysctl.h> 52178173Simp#include <sys/linker.h> 53178173Simp#include <sys/pcpu.h> 54178173Simp 55178173Simp#include <net/vnet.h> 56178173Simp 57178173Simp#include <vm/vm.h> 58178173Simp#include <vm/vm_param.h> 59178173Simp 60178173Simp#include <machine/vmparam.h> 61178173Simp 62178173Simp#include <ctype.h> 63178173Simp#include <fcntl.h> 64178173Simp#include <kvm.h> 65178173Simp#include <limits.h> 66178173Simp#include <nlist.h> 67178173Simp#include <paths.h> 68178173Simp#include <stdio.h> 69178173Simp#include <stdlib.h> 70178173Simp#include <string.h> 71178173Simp#include <strings.h> 72178173Simp#include <unistd.h> 73178173Simp 74178173Simp#include "kvm_private.h" 75178173Simp 76178173Simp/* from src/lib/libc/gen/nlist.c */ 77178173Simpint __fdnlist(int, struct nlist *); 78178173Simp 79178173Simpchar * 80178173Simpkvm_geterr(kvm_t *kd) 81178173Simp{ 82178173Simp return (kd->errbuf); 83178173Simp} 84178173Simp 85178173Simp#include <stdarg.h> 86178173Simp 87178173Simp/* 88178173Simp * Report an error using printf style arguments. "program" is kd->program 89178173Simp * on hard errors, and 0 on soft errors, so that under sun error emulation, 90178173Simp * only hard errors are printed out (otherwise, programs like gdb will 91178173Simp * generate tons of error messages when trying to access bogus pointers). 92178173Simp */ 93178173Simpvoid 94178173Simp_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 95178173Simp{ 96178173Simp va_list ap; 97178173Simp 98178173Simp va_start(ap, fmt); 99178173Simp if (program != NULL) { 100178173Simp (void)fprintf(stderr, "%s: ", program); 101178173Simp (void)vfprintf(stderr, fmt, ap); 102178173Simp (void)fputc('\n', stderr); 103178173Simp } else 104178173Simp (void)vsnprintf(kd->errbuf, 105178173Simp sizeof(kd->errbuf), fmt, ap); 106178173Simp 107178173Simp va_end(ap); 108178173Simp} 109178173Simp 110178173Simpvoid 111178173Simp_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 112178173Simp{ 113178173Simp va_list ap; 114178173Simp int n; 115178173Simp 116178173Simp va_start(ap, fmt); 117178173Simp if (program != NULL) { 118178173Simp (void)fprintf(stderr, "%s: ", program); 119178173Simp (void)vfprintf(stderr, fmt, ap); 120178173Simp (void)fprintf(stderr, ": %s\n", strerror(errno)); 121178173Simp } else { 122178173Simp char *cp = kd->errbuf; 123178173Simp 124178173Simp (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); 125178173Simp n = strlen(cp); 126178173Simp (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 127178173Simp strerror(errno)); 128178173Simp } 129178173Simp va_end(ap); 130178173Simp} 131178173Simp 132178173Simpvoid * 133178173Simp_kvm_malloc(kvm_t *kd, size_t n) 134178173Simp{ 135178173Simp void *p; 136178173Simp 137178173Simp if ((p = calloc(n, sizeof(char))) == NULL) 138178173Simp _kvm_err(kd, kd->program, "can't allocate %zu bytes: %s", 139178173Simp n, strerror(errno)); 140178173Simp return (p); 141178173Simp} 142178173Simp 143178173Simpstatic kvm_t * 144178173Simp_kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) 145178173Simp{ 146178173Simp struct stat st; 147178173Simp 148178173Simp kd->vmfd = -1; 149178173Simp kd->pmfd = -1; 150178173Simp kd->nlfd = -1; 151178173Simp kd->vmst = 0; 152178173Simp kd->procbase = 0; 153178173Simp kd->argspc = 0; 154178173Simp kd->argv = 0; 155178173Simp 156178173Simp if (uf == 0) 157178173Simp uf = getbootfile(); 158178173Simp else if (strlen(uf) >= MAXPATHLEN) { 159178173Simp _kvm_err(kd, kd->program, "exec file name too long"); 160178173Simp goto failed; 161178173Simp } 162178173Simp if (flag & ~O_RDWR) { 163178173Simp _kvm_err(kd, kd->program, "bad flags arg"); 164178173Simp goto failed; 165178173Simp } 166178173Simp if (mf == 0) 167178173Simp mf = _PATH_MEM; 168178173Simp 169178173Simp if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { 170178173Simp _kvm_syserr(kd, kd->program, "%s", mf); 171178173Simp goto failed; 172178173Simp } 173178173Simp if (fstat(kd->pmfd, &st) < 0) { 174178173Simp _kvm_syserr(kd, kd->program, "%s", mf); 175178173Simp goto failed; 176178173Simp } 177178173Simp if (S_ISREG(st.st_mode) && st.st_size <= 0) { 178178173Simp errno = EINVAL; 179178173Simp _kvm_syserr(kd, kd->program, "empty file"); 180178173Simp goto failed; 181178173Simp } 182178173Simp if (S_ISCHR(st.st_mode)) { 183178173Simp /* 184178173Simp * If this is a character special device, then check that 185178173Simp * it's /dev/mem. If so, open kmem too. (Maybe we should 186178173Simp * make it work for either /dev/mem or /dev/kmem -- in either 187178173Simp * case you're working with a live kernel.) 188178173Simp */ 189178173Simp if (strcmp(mf, _PATH_DEVNULL) == 0) { 190178173Simp kd->vmfd = open(_PATH_DEVNULL, O_RDONLY); 191178173Simp return (kd); 192178173Simp } else if (strcmp(mf, _PATH_MEM) == 0) { 193178173Simp if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC)) < 194178173Simp 0) { 195178173Simp _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 196178173Simp goto failed; 197178173Simp } 198178173Simp return (kd); 199178173Simp } 200178173Simp } 201178173Simp /* 202178173Simp * This is a crash dump. 203178173Simp * Initialize the virtual address translation machinery, 204178173Simp * but first setup the namelist fd. 205178173Simp */ 206178173Simp if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { 207178173Simp _kvm_syserr(kd, kd->program, "%s", uf); 208178173Simp goto failed; 209178173Simp } 210178173Simp if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0) 211178173Simp kd->rawdump = 1; 212178173Simp if (_kvm_initvtop(kd) < 0) 213178173Simp goto failed; 214178173Simp return (kd); 215178173Simpfailed: 216178173Simp /* 217178173Simp * Copy out the error if doing sane error semantics. 218178173Simp */ 219178173Simp if (errout != 0) 220178173Simp strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 221178173Simp (void)kvm_close(kd); 222178173Simp return (0); 223178173Simp} 224178173Simp 225178173Simpkvm_t * 226178173Simpkvm_openfiles(const char *uf, const char *mf, const char *sf __unused, int flag, 227178173Simp char *errout) 228178173Simp{ 229178173Simp kvm_t *kd; 230178173Simp 231178173Simp if ((kd = calloc(1, sizeof(*kd))) == NULL) { 232178173Simp (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 233178173Simp return (0); 234178173Simp } 235178173Simp kd->program = 0; 236178173Simp return (_kvm_open(kd, uf, mf, flag, errout)); 237178173Simp} 238178173Simp 239178173Simpkvm_t * 240178173Simpkvm_open(const char *uf, const char *mf, const char *sf __unused, int flag, 241178173Simp const char *errstr) 242178173Simp{ 243178173Simp kvm_t *kd; 244178173Simp 245178173Simp if ((kd = calloc(1, sizeof(*kd))) == NULL) { 246178173Simp if (errstr != NULL) 247178173Simp (void)fprintf(stderr, "%s: %s\n", 248178173Simp errstr, strerror(errno)); 249178173Simp return (0); 250178173Simp } 251178173Simp kd->program = errstr; 252178173Simp return (_kvm_open(kd, uf, mf, flag, NULL)); 253178173Simp} 254178173Simp 255178173Simpint 256178173Simpkvm_close(kvm_t *kd) 257178173Simp{ 258178173Simp int error = 0; 259178173Simp 260178173Simp if (kd->pmfd >= 0) 261178173Simp error |= close(kd->pmfd); 262178173Simp if (kd->vmfd >= 0) 263178173Simp error |= close(kd->vmfd); 264178173Simp if (kd->nlfd >= 0) 265178173Simp error |= close(kd->nlfd); 266178173Simp if (kd->vmst) 267178173Simp _kvm_freevtop(kd); 268178173Simp if (kd->procbase != 0) 269178173Simp free((void *)kd->procbase); 270178173Simp if (kd->argbuf != 0) 271178173Simp free((void *) kd->argbuf); 272178173Simp if (kd->argspc != 0) 273178173Simp free((void *) kd->argspc); 274178173Simp if (kd->argv != 0) 275178173Simp free((void *)kd->argv); 276178173Simp free((void *)kd); 277178173Simp 278178173Simp return (0); 279178173Simp} 280178173Simp 281178173Simp/* 282178173Simp * Walk the list of unresolved symbols, generate a new list and prefix the 283178173Simp * symbol names, try again, and merge back what we could resolve. 284178173Simp */ 285178173Simpstatic int 286178173Simpkvm_fdnlist_prefix(kvm_t *kd, struct nlist *nl, int missing, const char *prefix, 287178173Simp uintptr_t (*validate_fn)(kvm_t *, uintptr_t)) 288178173Simp{ 289178173Simp struct nlist *n, *np, *p; 290178173Simp char *cp, *ce; 291178173Simp const char *ccp; 292178173Simp size_t len; 293178173Simp int slen, unresolved; 294178173Simp 295178173Simp /* 296178173Simp * Calculate the space we need to malloc for nlist and names. 297178173Simp * We are going to store the name twice for later lookups: once 298178173Simp * with the prefix and once the unmodified name delmited by \0. 299178173Simp */ 300178173Simp len = 0; 301178173Simp unresolved = 0; 302178173Simp for (p = nl; p->n_name && p->n_name[0]; ++p) { 303178173Simp if (p->n_type != N_UNDF) 304178173Simp continue; 305178173Simp len += sizeof(struct nlist) + strlen(prefix) + 306178173Simp 2 * (strlen(p->n_name) + 1); 307178173Simp unresolved++; 308178173Simp } 309178173Simp if (unresolved == 0) 310178173Simp return (unresolved); 311178173Simp /* Add space for the terminating nlist entry. */ 312178173Simp len += sizeof(struct nlist); 313178173Simp unresolved++; 314178173Simp 315178173Simp /* Alloc one chunk for (nlist, [names]) and setup pointers. */ 316178173Simp n = np = malloc(len); 317178173Simp bzero(n, len); 318178173Simp if (n == NULL) 319178173Simp return (missing); 320178173Simp cp = ce = (char *)np; 321178173Simp cp += unresolved * sizeof(struct nlist); 322178173Simp ce += len; 323178173Simp 324178173Simp /* Generate shortened nlist with special prefix. */ 325178173Simp unresolved = 0; 326178173Simp for (p = nl; p->n_name && p->n_name[0]; ++p) { 327178173Simp if (p->n_type != N_UNDF) 328178173Simp continue; 329178173Simp bcopy(p, np, sizeof(struct nlist)); 330178173Simp /* Save the new\0orig. name so we can later match it again. */ 331178173Simp slen = snprintf(cp, ce - cp, "%s%s%c%s", prefix, 332178173Simp (prefix[0] != '\0' && p->n_name[0] == '_') ? 333178173Simp (p->n_name + 1) : p->n_name, '\0', p->n_name); 334178173Simp if (slen < 0 || slen >= ce - cp) 335178173Simp continue; 336178173Simp np->n_name = cp; 337178173Simp cp += slen + 1; 338178173Simp np++; 339178173Simp unresolved++; 340178173Simp } 341178173Simp 342178173Simp /* Do lookup on the reduced list. */ 343178173Simp np = n; 344178173Simp unresolved = __fdnlist(kd->nlfd, np); 345178173Simp 346178173Simp /* Check if we could resolve further symbols and update the list. */ 347178173Simp if (unresolved >= 0 && unresolved < missing) { 348178173Simp /* Find the first freshly resolved entry. */ 349178173Simp for (; np->n_name && np->n_name[0]; np++) 350178173Simp if (np->n_type != N_UNDF) 351178173Simp break; 352178173Simp /* 353178173Simp * The lists are both in the same order, 354178173Simp * so we can walk them in parallel. 355178173Simp */ 356178173Simp for (p = nl; np->n_name && np->n_name[0] && 357178173Simp p->n_name && p->n_name[0]; ++p) { 358178173Simp if (p->n_type != N_UNDF) 359178173Simp continue; 360178173Simp /* Skip expanded name and compare to orig. one. */ 361178173Simp ccp = np->n_name + strlen(np->n_name) + 1; 362178173Simp if (strcmp(ccp, p->n_name) != 0) 363178173Simp continue; 364178173Simp /* Update nlist with new, translated results. */ 365178173Simp p->n_type = np->n_type; 366178173Simp p->n_other = np->n_other; 367178173Simp p->n_desc = np->n_desc; 368178173Simp if (validate_fn) 369178173Simp p->n_value = (*validate_fn)(kd, np->n_value); 370178173Simp else 371178173Simp p->n_value = np->n_value; 372178173Simp missing--; 373178173Simp /* Find next freshly resolved entry. */ 374178173Simp for (np++; np->n_name && np->n_name[0]; np++) 375178173Simp if (np->n_type != N_UNDF) 376178173Simp break; 377178173Simp } 378178173Simp } 379178173Simp /* We could assert missing = unresolved here. */ 380178173Simp 381178173Simp free(n); 382178173Simp return (unresolved); 383178173Simp} 384178173Simp 385178173Simpint 386178173Simp_kvm_nlist(kvm_t *kd, struct nlist *nl, int initialize) 387178173Simp{ 388178173Simp struct nlist *p; 389178173Simp int nvalid; 390178173Simp struct kld_sym_lookup lookup; 391178173Simp int error; 392178173Simp const char *prefix = ""; 393178173Simp char symname[1024]; /* XXX-BZ symbol name length limit? */ 394178173Simp int tried_vnet, tried_dpcpu; 395178173Simp 396178173Simp /* 397178173Simp * If we can't use the kld symbol lookup, revert to the 398178173Simp * slow library call. 399178173Simp */ 400178173Simp if (!ISALIVE(kd)) { 401178173Simp error = __fdnlist(kd->nlfd, nl); 402178173Simp if (error <= 0) /* Hard error or success. */ 403178173Simp return (error); 404178173Simp 405178173Simp if (_kvm_vnet_initialized(kd, initialize)) 406178173Simp error = kvm_fdnlist_prefix(kd, nl, error, 407178173Simp VNET_SYMPREFIX, _kvm_vnet_validaddr); 408178173Simp 409178173Simp if (error > 0 && _kvm_dpcpu_initialized(kd, initialize)) 410178173Simp error = kvm_fdnlist_prefix(kd, nl, error, 411178173Simp DPCPU_SYMPREFIX, _kvm_dpcpu_validaddr); 412178173Simp 413178173Simp return (error); 414178173Simp } 415178173Simp 416178173Simp /* 417178173Simp * We can use the kld lookup syscall. Go through each nlist entry 418178173Simp * and look it up with a kldsym(2) syscall. 419178173Simp */ 420178173Simp nvalid = 0; 421178173Simp tried_vnet = 0; 422178173Simp tried_dpcpu = 0; 423178173Simpagain: 424178173Simp for (p = nl; p->n_name && p->n_name[0]; ++p) { 425178173Simp if (p->n_type != N_UNDF) 426178173Simp continue; 427178173Simp 428178173Simp lookup.version = sizeof(lookup); 429178173Simp lookup.symvalue = 0; 430178173Simp lookup.symsize = 0; 431178173Simp 432178173Simp error = snprintf(symname, sizeof(symname), "%s%s", prefix, 433178173Simp (prefix[0] != '\0' && p->n_name[0] == '_') ? 434178173Simp (p->n_name + 1) : p->n_name); 435178173Simp if (error < 0 || error >= (int)sizeof(symname)) 436178173Simp continue; 437178173Simp lookup.symname = symname; 438178173Simp if (lookup.symname[0] == '_') 439178173Simp lookup.symname++; 440178173Simp 441178173Simp if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 442178173Simp p->n_type = N_TEXT; 443178173Simp p->n_other = 0; 444178173Simp p->n_desc = 0; 445178173Simp if (_kvm_vnet_initialized(kd, initialize) && 446178173Simp strcmp(prefix, VNET_SYMPREFIX) == 0) 447178173Simp p->n_value = 448178173Simp _kvm_vnet_validaddr(kd, lookup.symvalue); 449178173Simp else if (_kvm_dpcpu_initialized(kd, initialize) && 450178173Simp strcmp(prefix, DPCPU_SYMPREFIX) == 0) 451178173Simp p->n_value = 452178173Simp _kvm_dpcpu_validaddr(kd, lookup.symvalue); 453178173Simp else 454178173Simp p->n_value = lookup.symvalue; 455178173Simp ++nvalid; 456178173Simp /* lookup.symsize */ 457178173Simp } 458178173Simp } 459178173Simp 460178173Simp /* 461178173Simp * Check the number of entries that weren't found. If they exist, 462178173Simp * try again with a prefix for virtualized or DPCPU symbol names. 463178173Simp */ 464178173Simp error = ((p - nl) - nvalid); 465178173Simp if (error && _kvm_vnet_initialized(kd, initialize) && !tried_vnet) { 466178173Simp tried_vnet = 1; 467178173Simp prefix = VNET_SYMPREFIX; 468178173Simp goto again; 469178173Simp } 470178173Simp if (error && _kvm_dpcpu_initialized(kd, initialize) && !tried_dpcpu) { 471178173Simp tried_dpcpu = 1; 472178173Simp prefix = DPCPU_SYMPREFIX; 473178173Simp goto again; 474178173Simp } 475178173Simp 476178173Simp /* 477178173Simp * Return the number of entries that weren't found. If they exist, 478178173Simp * also fill internal error buffer. 479178173Simp */ 480178173Simp error = ((p - nl) - nvalid); 481178173Simp if (error) 482178173Simp _kvm_syserr(kd, kd->program, "kvm_nlist"); 483178173Simp return (error); 484178173Simp} 485178173Simp 486178173Simpint 487178173Simpkvm_nlist(kvm_t *kd, struct nlist *nl) 488178173Simp{ 489178173Simp 490178173Simp /* 491178173Simp * If called via the public interface, permit intialization of 492178173Simp * further virtualized modules on demand. 493178173Simp */ 494178173Simp return (_kvm_nlist(kd, nl, 1)); 495178173Simp} 496178173Simp 497178173Simpssize_t 498178173Simpkvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) 499178173Simp{ 500178173Simp int cc; 501178173Simp ssize_t cr; 502178173Simp off_t pa; 503178173Simp char *cp; 504178173Simp 505178173Simp if (ISALIVE(kd)) { 506178173Simp /* 507178173Simp * We're using /dev/kmem. Just read straight from the 508178173Simp * device and let the active kernel do the address translation. 509178173Simp */ 510178173Simp errno = 0; 511178173Simp if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 512178173Simp _kvm_err(kd, 0, "invalid address (%lx)", kva); 513178173Simp return (-1); 514178173Simp } 515178173Simp cr = read(kd->vmfd, buf, len); 516178173Simp if (cr < 0) { 517178173Simp _kvm_syserr(kd, 0, "kvm_read"); 518178173Simp return (-1); 519178173Simp } else if (cr < (ssize_t)len) 520178173Simp _kvm_err(kd, kd->program, "short read"); 521178173Simp return (cr); 522178173Simp } 523178173Simp 524178173Simp cp = buf; 525178173Simp while (len > 0) { 526178173Simp cc = _kvm_kvatop(kd, kva, &pa); 527178173Simp if (cc == 0) 528178173Simp return (-1); 529178173Simp if (cc > (ssize_t)len) 530178173Simp cc = len; 531178173Simp errno = 0; 532178173Simp if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 533178173Simp _kvm_syserr(kd, 0, _PATH_MEM); 534178173Simp break; 535178173Simp } 536178173Simp cr = read(kd->pmfd, cp, cc); 537178173Simp if (cr < 0) { 538178173Simp _kvm_syserr(kd, kd->program, "kvm_read"); 539178173Simp break; 540178173Simp } 541178173Simp /* 542178173Simp * If kvm_kvatop returns a bogus value or our core file is 543178173Simp * truncated, we might wind up seeking beyond the end of the 544178173Simp * core file in which case the read will return 0 (EOF). 545178173Simp */ 546178173Simp if (cr == 0) 547178173Simp break; 548178173Simp cp += cr; 549178173Simp kva += cr; 550178173Simp len -= cr; 551178173Simp } 552178173Simp 553178173Simp return (cp - (char *)buf); 554178173Simp} 555178173Simp 556178173Simpssize_t 557178173Simpkvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) 558178173Simp{ 559178173Simp int cc; 560178173Simp 561178173Simp if (ISALIVE(kd)) { 562178173Simp /* 563178173Simp * Just like kvm_read, only we write. 564178173Simp */ 565178173Simp errno = 0; 566178173Simp if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 567178173Simp _kvm_err(kd, 0, "invalid address (%lx)", kva); 568178173Simp return (-1); 569178173Simp } 570178173Simp cc = write(kd->vmfd, buf, len); 571178173Simp if (cc < 0) { 572178173Simp _kvm_syserr(kd, 0, "kvm_write"); 573178173Simp return (-1); 574178173Simp } else if ((size_t)cc < len) 575178173Simp _kvm_err(kd, kd->program, "short write"); 576178173Simp return (cc); 577178173Simp } else { 578178173Simp _kvm_err(kd, kd->program, 579178173Simp "kvm_write not implemented for dead kernels"); 580178173Simp return (-1); 581178173Simp } 582178173Simp /* NOTREACHED */ 583178173Simp} 584178173Simp