1 /* $NetBSD: kvm.c,v 1.110 2022/01/10 19:51:30 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1989, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software developed by the Computer Systems
8 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
9 * BG 91-66 and contributed to Berkeley.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94";
40 #else
41 __RCSID("$NetBSD: kvm.c,v 1.110 2022/01/10 19:51:30 christos Exp $");
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44
45 #include <sys/param.h>
46 #include <sys/lwp.h>
47 #include <sys/proc.h>
48 #include <sys/ioctl.h>
49 #include <sys/stat.h>
50 #include <sys/sysctl.h>
51 #include <sys/mman.h>
52
53 #include <sys/core.h>
54 #include <sys/exec.h>
55 #include <sys/kcore.h>
56 #include <sys/ksyms.h>
57 #include <sys/types.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <machine/cpu.h>
62
63 #include <ctype.h>
64 #include <errno.h>
65 #include <fcntl.h>
66 #include <limits.h>
67 #include <nlist.h>
68 #include <paths.h>
69 #include <stdarg.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include <kvm.h>
75
76 #include "kvm_private.h"
77
78 static int _kvm_get_header(kvm_t *);
79 static kvm_t *_kvm_open(kvm_t *, const char *, const char *,
80 const char *, int, char *);
81 static int clear_gap(kvm_t *, bool (*)(void *, const void *, size_t),
82 void *, size_t);
83 static off_t Lseek(kvm_t *, int, off_t, int);
84 static ssize_t Pread(kvm_t *, int, void *, size_t, off_t);
85
86 char *
kvm_geterr(kvm_t * kd)87 kvm_geterr(kvm_t *kd)
88 {
89 return (kd->errbuf);
90 }
91
92 const char *
kvm_getkernelname(kvm_t * kd)93 kvm_getkernelname(kvm_t *kd)
94 {
95 return kd->kernelname;
96 }
97
98 /*
99 * Report an error using printf style arguments. "program" is kd->program
100 * on hard errors, and 0 on soft errors, so that under sun error emulation,
101 * only hard errors are printed out (otherwise, programs like gdb will
102 * generate tons of error messages when trying to access bogus pointers).
103 */
104 void
_kvm_err(kvm_t * kd,const char * program,const char * fmt,...)105 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
106 {
107 va_list ap;
108
109 va_start(ap, fmt);
110 if (program != NULL) {
111 (void)fprintf(stderr, "%s: ", program);
112 (void)vfprintf(stderr, fmt, ap);
113 (void)fputc('\n', stderr);
114 } else
115 (void)vsnprintf(kd->errbuf,
116 sizeof(kd->errbuf), fmt, ap);
117
118 va_end(ap);
119 }
120
121 void
_kvm_syserr(kvm_t * kd,const char * program,const char * fmt,...)122 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
123 {
124 va_list ap;
125 size_t n;
126
127 va_start(ap, fmt);
128 if (program != NULL) {
129 (void)fprintf(stderr, "%s: ", program);
130 (void)vfprintf(stderr, fmt, ap);
131 (void)fprintf(stderr, ": %s\n", strerror(errno));
132 } else {
133 char *cp = kd->errbuf;
134
135 (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap);
136 n = strlen(cp);
137 (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
138 strerror(errno));
139 }
140 va_end(ap);
141 }
142
143 void *
_kvm_malloc(kvm_t * kd,size_t n)144 _kvm_malloc(kvm_t *kd, size_t n)
145 {
146 void *p;
147
148 if ((p = malloc(n)) == NULL)
149 _kvm_err(kd, kd->program, "%s", strerror(errno));
150 return (p);
151 }
152
153 /*
154 * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us
155 * in the event of emergency.
156 */
157 static off_t
Lseek(kvm_t * kd,int fd,off_t offset,int whence)158 Lseek(kvm_t *kd, int fd, off_t offset, int whence)
159 {
160 off_t off;
161
162 errno = 0;
163
164 if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) {
165 _kvm_syserr(kd, kd->program, "Lseek");
166 return ((off_t)-1);
167 }
168 return (off);
169 }
170
171 ssize_t
_kvm_pread(kvm_t * kd,int fd,void * buf,size_t size,off_t off)172 _kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off)
173 {
174 ptrdiff_t moff;
175 void *newbuf;
176 size_t dsize;
177 ssize_t rv;
178 off_t doff;
179
180 if (kd->dump_mem != MAP_FAILED) {
181 if (size + off > kd->dump_size) {
182 errno = EINVAL;
183 return -1;
184 }
185 memcpy(buf, (char *)kd->dump_mem + (size_t)off, size);
186 return size;
187 }
188
189 /* If aligned nothing to do. */
190 if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) {
191 return pread(fd, buf, size, off);
192 }
193
194 /*
195 * Otherwise must buffer. We can't tolerate short reads in this
196 * case (lazy bum).
197 */
198 moff = (ptrdiff_t)off % kd->fdalign;
199 doff = off - moff;
200 dsize = moff + size + kd->fdalign - 1;
201 dsize -= dsize % kd->fdalign;
202 if (kd->iobufsz < dsize) {
203 newbuf = realloc(kd->iobuf, dsize);
204 if (newbuf == NULL) {
205 _kvm_syserr(kd, 0, "cannot allocate I/O buffer");
206 return (-1);
207 }
208 kd->iobuf = newbuf;
209 kd->iobufsz = dsize;
210 }
211 rv = pread(fd, kd->iobuf, dsize, doff);
212 if (rv < size + moff)
213 return -1;
214 memcpy(buf, kd->iobuf + moff, size);
215 return size;
216 }
217
218 static ssize_t
_kvm_pwrite(kvm_t * kd,const void * buf,size_t size,off_t off)219 _kvm_pwrite(kvm_t *kd, const void *buf, size_t size, off_t off)
220 {
221 char *mem = kd->dump_mem;
222
223 if (size + off > kd->dump_size) {
224 errno = EINVAL;
225 return -1;
226 }
227 memcpy(mem + (size_t)off, buf, size);
228 return size;
229 }
230
231 /*
232 * Wrapper around the pread(2) system call; calls _kvm_syserr() for us
233 * in the event of emergency.
234 */
235 static ssize_t
Pread(kvm_t * kd,int fd,void * buf,size_t nbytes,off_t offset)236 Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset)
237 {
238 ssize_t rv;
239
240 errno = 0;
241
242 if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes &&
243 errno != 0)
244 _kvm_syserr(kd, kd->program, "Pread");
245 return (rv);
246 }
247
248 static kvm_t *
_kvm_open(kvm_t * kd,const char * uf,const char * mf,const char * sf,int flag,char * errout)249 _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag,
250 char *errout)
251 {
252 struct stat st;
253 int ufgiven;
254
255 kd->pmfd = -1;
256 kd->vmfd = -1;
257 kd->swfd = -1;
258 kd->nlfd = -1;
259 kd->alive = KVM_ALIVE_DEAD;
260 kd->procbase = NULL;
261 kd->procbase_len = 0;
262 kd->procbase2 = NULL;
263 kd->procbase2_len = 0;
264 kd->lwpbase = NULL;
265 kd->lwpbase_len = 0;
266 kd->nbpg = getpagesize();
267 kd->swapspc = NULL;
268 kd->argspc = NULL;
269 kd->argspc_len = 0;
270 kd->argbuf = NULL;
271 kd->argv = NULL;
272 kd->vmst = NULL;
273 kd->vm_page_buckets = NULL;
274 kd->kcore_hdr = NULL;
275 kd->cpu_dsize = 0;
276 kd->cpu_data = NULL;
277 kd->dump_off = 0;
278 kd->fdalign = 1;
279 kd->iobuf = NULL;
280 kd->iobufsz = 0;
281 kd->errbuf[0] = '\0';
282 kd->dump_mem = MAP_FAILED;
283 kd->dump_size = 0;
284
285 if (flag & KVM_NO_FILES) {
286 kd->alive = KVM_ALIVE_SYSCTL;
287 return(kd);
288 }
289
290 /*
291 * Call the MD open hook. This sets:
292 * min_uva, max_uva
293 */
294 if (_kvm_mdopen(kd)) {
295 _kvm_err(kd, kd->program, "md init failed");
296 goto failed;
297 }
298
299 ufgiven = (uf != NULL);
300 if (!ufgiven) {
301 #ifdef CPU_BOOTED_KERNEL
302 /* 130 is 128 + '/' + '\0' */
303 static char booted_kernel[130];
304 int mib[2], rc;
305 size_t len;
306
307 mib[0] = CTL_MACHDEP;
308 mib[1] = CPU_BOOTED_KERNEL;
309 booted_kernel[0] = '/';
310 booted_kernel[1] = '\0';
311 len = sizeof(booted_kernel) - 2;
312 rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0);
313 booted_kernel[sizeof(booted_kernel) - 1] = '\0';
314 uf = (booted_kernel[1] == '/') ?
315 &booted_kernel[1] : &booted_kernel[0];
316 if (rc != -1)
317 rc = stat(uf, &st);
318 if (rc != -1 && !S_ISREG(st.st_mode))
319 rc = -1;
320 if (rc == -1)
321 #endif /* CPU_BOOTED_KERNEL */
322 uf = _PATH_UNIX;
323 }
324 else if (strlen(uf) >= MAXPATHLEN) {
325 _kvm_err(kd, kd->program, "exec file name too long");
326 goto failed;
327 }
328 if (flag & ~O_RDWR) {
329 _kvm_err(kd, kd->program, "bad flags arg");
330 goto failed;
331 }
332 if (mf == 0)
333 mf = _PATH_MEM;
334 if (sf == 0)
335 sf = _PATH_DRUM;
336
337 /*
338 * Open the kernel namelist. If /dev/ksyms doesn't
339 * exist, open the current kernel.
340 */
341 if (ufgiven == 0)
342 kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0);
343 if (kd->nlfd < 0) {
344 if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
345 _kvm_syserr(kd, kd->program, "%s", uf);
346 goto failed;
347 }
348 strlcpy(kd->kernelname, uf, sizeof(kd->kernelname));
349 } else {
350 strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname));
351 }
352
353 if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) {
354 _kvm_syserr(kd, kd->program, "%s", mf);
355 goto failed;
356 }
357 if (fstat(kd->pmfd, &st) < 0) {
358 _kvm_syserr(kd, kd->program, "%s", mf);
359 goto failed;
360 }
361 if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) {
362 /*
363 * If this is /dev/mem, open kmem too. (Maybe we should
364 * make it work for either /dev/mem or /dev/kmem -- in either
365 * case you're working with a live kernel.)
366 */
367 if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) {
368 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
369 goto failed;
370 }
371 kd->alive = KVM_ALIVE_FILES;
372 if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) {
373 if (errno != ENXIO) {
374 _kvm_syserr(kd, kd->program, "%s", sf);
375 goto failed;
376 }
377 /* swap is not configured? not fatal */
378 }
379 } else {
380 if (S_ISCHR(st.st_mode)) {
381 kd->fdalign = DEV_BSIZE;
382 } else {
383 kd->fdalign = 1;
384 }
385
386 /*
387 * This is a crash dump.
388 * Initialize the virtual address translation machinery.
389 *
390 * If there is no valid core header, fail silently here.
391 * The address translations however will fail without
392 * header. Things can be made to run by calling
393 * kvm_dump_mkheader() before doing any translation.
394 */
395 if (_kvm_get_header(kd) == 0) {
396 if (_kvm_initvtop(kd) < 0)
397 goto failed;
398 }
399 kd->dump_size = (size_t)st.st_size;
400 kd->dump_mem = mmap(NULL, kd->dump_size, PROT_READ|PROT_WRITE,
401 MAP_FILE|MAP_PRIVATE, kd->pmfd, 0);
402 }
403 return (kd);
404 failed:
405 /*
406 * Copy out the error if doing sane error semantics.
407 */
408 if (errout != 0)
409 (void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
410 (void)kvm_close(kd);
411 return (0);
412 }
413
414 /*
415 * The kernel dump file (from savecore) contains:
416 * kcore_hdr_t kcore_hdr;
417 * kcore_seg_t cpu_hdr;
418 * (opaque) cpu_data; (size is cpu_hdr.c_size)
419 * kcore_seg_t mem_hdr;
420 * (memory) mem_data; (size is mem_hdr.c_size)
421 *
422 * Note: khdr is padded to khdr.c_hdrsize;
423 * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize
424 */
425 static int
_kvm_get_header(kvm_t * kd)426 _kvm_get_header(kvm_t *kd)
427 {
428 kcore_hdr_t kcore_hdr;
429 kcore_seg_t cpu_hdr;
430 kcore_seg_t mem_hdr;
431 size_t offset;
432 ssize_t sz;
433
434 /*
435 * Read the kcore_hdr_t
436 */
437 sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0);
438 if (sz != sizeof(kcore_hdr))
439 return (-1);
440
441 /*
442 * Currently, we only support dump-files made by the current
443 * architecture...
444 */
445 if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) ||
446 (CORE_GETMID(kcore_hdr) != MID_MACHINE))
447 return (-1);
448
449 /*
450 * Currently, we only support exactly 2 segments: cpu-segment
451 * and data-segment in exactly that order.
452 */
453 if (kcore_hdr.c_nseg != 2)
454 return (-1);
455
456 /*
457 * Save away the kcore_hdr. All errors after this
458 * should do a to "goto fail" to deallocate things.
459 */
460 kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr));
461 memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr));
462 offset = kcore_hdr.c_hdrsize;
463
464 /*
465 * Read the CPU segment header
466 */
467 sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset);
468 if (sz != sizeof(cpu_hdr))
469 goto fail;
470 if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) ||
471 (CORE_GETFLAG(cpu_hdr) != CORE_CPU))
472 goto fail;
473 offset += kcore_hdr.c_seghdrsize;
474
475 /*
476 * Read the CPU segment DATA.
477 */
478 kd->cpu_dsize = cpu_hdr.c_size;
479 kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size);
480 if (kd->cpu_data == NULL)
481 goto fail;
482 sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset);
483 if (sz != cpu_hdr.c_size)
484 goto fail;
485 offset += cpu_hdr.c_size;
486
487 /*
488 * Read the next segment header: data segment
489 */
490 sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset);
491 if (sz != sizeof(mem_hdr))
492 goto fail;
493 offset += kcore_hdr.c_seghdrsize;
494
495 if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) ||
496 (CORE_GETFLAG(mem_hdr) != CORE_DATA))
497 goto fail;
498
499 kd->dump_off = offset;
500 return (0);
501
502 fail:
503 if (kd->kcore_hdr != NULL) {
504 free(kd->kcore_hdr);
505 kd->kcore_hdr = NULL;
506 }
507 if (kd->cpu_data != NULL) {
508 free(kd->cpu_data);
509 kd->cpu_data = NULL;
510 kd->cpu_dsize = 0;
511 }
512 return (-1);
513 }
514
515 /*
516 * The format while on the dump device is: (new format)
517 * kcore_seg_t cpu_hdr;
518 * (opaque) cpu_data; (size is cpu_hdr.c_size)
519 * kcore_seg_t mem_hdr;
520 * (memory) mem_data; (size is mem_hdr.c_size)
521 */
522 int
kvm_dump_mkheader(kvm_t * kd,off_t dump_off)523 kvm_dump_mkheader(kvm_t *kd, off_t dump_off)
524 {
525 kcore_seg_t cpu_hdr;
526 size_t hdr_size;
527 ssize_t sz;
528
529 if (kd->kcore_hdr != NULL) {
530 _kvm_err(kd, kd->program, "already has a dump header");
531 return (-1);
532 }
533 if (ISALIVE(kd)) {
534 _kvm_err(kd, kd->program, "don't use on live kernel");
535 return (-1);
536 }
537
538 /*
539 * Validate new format crash dump
540 */
541 sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off);
542 if (sz != sizeof(cpu_hdr)) {
543 if (sz == -1)
544 _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64
545 " for cpu_hdr failed: %s", sizeof(cpu_hdr),
546 dump_off, strerror(errno));
547 else
548 _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64
549 " for cpu_hdr instead of requested %zu",
550 sz, dump_off, sizeof(cpu_hdr));
551 return (-1);
552 }
553 if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC)
554 || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) {
555 _kvm_err(kd, 0, "invalid magic in cpu_hdr");
556 return (0);
557 }
558 hdr_size = ALIGN(sizeof(cpu_hdr));
559
560 /*
561 * Read the CPU segment.
562 */
563 kd->cpu_dsize = cpu_hdr.c_size;
564 kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize);
565 if (kd->cpu_data == NULL) {
566 _kvm_err(kd, kd->program, "no cpu_data");
567 goto fail;
568 }
569 sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size,
570 dump_off + hdr_size);
571 if (sz != cpu_hdr.c_size) {
572 _kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %"PRIu32,
573 sz, cpu_hdr.c_size);
574 goto fail;
575 }
576 hdr_size += kd->cpu_dsize;
577
578 /*
579 * Leave phys mem pointer at beginning of memory data
580 */
581 kd->dump_off = dump_off + hdr_size;
582 if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) {
583 _kvm_err(kd, kd->program, "failed to seek to %" PRId64,
584 (int64_t)kd->dump_off);
585 goto fail;
586 }
587
588 /*
589 * Create a kcore_hdr.
590 */
591 kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t));
592 if (kd->kcore_hdr == NULL) {
593 _kvm_err(kd, kd->program, "failed to allocate header");
594 goto fail;
595 }
596
597 kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t));
598 kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t));
599 kd->kcore_hdr->c_nseg = 2;
600 CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0);
601
602 /*
603 * Now that we have a valid header, enable translations.
604 */
605 if (_kvm_initvtop(kd) == 0)
606 /* Success */
607 return (hdr_size);
608
609 fail:
610 if (kd->kcore_hdr != NULL) {
611 free(kd->kcore_hdr);
612 kd->kcore_hdr = NULL;
613 }
614 if (kd->cpu_data != NULL) {
615 free(kd->cpu_data);
616 kd->cpu_data = NULL;
617 kd->cpu_dsize = 0;
618 }
619 return (-1);
620 }
621
622 static int
clear_gap(kvm_t * kd,bool (* write_buf)(void *,const void *,size_t),void * cookie,size_t size)623 clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t),
624 void *cookie, size_t size)
625 {
626 char buf[1024];
627 size_t len;
628
629 (void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size);
630
631 while (size > 0) {
632 len = size > sizeof(buf) ? sizeof(buf) : size;
633 if (!(*write_buf)(cookie, buf, len)) {
634 _kvm_syserr(kd, kd->program, "clear_gap");
635 return -1;
636 }
637 size -= len;
638 }
639
640 return 0;
641 }
642
643 /*
644 * Write the dump header by calling write_buf with cookie as first argument.
645 */
646 int
kvm_dump_header(kvm_t * kd,bool (* write_buf)(void *,const void *,size_t),void * cookie,int dumpsize)647 kvm_dump_header(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t),
648 void *cookie, int dumpsize)
649 {
650 kcore_seg_t seghdr;
651 long offset;
652 size_t gap;
653
654 if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) {
655 _kvm_err(kd, kd->program, "no valid dump header(s)");
656 return (-1);
657 }
658
659 /*
660 * Write the generic header
661 */
662 offset = 0;
663 if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) {
664 _kvm_syserr(kd, kd->program, "kvm_dump_header");
665 return (-1);
666 }
667 offset += kd->kcore_hdr->c_hdrsize;
668 gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t);
669 if (clear_gap(kd, write_buf, cookie, gap) == -1)
670 return (-1);
671
672 /*
673 * Write the CPU header
674 */
675 CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU);
676 seghdr.c_size = ALIGN(kd->cpu_dsize);
677 if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) {
678 _kvm_syserr(kd, kd->program, "kvm_dump_header");
679 return (-1);
680 }
681 offset += kd->kcore_hdr->c_seghdrsize;
682 gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
683 if (clear_gap(kd, write_buf, cookie, gap) == -1)
684 return (-1);
685
686 if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) {
687 _kvm_syserr(kd, kd->program, "kvm_dump_header");
688 return (-1);
689 }
690 offset += seghdr.c_size;
691 gap = seghdr.c_size - kd->cpu_dsize;
692 if (clear_gap(kd, write_buf, cookie, gap) == -1)
693 return (-1);
694
695 /*
696 * Write the actual dump data segment header
697 */
698 CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA);
699 seghdr.c_size = dumpsize;
700 if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) {
701 _kvm_syserr(kd, kd->program, "kvm_dump_header");
702 return (-1);
703 }
704 offset += kd->kcore_hdr->c_seghdrsize;
705 gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr);
706 if (clear_gap(kd, write_buf, cookie, gap) == -1)
707 return (-1);
708
709 return (int)offset;
710 }
711
712 static bool
kvm_dump_header_stdio(void * cookie,const void * buf,size_t len)713 kvm_dump_header_stdio(void *cookie, const void *buf, size_t len)
714 {
715 return fwrite(buf, len, 1, (FILE *)cookie) == 1;
716 }
717
718 int
kvm_dump_wrtheader(kvm_t * kd,FILE * fp,int dumpsize)719 kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize)
720 {
721 return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize);
722 }
723
724 kvm_t *
kvm_openfiles(const char * uf,const char * mf,const char * sf,int flag,char * errout)725 kvm_openfiles(const char *uf, const char *mf, const char *sf,
726 int flag, char *errout)
727 {
728 kvm_t *kd;
729
730 if ((kd = malloc(sizeof(*kd))) == NULL) {
731 (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
732 return (0);
733 }
734 kd->program = 0;
735 return (_kvm_open(kd, uf, mf, sf, flag, errout));
736 }
737
738 kvm_t *
kvm_open(const char * uf,const char * mf,const char * sf,int flag,const char * program)739 kvm_open(const char *uf, const char *mf, const char *sf, int flag,
740 const char *program)
741 {
742 kvm_t *kd;
743
744 if ((kd = malloc(sizeof(*kd))) == NULL) {
745 (void)fprintf(stderr, "%s: %s\n",
746 program ? program : getprogname(), strerror(errno));
747 return (0);
748 }
749 kd->program = program;
750 return (_kvm_open(kd, uf, mf, sf, flag, NULL));
751 }
752
753 int
kvm_close(kvm_t * kd)754 kvm_close(kvm_t *kd)
755 {
756 int error = 0;
757
758 if (kd->pmfd >= 0)
759 error |= close(kd->pmfd);
760 if (kd->vmfd >= 0)
761 error |= close(kd->vmfd);
762 if (kd->nlfd >= 0)
763 error |= close(kd->nlfd);
764 if (kd->swfd >= 0)
765 error |= close(kd->swfd);
766 if (kd->vmst)
767 _kvm_freevtop(kd);
768 kd->cpu_dsize = 0;
769 if (kd->cpu_data != NULL)
770 free(kd->cpu_data);
771 if (kd->kcore_hdr != NULL)
772 free(kd->kcore_hdr);
773 if (kd->procbase != 0)
774 free(kd->procbase);
775 if (kd->procbase2 != 0)
776 free(kd->procbase2);
777 if (kd->lwpbase != 0)
778 free(kd->lwpbase);
779 if (kd->swapspc != 0)
780 free(kd->swapspc);
781 if (kd->argspc != 0)
782 free(kd->argspc);
783 if (kd->argbuf != 0)
784 free(kd->argbuf);
785 if (kd->argv != 0)
786 free(kd->argv);
787 if (kd->iobuf != 0)
788 free(kd->iobuf);
789 if (kd->dump_mem != MAP_FAILED)
790 munmap(kd->dump_mem, kd->dump_size);
791 free(kd);
792
793 return (error);
794 }
795
796 int
kvm_nlist(kvm_t * kd,struct nlist * nl)797 kvm_nlist(kvm_t *kd, struct nlist *nl)
798 {
799 int rv;
800
801 /*
802 * Call the nlist(3) routines to retrieve the given namelist.
803 */
804 rv = __fdnlist(kd->nlfd, nl);
805
806 if (rv == -1)
807 _kvm_err(kd, 0, "bad namelist");
808
809 return (rv);
810 }
811
812 int
kvm_dump_inval(kvm_t * kd)813 kvm_dump_inval(kvm_t *kd)
814 {
815 struct nlist nl[2];
816 paddr_t pa;
817 size_t dsize;
818 off_t doff;
819 void *newbuf;
820
821 if (ISALIVE(kd)) {
822 _kvm_err(kd, kd->program, "clearing dump on live kernel");
823 return (-1);
824 }
825 nl[0].n_name = "_dumpmag";
826 nl[1].n_name = NULL;
827
828 if (kvm_nlist(kd, nl) == -1) {
829 _kvm_err(kd, 0, "bad namelist");
830 return (-1);
831 }
832 if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0)
833 return (-1);
834
835 errno = 0;
836 dsize = MAX(kd->fdalign, sizeof(u_long));
837 if (kd->iobufsz < dsize) {
838 newbuf = realloc(kd->iobuf, dsize);
839 if (newbuf == NULL) {
840 _kvm_syserr(kd, 0, "cannot allocate I/O buffer");
841 return (-1);
842 }
843 kd->iobuf = newbuf;
844 kd->iobufsz = dsize;
845 }
846 memset(kd->iobuf, 0, dsize);
847 doff = _kvm_pa2off(kd, pa);
848 doff -= doff % kd->fdalign;
849 if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) {
850 _kvm_syserr(kd, 0, "cannot invalidate dump - pwrite");
851 return (-1);
852 }
853 return (0);
854 }
855
856 ssize_t
kvm_read(kvm_t * kd,u_long kva,void * buf,size_t len)857 kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len)
858 {
859 int cc;
860 void *cp;
861
862 if (ISKMEM(kd)) {
863 /*
864 * We're using /dev/kmem. Just read straight from the
865 * device and let the active kernel do the address translation.
866 */
867 errno = 0;
868 cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva);
869 if (cc < 0) {
870 _kvm_syserr(kd, 0, "kvm_read");
871 return (-1);
872 } else if (cc < len)
873 _kvm_err(kd, kd->program, "short read");
874 return (cc);
875 } else if (ISSYSCTL(kd)) {
876 _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, "
877 "can't use kvm_read");
878 return (-1);
879 } else {
880 if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) {
881 _kvm_err(kd, kd->program, "no valid dump header");
882 return (-1);
883 }
884 cp = buf;
885 while (len > 0) {
886 paddr_t pa;
887 off_t foff;
888
889 cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa);
890 if (cc == 0) {
891 _kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva);
892 return (-1);
893 }
894 if (cc > len)
895 cc = len;
896 foff = _kvm_pa2off(kd, pa);
897 errno = 0;
898 cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff);
899 if (cc < 0) {
900 _kvm_syserr(kd, kd->program, "kvm_read");
901 break;
902 }
903 /*
904 * If kvm_kvatop returns a bogus value or our core
905 * file is truncated, we might wind up seeking beyond
906 * the end of the core file in which case the read will
907 * return 0 (EOF).
908 */
909 if (cc == 0)
910 break;
911 cp = (char *)cp + cc;
912 kva += cc;
913 len -= cc;
914 }
915 return ((char *)cp - (char *)buf);
916 }
917 /* NOTREACHED */
918 }
919
920 ssize_t
kvm_write(kvm_t * kd,u_long kva,const void * buf,size_t len)921 kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
922 {
923 int cc;
924 const void *cp;
925
926 if (ISKMEM(kd)) {
927 /*
928 * Just like kvm_read, only we write.
929 */
930 errno = 0;
931 cc = pwrite(kd->vmfd, buf, len, (off_t)kva);
932 if (cc < 0) {
933 _kvm_syserr(kd, 0, "kvm_write");
934 return (-1);
935 } else if (cc < len)
936 _kvm_err(kd, kd->program, "short write");
937 return (cc);
938 } else if (ISSYSCTL(kd)) {
939 _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, "
940 "can't use kvm_write");
941 return (-1);
942 } else {
943 if (kd->dump_mem == MAP_FAILED) {
944 _kvm_err(kd, kd->program,
945 "kvm_write not implemented for dead kernels");
946 return (-1);
947 }
948 cp = buf;
949 while (len > 0) {
950 paddr_t pa;
951 off_t foff;
952
953 cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa);
954 if (cc == 0) {
955 _kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva);
956 return (-1);
957 }
958 if (cc > len)
959 cc = len;
960 foff = _kvm_pa2off(kd, pa);
961 errno = 0;
962 cc = _kvm_pwrite(kd, cp, (size_t)cc, foff);
963 if (cc < 0) {
964 _kvm_syserr(kd, kd->program, "kvm_pwrite");
965 break;
966 }
967 /*
968 * If kvm_kvatop returns a bogus value or our core
969 * file is truncated, we might wind up seeking beyond
970 * the end of the core file in which case the read will
971 * return 0 (EOF).
972 */
973 if (cc == 0)
974 break;
975 cp = (const char *)cp + cc;
976 kva += cc;
977 len -= cc;
978 }
979 return ((const char *)cp - (const char *)buf);
980 }
981 /* NOTREACHED */
982 }
983