xref: /illumos-gate/usr/src/lib/libkvm/common/kvm.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <kvm.h>
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <limits.h>
35*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
36*7c478bd9Sstevel@tonic-gate #include <strings.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/mem.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate struct _kvmd {
44*7c478bd9Sstevel@tonic-gate 	struct dumphdr	kvm_dump;
45*7c478bd9Sstevel@tonic-gate 	char		*kvm_debug;
46*7c478bd9Sstevel@tonic-gate 	int		kvm_openflag;
47*7c478bd9Sstevel@tonic-gate 	int		kvm_corefd;
48*7c478bd9Sstevel@tonic-gate 	int		kvm_kmemfd;
49*7c478bd9Sstevel@tonic-gate 	int		kvm_memfd;
50*7c478bd9Sstevel@tonic-gate 	size_t		kvm_coremapsize;
51*7c478bd9Sstevel@tonic-gate 	char		*kvm_core;
52*7c478bd9Sstevel@tonic-gate 	dump_map_t	*kvm_map;
53*7c478bd9Sstevel@tonic-gate 	pfn_t		*kvm_pfn;
54*7c478bd9Sstevel@tonic-gate 	struct as	*kvm_kas;
55*7c478bd9Sstevel@tonic-gate 	proc_t		*kvm_practive;
56*7c478bd9Sstevel@tonic-gate 	pid_t		kvm_pid;
57*7c478bd9Sstevel@tonic-gate 	char		kvm_namelist[MAXNAMELEN + 1];
58*7c478bd9Sstevel@tonic-gate 	proc_t		kvm_proc;
59*7c478bd9Sstevel@tonic-gate };
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #define	PREAD	(ssize_t (*)(int, void *, size_t, offset_t))pread64
62*7c478bd9Sstevel@tonic-gate #define	PWRITE	(ssize_t (*)(int, void *, size_t, offset_t))pwrite64
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static kvm_t *
65*7c478bd9Sstevel@tonic-gate fail(kvm_t *kd, const char *err, const char *message, ...)
66*7c478bd9Sstevel@tonic-gate {
67*7c478bd9Sstevel@tonic-gate 	va_list args;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	va_start(args, message);
70*7c478bd9Sstevel@tonic-gate 	if (err || (kd && kd->kvm_debug)) {
71*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", err ? err : "KVM_DEBUG");
72*7c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, message, args);
73*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 	va_end(args);
76*7c478bd9Sstevel@tonic-gate 	if (kd != NULL)
77*7c478bd9Sstevel@tonic-gate 		(void) kvm_close(kd);
78*7c478bd9Sstevel@tonic-gate 	return (NULL);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
82*7c478bd9Sstevel@tonic-gate kvm_t *
83*7c478bd9Sstevel@tonic-gate kvm_open(const char *namelist, const char *corefile, const char *swapfile,
84*7c478bd9Sstevel@tonic-gate 	int flag, const char *err)
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	kvm_t *kd;
87*7c478bd9Sstevel@tonic-gate 	struct stat64 memstat, kmemstat, allkmemstat, corestat;
88*7c478bd9Sstevel@tonic-gate 	struct nlist nl[3] = { { "kas" }, { "practive" }, { "" } };
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if ((kd = calloc(1, sizeof (kvm_t))) == NULL)
91*7c478bd9Sstevel@tonic-gate 		return (fail(NULL, err, "cannot allocate space for kvm_t"));
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	kd->kvm_corefd = kd->kvm_kmemfd = kd->kvm_memfd = -1;
94*7c478bd9Sstevel@tonic-gate 	kd->kvm_debug = getenv("KVM_DEBUG");
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if ((kd->kvm_openflag = flag) != O_RDONLY && flag != O_RDWR)
97*7c478bd9Sstevel@tonic-gate 		return (fail(kd, err, "illegal flag 0x%x to kvm_open()", flag));
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	if (corefile == NULL)
100*7c478bd9Sstevel@tonic-gate 		corefile = "/dev/kmem";
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	if (stat64(corefile, &corestat) == -1)
103*7c478bd9Sstevel@tonic-gate 		return (fail(kd, err, "cannot stat %s", corefile));
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	if (S_ISCHR(corestat.st_mode)) {
106*7c478bd9Sstevel@tonic-gate 		if (stat64("/dev/mem", &memstat) == -1)
107*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "cannot stat /dev/mem"));
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 		if (stat64("/dev/kmem", &kmemstat) == -1)
110*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "cannot stat /dev/kmem"));
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 		if (stat64("/dev/allkmem", &allkmemstat) == -1)
113*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "cannot stat /dev/allkmem"));
114*7c478bd9Sstevel@tonic-gate 		if (corestat.st_rdev == memstat.st_rdev ||
115*7c478bd9Sstevel@tonic-gate 		    corestat.st_rdev == kmemstat.st_rdev ||
116*7c478bd9Sstevel@tonic-gate 		    corestat.st_rdev == allkmemstat.st_rdev) {
117*7c478bd9Sstevel@tonic-gate 			char *kmem = (corestat.st_rdev == allkmemstat.st_rdev ?
118*7c478bd9Sstevel@tonic-gate 			    "/dev/allkmem" : "/dev/kmem");
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 			if ((kd->kvm_kmemfd = open64(kmem, flag)) == -1)
121*7c478bd9Sstevel@tonic-gate 				return (fail(kd, err, "cannot open %s", kmem));
122*7c478bd9Sstevel@tonic-gate 			if ((kd->kvm_memfd = open64("/dev/mem", flag)) == -1)
123*7c478bd9Sstevel@tonic-gate 				return (fail(kd, err, "cannot open /dev/mem"));
124*7c478bd9Sstevel@tonic-gate 		}
125*7c478bd9Sstevel@tonic-gate 	} else {
126*7c478bd9Sstevel@tonic-gate 		if ((kd->kvm_corefd = open64(corefile, flag)) == -1)
127*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "cannot open %s", corefile));
128*7c478bd9Sstevel@tonic-gate 		if (pread64(kd->kvm_corefd, &kd->kvm_dump,
129*7c478bd9Sstevel@tonic-gate 		    sizeof (kd->kvm_dump), 0) != sizeof (kd->kvm_dump))
130*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "cannot read dump header"));
131*7c478bd9Sstevel@tonic-gate 		if (kd->kvm_dump.dump_magic != DUMP_MAGIC)
132*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "%s is not a kernel core file "
133*7c478bd9Sstevel@tonic-gate 			    "(bad magic number %x)", corefile,
134*7c478bd9Sstevel@tonic-gate 			    kd->kvm_dump.dump_magic));
135*7c478bd9Sstevel@tonic-gate 		if (kd->kvm_dump.dump_version != DUMP_VERSION)
136*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err,
137*7c478bd9Sstevel@tonic-gate 			    "libkvm version (%u) != corefile version (%u)",
138*7c478bd9Sstevel@tonic-gate 			    DUMP_VERSION, kd->kvm_dump.dump_version));
139*7c478bd9Sstevel@tonic-gate 		if (kd->kvm_dump.dump_wordsize != DUMP_WORDSIZE)
140*7c478bd9Sstevel@tonic-gate 			return (fail(kd, err, "%s is a %d-bit core file - "
141*7c478bd9Sstevel@tonic-gate 			    "cannot examine with %d-bit libkvm", corefile,
142*7c478bd9Sstevel@tonic-gate 			    kd->kvm_dump.dump_wordsize, DUMP_WORDSIZE));
143*7c478bd9Sstevel@tonic-gate 		/*
144*7c478bd9Sstevel@tonic-gate 		 * We try to mmap(2) the entire corefile for performance
145*7c478bd9Sstevel@tonic-gate 		 * (so we can use bcopy(3C) rather than pread(2)).  Failing
146*7c478bd9Sstevel@tonic-gate 		 * that, we insist on at least mmap(2)ing the dump map.
147*7c478bd9Sstevel@tonic-gate 		 */
148*7c478bd9Sstevel@tonic-gate 		kd->kvm_coremapsize = (size_t)corestat.st_size;
149*7c478bd9Sstevel@tonic-gate 		if (corestat.st_size > LONG_MAX ||
150*7c478bd9Sstevel@tonic-gate 		    (kd->kvm_core = mmap64(0, kd->kvm_coremapsize,
151*7c478bd9Sstevel@tonic-gate 		    PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) == MAP_FAILED) {
152*7c478bd9Sstevel@tonic-gate 			kd->kvm_coremapsize = kd->kvm_dump.dump_data;
153*7c478bd9Sstevel@tonic-gate 			if ((kd->kvm_core = mmap64(0, kd->kvm_coremapsize,
154*7c478bd9Sstevel@tonic-gate 			    PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) ==
155*7c478bd9Sstevel@tonic-gate 			    MAP_FAILED)
156*7c478bd9Sstevel@tonic-gate 				return (fail(kd, err, "cannot mmap corefile"));
157*7c478bd9Sstevel@tonic-gate 		}
158*7c478bd9Sstevel@tonic-gate 		kd->kvm_map = (void *)(kd->kvm_core + kd->kvm_dump.dump_map);
159*7c478bd9Sstevel@tonic-gate 		kd->kvm_pfn = (void *)(kd->kvm_core + kd->kvm_dump.dump_pfn);
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (namelist == NULL)
163*7c478bd9Sstevel@tonic-gate 		namelist = "/dev/ksyms";
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	(void) strncpy(kd->kvm_namelist, namelist, MAXNAMELEN);
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	if (kvm_nlist(kd, nl) == -1)
168*7c478bd9Sstevel@tonic-gate 		return (fail(kd, err, "%s is not a %d-bit kernel namelist",
169*7c478bd9Sstevel@tonic-gate 		    namelist, DUMP_WORDSIZE));
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	kd->kvm_kas = (struct as *)nl[0].n_value;
172*7c478bd9Sstevel@tonic-gate 	kd->kvm_practive = (proc_t *)nl[1].n_value;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	(void) kvm_setproc(kd);
175*7c478bd9Sstevel@tonic-gate 	return (kd);
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate int
179*7c478bd9Sstevel@tonic-gate kvm_close(kvm_t *kd)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_core != NULL && kd->kvm_core != MAP_FAILED)
182*7c478bd9Sstevel@tonic-gate 		(void) munmap(kd->kvm_core, kd->kvm_coremapsize);
183*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_corefd != -1)
184*7c478bd9Sstevel@tonic-gate 		(void) close(kd->kvm_corefd);
185*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_kmemfd != -1)
186*7c478bd9Sstevel@tonic-gate 		(void) close(kd->kvm_kmemfd);
187*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_memfd != -1)
188*7c478bd9Sstevel@tonic-gate 		(void) close(kd->kvm_memfd);
189*7c478bd9Sstevel@tonic-gate 	free(kd);
190*7c478bd9Sstevel@tonic-gate 	return (0);
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate int
194*7c478bd9Sstevel@tonic-gate kvm_nlist(kvm_t *kd, struct nlist nl[])
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	return (nlist(kd->kvm_namelist, nl));
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate static offset_t
200*7c478bd9Sstevel@tonic-gate kvm_lookup(kvm_t *kd, struct as *as, uint64_t addr)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1);
203*7c478bd9Sstevel@tonic-gate 	uint64_t page = addr - pageoff;
204*7c478bd9Sstevel@tonic-gate 	offset_t off = 0;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_debug)
207*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "kvm_lookup(%p, %llx):", (void *)as, addr);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if (as == NULL) {		/* physical addressing mode */
210*7c478bd9Sstevel@tonic-gate 		long first = 0;
211*7c478bd9Sstevel@tonic-gate 		long last = kd->kvm_dump.dump_npages - 1;
212*7c478bd9Sstevel@tonic-gate 		pfn_t target = (pfn_t)(page >> kd->kvm_dump.dump_pageshift);
213*7c478bd9Sstevel@tonic-gate 		while (last >= first) {
214*7c478bd9Sstevel@tonic-gate 			long middle = (first + last) / 2;
215*7c478bd9Sstevel@tonic-gate 			pfn_t pfn = kd->kvm_pfn[middle];
216*7c478bd9Sstevel@tonic-gate 			if (kd->kvm_debug)
217*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, " %ld ->", middle);
218*7c478bd9Sstevel@tonic-gate 			if (pfn == target) {
219*7c478bd9Sstevel@tonic-gate 				off = kd->kvm_dump.dump_data + pageoff +
220*7c478bd9Sstevel@tonic-gate 				    ((uint64_t)middle <<
221*7c478bd9Sstevel@tonic-gate 				    kd->kvm_dump.dump_pageshift);
222*7c478bd9Sstevel@tonic-gate 				break;
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 			if (pfn < target)
225*7c478bd9Sstevel@tonic-gate 				first = middle + 1;
226*7c478bd9Sstevel@tonic-gate 			else
227*7c478bd9Sstevel@tonic-gate 				last = middle - 1;
228*7c478bd9Sstevel@tonic-gate 		}
229*7c478bd9Sstevel@tonic-gate 	} else {
230*7c478bd9Sstevel@tonic-gate 		long hash = DUMP_HASH(&kd->kvm_dump, as, page);
231*7c478bd9Sstevel@tonic-gate 		off = kd->kvm_map[hash].dm_first;
232*7c478bd9Sstevel@tonic-gate 		while (off != 0) {
233*7c478bd9Sstevel@tonic-gate 			dump_map_t *dmp = (void *)(kd->kvm_core + off);
234*7c478bd9Sstevel@tonic-gate 			if (kd->kvm_debug)
235*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, " %llx ->", off);
236*7c478bd9Sstevel@tonic-gate 			if (dmp < kd->kvm_map ||
237*7c478bd9Sstevel@tonic-gate 			    dmp > kd->kvm_map + kd->kvm_dump.dump_hashmask ||
238*7c478bd9Sstevel@tonic-gate 			    (off & (sizeof (offset_t) - 1)) != 0 ||
239*7c478bd9Sstevel@tonic-gate 			    DUMP_HASH(&kd->kvm_dump, dmp->dm_as, dmp->dm_va) !=
240*7c478bd9Sstevel@tonic-gate 			    hash) {
241*7c478bd9Sstevel@tonic-gate 				if (kd->kvm_debug)
242*7c478bd9Sstevel@tonic-gate 					fprintf(stderr, " dump map corrupt\n");
243*7c478bd9Sstevel@tonic-gate 				return (0);
244*7c478bd9Sstevel@tonic-gate 			}
245*7c478bd9Sstevel@tonic-gate 			if (dmp->dm_va == page && dmp->dm_as == as) {
246*7c478bd9Sstevel@tonic-gate 				off = dmp->dm_data + pageoff;
247*7c478bd9Sstevel@tonic-gate 				break;
248*7c478bd9Sstevel@tonic-gate 			}
249*7c478bd9Sstevel@tonic-gate 			off = dmp->dm_next;
250*7c478bd9Sstevel@tonic-gate 		}
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_debug)
253*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s found: %llx\n", off ? "" : " not", off);
254*7c478bd9Sstevel@tonic-gate 	return (off);
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate static ssize_t
258*7c478bd9Sstevel@tonic-gate kvm_rw(kvm_t *kd, uint64_t addr, void *buf, size_t size,
259*7c478bd9Sstevel@tonic-gate 	struct as *as, ssize_t (*prw)(int, void *, size_t, offset_t))
260*7c478bd9Sstevel@tonic-gate {
261*7c478bd9Sstevel@tonic-gate 	offset_t off;
262*7c478bd9Sstevel@tonic-gate 	size_t resid = size;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	/*
265*7c478bd9Sstevel@tonic-gate 	 * read/write of zero bytes always succeeds
266*7c478bd9Sstevel@tonic-gate 	 */
267*7c478bd9Sstevel@tonic-gate 	if (size == 0)
268*7c478bd9Sstevel@tonic-gate 		return (0);
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_core == NULL) {
271*7c478bd9Sstevel@tonic-gate 		char procbuf[100];
272*7c478bd9Sstevel@tonic-gate 		int procfd;
273*7c478bd9Sstevel@tonic-gate 		ssize_t rval;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 		if (as == kd->kvm_kas)
276*7c478bd9Sstevel@tonic-gate 			return (prw(kd->kvm_kmemfd, buf, size, addr));
277*7c478bd9Sstevel@tonic-gate 		if (as == NULL)
278*7c478bd9Sstevel@tonic-gate 			return (prw(kd->kvm_memfd, buf, size, addr));
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 		(void) sprintf(procbuf, "/proc/%ld/as", kd->kvm_pid);
281*7c478bd9Sstevel@tonic-gate 		if ((procfd = open64(procbuf, kd->kvm_openflag)) == -1)
282*7c478bd9Sstevel@tonic-gate 			return (-1);
283*7c478bd9Sstevel@tonic-gate 		rval = prw(procfd, buf, size, addr);
284*7c478bd9Sstevel@tonic-gate 		(void) close(procfd);
285*7c478bd9Sstevel@tonic-gate 		return (rval);
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	while (resid != 0) {
289*7c478bd9Sstevel@tonic-gate 		uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1);
290*7c478bd9Sstevel@tonic-gate 		ssize_t len = MIN(resid, kd->kvm_dump.dump_pagesize - pageoff);
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 		if ((off = kvm_lookup(kd, as, addr)) == 0)
293*7c478bd9Sstevel@tonic-gate 			break;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 		if (prw == PREAD && off < kd->kvm_coremapsize)
296*7c478bd9Sstevel@tonic-gate 			bcopy(kd->kvm_core + off, buf, len);
297*7c478bd9Sstevel@tonic-gate 		else if ((len = prw(kd->kvm_corefd, buf, len, off)) <= 0)
298*7c478bd9Sstevel@tonic-gate 			break;
299*7c478bd9Sstevel@tonic-gate 		resid -= len;
300*7c478bd9Sstevel@tonic-gate 		addr += len;
301*7c478bd9Sstevel@tonic-gate 		buf = (char *)buf + len;
302*7c478bd9Sstevel@tonic-gate 	}
303*7c478bd9Sstevel@tonic-gate 	return (resid < size ? size - resid : -1);
304*7c478bd9Sstevel@tonic-gate }
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate ssize_t
307*7c478bd9Sstevel@tonic-gate kvm_read(kvm_t *kd, uintptr_t addr, void *buf, size_t size)
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD));
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate ssize_t
313*7c478bd9Sstevel@tonic-gate kvm_kread(kvm_t *kd, uintptr_t addr, void *buf, size_t size)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD));
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate ssize_t
319*7c478bd9Sstevel@tonic-gate kvm_uread(kvm_t *kd, uintptr_t addr, void *buf, size_t size)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, buf, size, kd->kvm_proc.p_as, PREAD));
322*7c478bd9Sstevel@tonic-gate }
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate ssize_t
325*7c478bd9Sstevel@tonic-gate kvm_aread(kvm_t *kd, uintptr_t addr, void *buf, size_t size, struct as *as)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, buf, size, as, PREAD));
328*7c478bd9Sstevel@tonic-gate }
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate ssize_t
331*7c478bd9Sstevel@tonic-gate kvm_pread(kvm_t *kd, uint64_t addr, void *buf, size_t size)
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, buf, size, NULL, PREAD));
334*7c478bd9Sstevel@tonic-gate }
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate ssize_t
337*7c478bd9Sstevel@tonic-gate kvm_write(kvm_t *kd, uintptr_t addr, const void *buf, size_t size)
338*7c478bd9Sstevel@tonic-gate {
339*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE));
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate ssize_t
343*7c478bd9Sstevel@tonic-gate kvm_kwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size)
344*7c478bd9Sstevel@tonic-gate {
345*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE));
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate ssize_t
349*7c478bd9Sstevel@tonic-gate kvm_uwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_proc.p_as, PWRITE));
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate ssize_t
355*7c478bd9Sstevel@tonic-gate kvm_awrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size,
356*7c478bd9Sstevel@tonic-gate     struct as *as)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, (void *)buf, size, as, PWRITE));
359*7c478bd9Sstevel@tonic-gate }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate ssize_t
362*7c478bd9Sstevel@tonic-gate kvm_pwrite(kvm_t *kd, uint64_t addr, const void *buf, size_t size)
363*7c478bd9Sstevel@tonic-gate {
364*7c478bd9Sstevel@tonic-gate 	return (kvm_rw(kd, addr, (void *)buf, size, NULL, PWRITE));
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate uint64_t
368*7c478bd9Sstevel@tonic-gate kvm_physaddr(kvm_t *kd, struct as *as, uintptr_t addr)
369*7c478bd9Sstevel@tonic-gate {
370*7c478bd9Sstevel@tonic-gate 	mem_vtop_t mem_vtop;
371*7c478bd9Sstevel@tonic-gate 	offset_t off;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_core == NULL) {
374*7c478bd9Sstevel@tonic-gate 		mem_vtop.m_as = as;
375*7c478bd9Sstevel@tonic-gate 		mem_vtop.m_va = (void *)addr;
376*7c478bd9Sstevel@tonic-gate 		if (ioctl(kd->kvm_kmemfd, MEM_VTOP, &mem_vtop) == 0)
377*7c478bd9Sstevel@tonic-gate 			return ((uint64_t)mem_vtop.m_pfn * getpagesize() +
378*7c478bd9Sstevel@tonic-gate 			    (addr & (getpagesize() - 1)));
379*7c478bd9Sstevel@tonic-gate 	} else {
380*7c478bd9Sstevel@tonic-gate 		if ((off = kvm_lookup(kd, as, addr)) != 0) {
381*7c478bd9Sstevel@tonic-gate 			long pfn_index =
382*7c478bd9Sstevel@tonic-gate 			    (u_offset_t)(off - kd->kvm_dump.dump_data) >>
383*7c478bd9Sstevel@tonic-gate 			    kd->kvm_dump.dump_pageshift;
384*7c478bd9Sstevel@tonic-gate 			return (((uint64_t)kd->kvm_pfn[pfn_index] <<
385*7c478bd9Sstevel@tonic-gate 			    kd->kvm_dump.dump_pageshift) +
386*7c478bd9Sstevel@tonic-gate 			    (addr & (kd->kvm_dump.dump_pagesize - 1)));
387*7c478bd9Sstevel@tonic-gate 		}
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 	return (-1ULL);
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate struct proc *
393*7c478bd9Sstevel@tonic-gate kvm_getproc(kvm_t *kd, pid_t pid)
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	(void) kvm_setproc(kd);
396*7c478bd9Sstevel@tonic-gate 	while (kvm_nextproc(kd) != NULL)
397*7c478bd9Sstevel@tonic-gate 		if (kd->kvm_pid == pid)
398*7c478bd9Sstevel@tonic-gate 			return (&kd->kvm_proc);
399*7c478bd9Sstevel@tonic-gate 	return (NULL);
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate struct proc *
403*7c478bd9Sstevel@tonic-gate kvm_nextproc(kvm_t *kd)
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate 	if (kd->kvm_proc.p_next == NULL ||
406*7c478bd9Sstevel@tonic-gate 	    kvm_kread(kd, (uintptr_t)kd->kvm_proc.p_next,
407*7c478bd9Sstevel@tonic-gate 	    &kd->kvm_proc, sizeof (proc_t)) != sizeof (proc_t) ||
408*7c478bd9Sstevel@tonic-gate 	    kvm_kread(kd, (uintptr_t)&kd->kvm_proc.p_pidp->pid_id,
409*7c478bd9Sstevel@tonic-gate 	    &kd->kvm_pid, sizeof (pid_t)) != sizeof (pid_t))
410*7c478bd9Sstevel@tonic-gate 		return (NULL);
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	return (&kd->kvm_proc);
413*7c478bd9Sstevel@tonic-gate }
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate int
416*7c478bd9Sstevel@tonic-gate kvm_setproc(kvm_t *kd)
417*7c478bd9Sstevel@tonic-gate {
418*7c478bd9Sstevel@tonic-gate 	(void) kvm_kread(kd, (uintptr_t)kd->kvm_practive,
419*7c478bd9Sstevel@tonic-gate 	    &kd->kvm_proc.p_next, sizeof (proc_t *));
420*7c478bd9Sstevel@tonic-gate 	kd->kvm_pid = -1;
421*7c478bd9Sstevel@tonic-gate 	return (0);
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
425*7c478bd9Sstevel@tonic-gate struct user *
426*7c478bd9Sstevel@tonic-gate kvm_getu(kvm_t *kd, struct proc *p)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	return (&p->p_user);
429*7c478bd9Sstevel@tonic-gate }
430