drvstats.c revision 1.1 1 1.1 blymn /* $NetBSD: drvstats.c,v 1.1 2006/04/14 13:12:37 blymn Exp $ */
2 1.1 blymn
3 1.1 blymn /*
4 1.1 blymn * Copyright (c) 1996 John M. Vinopal
5 1.1 blymn * All rights reserved.
6 1.1 blymn *
7 1.1 blymn * Redistribution and use in source and binary forms, with or without
8 1.1 blymn * modification, are permitted provided that the following conditions
9 1.1 blymn * are met:
10 1.1 blymn * 1. Redistributions of source code must retain the above copyright
11 1.1 blymn * notice, this list of conditions and the following disclaimer.
12 1.1 blymn * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 blymn * notice, this list of conditions and the following disclaimer in the
14 1.1 blymn * documentation and/or other materials provided with the distribution.
15 1.1 blymn * 3. All advertising materials mentioning features or use of this software
16 1.1 blymn * must display the following acknowledgement:
17 1.1 blymn * This product includes software developed for the NetBSD Project
18 1.1 blymn * by John M. Vinopal.
19 1.1 blymn * 4. The name of the author may not be used to endorse or promote products
20 1.1 blymn * derived from this software without specific prior written permission.
21 1.1 blymn *
22 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 1.1 blymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.1 blymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.1 blymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 1.1 blymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 1.1 blymn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 1.1 blymn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 1.1 blymn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 1.1 blymn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 blymn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 blymn * SUCH DAMAGE.
33 1.1 blymn */
34 1.1 blymn
35 1.1 blymn #include <sys/param.h>
36 1.1 blymn #include <sys/sched.h>
37 1.1 blymn #include <sys/sysctl.h>
38 1.1 blymn #include <sys/time.h>
39 1.1 blymn #include <sys/iostat.h>
40 1.1 blymn
41 1.1 blymn #include <err.h>
42 1.1 blymn #include <fcntl.h>
43 1.1 blymn #include <kvm.h>
44 1.1 blymn #include <limits.h>
45 1.1 blymn #include <nlist.h>
46 1.1 blymn #include <stdio.h>
47 1.1 blymn #include <stdlib.h>
48 1.1 blymn #include <string.h>
49 1.1 blymn #include <unistd.h>
50 1.1 blymn #include "drvstats.h"
51 1.1 blymn
52 1.1 blymn static struct nlist namelist[] = {
53 1.1 blymn #define X_TK_NIN 0
54 1.1 blymn { "_tk_nin" }, /* tty characters in */
55 1.1 blymn #define X_TK_NOUT 1
56 1.1 blymn { "_tk_nout" }, /* tty characters out */
57 1.1 blymn #define X_HZ 2
58 1.1 blymn { "_hz" }, /* ticks per second */
59 1.1 blymn #define X_STATHZ 3
60 1.1 blymn { "_stathz" },
61 1.1 blymn #define X_DRIVE_COUNT 4
62 1.1 blymn { "_iostat_count" }, /* number of drives */
63 1.1 blymn #define X_DRIVELIST 5
64 1.1 blymn { "_iostatlist" }, /* TAILQ of drives */
65 1.1 blymn { NULL },
66 1.1 blymn };
67 1.1 blymn
68 1.1 blymn /* Structures to hold the statistics. */
69 1.1 blymn struct _drive cur, last;
70 1.1 blymn
71 1.1 blymn /* Kernel pointers: nlistf and memf defined in calling program. */
72 1.1 blymn static kvm_t *kd = NULL;
73 1.1 blymn extern char *nlistf;
74 1.1 blymn extern char *memf;
75 1.1 blymn extern int hz;
76 1.1 blymn
77 1.1 blymn /* Pointer to list of drives. */
78 1.1 blymn static struct io_stats *iostathead = NULL;
79 1.1 blymn /* sysctl hw.drivestats buffer. */
80 1.1 blymn static struct io_sysctl *drives = NULL;
81 1.1 blymn
82 1.1 blymn /* Backward compatibility references. */
83 1.1 blymn int ndrive = 0;
84 1.1 blymn int *drv_select;
85 1.1 blymn char **dr_name;
86 1.1 blymn
87 1.1 blymn #define KVM_ERROR(_string) do { \
88 1.1 blymn warnx("%s", (_string)); \
89 1.1 blymn errx(1, "%s", kvm_geterr(kd)); \
90 1.1 blymn } while (/* CONSTCOND */0)
91 1.1 blymn
92 1.1 blymn /*
93 1.1 blymn * Dereference the namelist pointer `v' and fill in the local copy
94 1.1 blymn * 'p' which is of size 's'.
95 1.1 blymn */
96 1.1 blymn #define deref_nl(v, p, s) do { \
97 1.1 blymn deref_kptr((void *)namelist[(v)].n_value, (p), (s)); \
98 1.1 blymn } while (/* CONSTCOND */0)
99 1.1 blymn
100 1.1 blymn /* Missing from <sys/time.h> */
101 1.1 blymn #define timerset(tvp, uvp) do { \
102 1.1 blymn ((uvp)->tv_sec = (tvp)->tv_sec); \
103 1.1 blymn ((uvp)->tv_usec = (tvp)->tv_usec); \
104 1.1 blymn } while (/* CONSTCOND */0)
105 1.1 blymn
106 1.1 blymn static void deref_kptr(void *, void *, size_t);
107 1.1 blymn
108 1.1 blymn /*
109 1.1 blymn * Take the delta between the present values and the last recorded
110 1.1 blymn * values, storing the present values in the 'last' structure, and
111 1.1 blymn * the delta values in the 'cur' structure.
112 1.1 blymn */
113 1.1 blymn void
114 1.1 blymn drvswap(void)
115 1.1 blymn {
116 1.1 blymn u_int64_t tmp;
117 1.1 blymn int i;
118 1.1 blymn
119 1.1 blymn #define SWAP(fld) do { \
120 1.1 blymn tmp = cur.fld; \
121 1.1 blymn cur.fld -= last.fld; \
122 1.1 blymn last.fld = tmp; \
123 1.1 blymn } while (/* CONSTCOND */0)
124 1.1 blymn
125 1.1 blymn for (i = 0; i < ndrive; i++) {
126 1.1 blymn struct timeval tmp_timer;
127 1.1 blymn
128 1.1 blymn if (!cur.select[i])
129 1.1 blymn continue;
130 1.1 blymn
131 1.1 blymn /* Delta Values. */
132 1.1 blymn SWAP(rxfer[i]);
133 1.1 blymn SWAP(wxfer[i]);
134 1.1 blymn SWAP(seek[i]);
135 1.1 blymn SWAP(rbytes[i]);
136 1.1 blymn SWAP(wbytes[i]);
137 1.1 blymn
138 1.1 blymn /* Delta Time. */
139 1.1 blymn timerclear(&tmp_timer);
140 1.1 blymn timerset(&(cur.time[i]), &tmp_timer);
141 1.1 blymn timersub(&tmp_timer, &(last.time[i]), &(cur.time[i]));
142 1.1 blymn timerclear(&(last.time[i]));
143 1.1 blymn timerset(&tmp_timer, &(last.time[i]));
144 1.1 blymn }
145 1.1 blymn }
146 1.1 blymn
147 1.1 blymn void
148 1.1 blymn tkswap(void)
149 1.1 blymn {
150 1.1 blymn u_int64_t tmp;
151 1.1 blymn
152 1.1 blymn SWAP(tk_nin);
153 1.1 blymn SWAP(tk_nout);
154 1.1 blymn }
155 1.1 blymn
156 1.1 blymn void
157 1.1 blymn cpuswap(void)
158 1.1 blymn {
159 1.1 blymn double etime;
160 1.1 blymn u_int64_t tmp;
161 1.1 blymn int i, state;
162 1.1 blymn
163 1.1 blymn for (i = 0; i < CPUSTATES; i++)
164 1.1 blymn SWAP(cp_time[i]);
165 1.1 blymn
166 1.1 blymn etime = 0;
167 1.1 blymn for (state = 0; state < CPUSTATES; ++state) {
168 1.1 blymn etime += cur.cp_time[state];
169 1.1 blymn }
170 1.1 blymn if (etime == 0)
171 1.1 blymn etime = 1;
172 1.1 blymn etime /= hz;
173 1.1 blymn etime /= cur.cp_ncpu;
174 1.1 blymn
175 1.1 blymn cur.cp_etime = etime;
176 1.1 blymn }
177 1.1 blymn #undef SWAP
178 1.1 blymn
179 1.1 blymn /*
180 1.1 blymn * Read the drive statistics for each drive in the drive list.
181 1.1 blymn * Also collect statistics for tty i/o and CPU ticks.
182 1.1 blymn */
183 1.1 blymn void
184 1.1 blymn drvreadstats(void)
185 1.1 blymn {
186 1.1 blymn struct io_stats cur_drive, *p;
187 1.1 blymn size_t size;
188 1.1 blymn int mib[3];
189 1.1 blymn int i;
190 1.1 blymn
191 1.1 blymn p = iostathead;
192 1.1 blymn
193 1.1 blymn if (memf == NULL) {
194 1.1 blymn mib[0] = CTL_HW;
195 1.1 blymn mib[1] = HW_IOSTATS;
196 1.1 blymn mib[2] = sizeof(struct io_sysctl);
197 1.1 blymn
198 1.1 blymn size = ndrive * sizeof(struct io_sysctl);
199 1.1 blymn if (sysctl(mib, 3, drives, &size, NULL, 0) < 0)
200 1.1 blymn err(1, "sysctl hw.iostats failed");
201 1.1 blymn for (i = 0; i < ndrive; i++) {
202 1.1 blymn cur.rxfer[i] = drives[i].rxfer;
203 1.1 blymn cur.wxfer[i] = drives[i].wxfer;
204 1.1 blymn cur.seek[i] = drives[i].seek;
205 1.1 blymn cur.rbytes[i] = drives[i].rbytes;
206 1.1 blymn cur.wbytes[i] = drives[i].wbytes;
207 1.1 blymn cur.time[i].tv_sec = drives[i].time_sec;
208 1.1 blymn cur.time[i].tv_usec = drives[i].time_usec;
209 1.1 blymn }
210 1.1 blymn
211 1.1 blymn mib[0] = CTL_KERN;
212 1.1 blymn mib[1] = KERN_TKSTAT;
213 1.1 blymn mib[2] = KERN_TKSTAT_NIN;
214 1.1 blymn size = sizeof(cur.tk_nin);
215 1.1 blymn if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0)
216 1.1 blymn cur.tk_nin = 0;
217 1.1 blymn
218 1.1 blymn mib[2] = KERN_TKSTAT_NOUT;
219 1.1 blymn size = sizeof(cur.tk_nout);
220 1.1 blymn if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0)
221 1.1 blymn cur.tk_nout = 0;
222 1.1 blymn } else {
223 1.1 blymn for (i = 0; i < ndrive; i++) {
224 1.1 blymn deref_kptr(p, &cur_drive, sizeof(cur_drive));
225 1.1 blymn cur.rxfer[i] = cur_drive.rxfer;
226 1.1 blymn cur.wxfer[i] = cur_drive.wxfer;
227 1.1 blymn cur.seek[i] = cur_drive.seek;
228 1.1 blymn cur.rbytes[i] = cur_drive.rbytes;
229 1.1 blymn cur.wbytes[i] = cur_drive.wbytes;
230 1.1 blymn timerset(&(cur_drive.time), &(cur.time[i]));
231 1.1 blymn p = cur_drive.link.tqe_next;
232 1.1 blymn }
233 1.1 blymn
234 1.1 blymn deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
235 1.1 blymn deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
236 1.1 blymn }
237 1.1 blymn
238 1.1 blymn /*
239 1.1 blymn * XXX Need to locate the `correct' CPU when looking for this
240 1.1 blymn * XXX in crash dumps. Just don't report it for now, in that
241 1.1 blymn * XXX case.
242 1.1 blymn */
243 1.1 blymn size = sizeof(cur.cp_time);
244 1.1 blymn memset(cur.cp_time, 0, size);
245 1.1 blymn if (memf == NULL) {
246 1.1 blymn mib[0] = CTL_KERN;
247 1.1 blymn mib[1] = KERN_CP_TIME;
248 1.1 blymn if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0)
249 1.1 blymn memset(cur.cp_time, 0, sizeof(cur.cp_time));
250 1.1 blymn }
251 1.1 blymn }
252 1.1 blymn
253 1.1 blymn /*
254 1.1 blymn * Read collect statistics for tty i/o.
255 1.1 blymn */
256 1.1 blymn
257 1.1 blymn void
258 1.1 blymn tkreadstats(void)
259 1.1 blymn {
260 1.1 blymn size_t size;
261 1.1 blymn int mib[3];
262 1.1 blymn
263 1.1 blymn if (memf == NULL) {
264 1.1 blymn mib[0] = CTL_KERN;
265 1.1 blymn mib[1] = KERN_TKSTAT;
266 1.1 blymn mib[2] = KERN_TKSTAT_NIN;
267 1.1 blymn size = sizeof(cur.tk_nin);
268 1.1 blymn if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0)
269 1.1 blymn cur.tk_nin = 0;
270 1.1 blymn
271 1.1 blymn mib[2] = KERN_TKSTAT_NOUT;
272 1.1 blymn size = sizeof(cur.tk_nout);
273 1.1 blymn if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0)
274 1.1 blymn cur.tk_nout = 0;
275 1.1 blymn } else {
276 1.1 blymn deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
277 1.1 blymn deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
278 1.1 blymn }
279 1.1 blymn }
280 1.1 blymn
281 1.1 blymn /*
282 1.1 blymn * Read collect statistics for CPU ticks.
283 1.1 blymn */
284 1.1 blymn
285 1.1 blymn void
286 1.1 blymn cpureadstats(void)
287 1.1 blymn {
288 1.1 blymn size_t size;
289 1.1 blymn int mib[2];
290 1.1 blymn
291 1.1 blymn /*
292 1.1 blymn * XXX Need to locate the `correct' CPU when looking for this
293 1.1 blymn * XXX in crash dumps. Just don't report it for now, in that
294 1.1 blymn * XXX case.
295 1.1 blymn */
296 1.1 blymn size = sizeof(cur.cp_time);
297 1.1 blymn memset(cur.cp_time, 0, size);
298 1.1 blymn if (memf == NULL) {
299 1.1 blymn mib[0] = CTL_KERN;
300 1.1 blymn mib[1] = KERN_CP_TIME;
301 1.1 blymn if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0)
302 1.1 blymn memset(cur.cp_time, 0, sizeof(cur.cp_time));
303 1.1 blymn }
304 1.1 blymn }
305 1.1 blymn
306 1.1 blymn /*
307 1.1 blymn * Perform all of the initialization and memory allocation needed to
308 1.1 blymn * track drive statistics.
309 1.1 blymn */
310 1.1 blymn int
311 1.1 blymn drvinit(int selected)
312 1.1 blymn {
313 1.1 blymn struct iostatlist_head iostat_head;
314 1.1 blymn struct io_stats cur_drive, *p;
315 1.1 blymn struct clockinfo clockinfo;
316 1.1 blymn char errbuf[_POSIX2_LINE_MAX];
317 1.1 blymn size_t size;
318 1.1 blymn static int once = 0;
319 1.1 blymn int i, mib[3];
320 1.1 blymn
321 1.1 blymn if (once)
322 1.1 blymn return (1);
323 1.1 blymn
324 1.1 blymn if (memf == NULL) {
325 1.1 blymn mib[0] = CTL_HW;
326 1.1 blymn mib[1] = HW_NCPU;
327 1.1 blymn size = sizeof(cur.cp_ncpu);
328 1.1 blymn if (sysctl(mib, 2, &cur.cp_ncpu, &size, NULL, 0) == -1)
329 1.1 blymn err(1, "sysctl hw.ncpu failed");
330 1.1 blymn
331 1.1 blymn mib[0] = CTL_KERN;
332 1.1 blymn mib[1] = KERN_CLOCKRATE;
333 1.1 blymn size = sizeof(clockinfo);
334 1.1 blymn if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1)
335 1.1 blymn err(1, "sysctl kern.clockrate failed");
336 1.1 blymn hz = clockinfo.stathz;
337 1.1 blymn if (!hz)
338 1.1 blymn hz = clockinfo.hz;
339 1.1 blymn
340 1.1 blymn mib[0] = CTL_HW;
341 1.1 blymn mib[1] = HW_IOSTATS;
342 1.1 blymn mib[2] = sizeof(struct io_sysctl);
343 1.1 blymn if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
344 1.1 blymn err(1, "sysctl hw.drivestats failed");
345 1.1 blymn ndrive = size / sizeof(struct io_sysctl);
346 1.1 blymn
347 1.1 blymn if (size == 0) {
348 1.1 blymn warnx("No drives attached.");
349 1.1 blymn } else {
350 1.1 blymn drives = (struct io_sysctl *)malloc(size);
351 1.1 blymn if (drives == NULL)
352 1.1 blymn errx(1, "Memory allocation failure.");
353 1.1 blymn }
354 1.1 blymn } else {
355 1.1 blymn /* Open the kernel. */
356 1.1 blymn if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
357 1.1 blymn errbuf)) == NULL)
358 1.1 blymn errx(1, "kvm_openfiles: %s", errbuf);
359 1.1 blymn
360 1.1 blymn /* Obtain the namelist symbols from the kernel. */
361 1.1 blymn if (kvm_nlist(kd, namelist))
362 1.1 blymn KVM_ERROR("kvm_nlist failed to read symbols.");
363 1.1 blymn
364 1.1 blymn /* Get the number of attached drives. */
365 1.1 blymn deref_nl(X_DRIVE_COUNT, &ndrive, sizeof(ndrive));
366 1.1 blymn
367 1.1 blymn if (ndrive < 0)
368 1.1 blymn errx(1, "invalid _drive_count %d.", ndrive);
369 1.1 blymn else if (ndrive == 0) {
370 1.1 blymn warnx("No drives attached.");
371 1.1 blymn } else {
372 1.1 blymn /* Get a pointer to the first drive. */
373 1.1 blymn deref_nl(X_DRIVELIST, &iostat_head,
374 1.1 blymn sizeof(iostat_head));
375 1.1 blymn iostathead = iostat_head.tqh_first;
376 1.1 blymn }
377 1.1 blymn
378 1.1 blymn /* Get ticks per second. */
379 1.1 blymn deref_nl(X_STATHZ, &hz, sizeof(hz));
380 1.1 blymn if (!hz)
381 1.1 blymn deref_nl(X_HZ, &hz, sizeof(hz));
382 1.1 blymn }
383 1.1 blymn
384 1.1 blymn /* Allocate space for the statistics. */
385 1.1 blymn cur.time = calloc(ndrive, sizeof(struct timeval));
386 1.1 blymn cur.rxfer = calloc(ndrive, sizeof(u_int64_t));
387 1.1 blymn cur.wxfer = calloc(ndrive, sizeof(u_int64_t));
388 1.1 blymn cur.seek = calloc(ndrive, sizeof(u_int64_t));
389 1.1 blymn cur.rbytes = calloc(ndrive, sizeof(u_int64_t));
390 1.1 blymn cur.wbytes = calloc(ndrive, sizeof(u_int64_t));
391 1.1 blymn last.time = calloc(ndrive, sizeof(struct timeval));
392 1.1 blymn last.rxfer = calloc(ndrive, sizeof(u_int64_t));
393 1.1 blymn last.wxfer = calloc(ndrive, sizeof(u_int64_t));
394 1.1 blymn last.seek = calloc(ndrive, sizeof(u_int64_t));
395 1.1 blymn last.rbytes = calloc(ndrive, sizeof(u_int64_t));
396 1.1 blymn last.wbytes = calloc(ndrive, sizeof(u_int64_t));
397 1.1 blymn cur.select = calloc(ndrive, sizeof(int));
398 1.1 blymn cur.name = calloc(ndrive, sizeof(char *));
399 1.1 blymn
400 1.1 blymn if (cur.time == NULL || cur.rxfer == NULL ||
401 1.1 blymn cur.wxfer == NULL || cur.seek == NULL ||
402 1.1 blymn cur.rbytes == NULL || cur.wbytes == NULL ||
403 1.1 blymn last.time == NULL || last.rxfer == NULL ||
404 1.1 blymn last.wxfer == NULL || last.seek == NULL ||
405 1.1 blymn last.rbytes == NULL || last.wbytes == NULL ||
406 1.1 blymn cur.select == NULL || cur.name == NULL)
407 1.1 blymn errx(1, "Memory allocation failure.");
408 1.1 blymn
409 1.1 blymn /* Set up the compatibility interfaces. */
410 1.1 blymn drv_select = cur.select;
411 1.1 blymn dr_name = cur.name;
412 1.1 blymn
413 1.1 blymn /* Read the drive names and set intial selection. */
414 1.1 blymn if (memf == NULL) {
415 1.1 blymn mib[0] = CTL_HW; /* Should be still set from */
416 1.1 blymn mib[1] = HW_IOSTATS; /* ... above, but be safe... */
417 1.1 blymn mib[2] = sizeof(struct io_sysctl);
418 1.1 blymn if (sysctl(mib, 3, drives, &size, NULL, 0) == -1)
419 1.1 blymn err(1, "sysctl hw.iostats failed");
420 1.1 blymn for (i = 0; i < ndrive; i++) {
421 1.1 blymn cur.name[i] = drives[i].name;
422 1.1 blymn cur.select[i] = selected;
423 1.1 blymn }
424 1.1 blymn } else {
425 1.1 blymn p = iostathead;
426 1.1 blymn for (i = 0; i < ndrive; i++) {
427 1.1 blymn char buf[10];
428 1.1 blymn deref_kptr(p, &cur_drive, sizeof(cur_drive));
429 1.1 blymn deref_kptr(cur_drive.name, buf, sizeof(buf));
430 1.1 blymn cur.name[i] = strdup(buf);
431 1.1 blymn if (!cur.name[i])
432 1.1 blymn err(1, "strdup");
433 1.1 blymn cur.select[i] = selected;
434 1.1 blymn
435 1.1 blymn p = cur_drive.link.tqe_next;
436 1.1 blymn }
437 1.1 blymn }
438 1.1 blymn
439 1.1 blymn /* Never do this initialization again. */
440 1.1 blymn once = 1;
441 1.1 blymn return (1);
442 1.1 blymn }
443 1.1 blymn
444 1.1 blymn /*
445 1.1 blymn * Dereference the kernel pointer `kptr' and fill in the local copy
446 1.1 blymn * pointed to by `ptr'. The storage space must be pre-allocated,
447 1.1 blymn * and the size of the copy passed in `len'.
448 1.1 blymn */
449 1.1 blymn static void
450 1.1 blymn deref_kptr(void *kptr, void *ptr, size_t len)
451 1.1 blymn {
452 1.1 blymn char buf[128];
453 1.1 blymn
454 1.1 blymn if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
455 1.1 blymn memset(buf, 0, sizeof(buf));
456 1.1 blymn snprintf(buf, sizeof buf, "can't dereference kptr 0x%lx",
457 1.1 blymn (u_long)kptr);
458 1.1 blymn KVM_ERROR(buf);
459 1.1 blymn }
460 1.1 blymn }
461