1 /*        $NetBSD: kvm.c,v 1.111 2023/08/23 14:00:11 rin 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.111 2023/08/23 14:00:11 rin 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