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