xref: /dragonfly/lib/libkvm/kvm.c (revision 2883267451709ba7b19e97e2aa5ca87bbcb134a8)
1 /*-
2  * Copyright (c) 1989, 1992, 1993
3  *        The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software developed by the Computer Systems
6  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7  * BG 91-66 and contributed to Berkeley.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)kvm.c        8.2 (Berkeley) 2/13/94
34  * $FreeBSD: src/lib/libkvm/kvm.c,v 1.12.2.3 2002/09/13 14:53:43 nectar Exp $
35  */
36 
37 #include <sys/user.h>         /* MUST BE FIRST */
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/sysctl.h>
42 #include <sys/linker.h>
43 
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/swap_pager.h>
47 
48 #include <machine/vmparam.h>
49 
50 #include <ctype.h>
51 #include <fcntl.h>
52 #include <limits.h>
53 #include <nlist.h>
54 #include <paths.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <stdarg.h>
59 #include <unistd.h>
60 
61 #include "kvm.h"
62 #include "kvm_private.h"
63 
64 /* from src/lib/libc/gen/nlist.c */
65 int __fdnlist                 (int, struct nlist *);
66 
67 static int
kvm_notrans(kvm_t * kd)68 kvm_notrans(kvm_t *kd)
69 {
70           return kvm_ishost(kd) || kvm_isvkernel(kd);
71 }
72 
73 char *
kvm_geterr(kvm_t * kd)74 kvm_geterr(kvm_t *kd)
75 {
76           return (kd->errbuf);
77 }
78 
79 /*
80  * Report an error using printf style arguments.  "program" is kd->program
81  * on hard errors, and 0 on soft errors, so that under sun error emulation,
82  * only hard errors are printed out (otherwise, programs like gdb will
83  * generate tons of error messages when trying to access bogus pointers).
84  */
85 void
_kvm_err(kvm_t * kd,const char * program,const char * fmt,...)86 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
87 {
88           va_list ap;
89 
90           va_start(ap, fmt);
91           if (program != NULL) {
92                     (void)fprintf(stderr, "%s: ", program);
93                     (void)vfprintf(stderr, fmt, ap);
94                     (void)fputc('\n', stderr);
95           } else
96                     (void)vsnprintf(kd->errbuf,
97                         sizeof(kd->errbuf), fmt, ap);
98 
99           va_end(ap);
100 }
101 
102 void
_kvm_syserr(kvm_t * kd,const char * program,const char * fmt,...)103 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
104 {
105           va_list ap;
106           int n;
107 
108           va_start(ap, fmt);
109           if (program != NULL) {
110                     (void)fprintf(stderr, "%s: ", program);
111                     (void)vfprintf(stderr, fmt, ap);
112                     (void)fprintf(stderr, ": %s\n", strerror(errno));
113           } else {
114                     char *cp = kd->errbuf;
115 
116                     (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap);
117                     n = strlen(cp);
118                     (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s",
119                         strerror(errno));
120           }
121           va_end(ap);
122 }
123 
124 void *
_kvm_malloc(kvm_t * kd,size_t n)125 _kvm_malloc(kvm_t *kd, size_t n)
126 {
127           void *p;
128 
129           if ((p = calloc(n, sizeof(char))) == NULL)
130                     _kvm_err(kd, kd->program, "can't allocate %zd bytes: %s",
131                                n, strerror(errno));
132           return (p);
133 }
134 
135 static int
is_proc_mem(const char * p)136 is_proc_mem(const char *p)
137 {
138           static char proc[] = "/proc/";
139           static char mem[] = "/mem";
140           if (strncmp(proc, p, sizeof(proc) - 1))
141                     return 0;
142           p += sizeof(proc) - 1;
143           for (; *p != '\0'; ++p)
144                     if (!isdigit(*p))
145                               break;
146           if (!isdigit(*(p - 1)))
147                     return 0;
148           return !strncmp(p, mem, sizeof(mem) - 1);
149 }
150 
151 static kvm_t *
_kvm_open(kvm_t * kd,const char * uf,const char * mf,int flag,char * errout)152 _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout)
153 {
154           struct stat st;
155 
156           kd->vmfd = -1;
157           kd->pmfd = -1;
158           kd->nlfd = -1;
159           kd->vmst = 0;
160           kd->procbase = NULL;
161           kd->procend = NULL;
162           kd->argspc = 0;
163           kd->argv = 0;
164           kd->flags = 0;
165 
166           if (uf == NULL)
167                     uf = getbootfile();
168           else if (strlen(uf) >= MAXPATHLEN) {
169                     _kvm_err(kd, kd->program, "exec file name too long");
170                     goto failed;
171           }
172           if (flag & ~O_RDWR) {
173                     _kvm_err(kd, kd->program, "bad flags arg");
174                     goto failed;
175           }
176           if (mf == NULL)
177                     mf = _PATH_MEM;
178 
179           if ((kd->pmfd = open(mf, flag, 0)) < 0) {
180                     _kvm_syserr(kd, kd->program, "%s", mf);
181                     goto failed;
182           }
183           if (fstat(kd->pmfd, &st) < 0) {
184                     _kvm_syserr(kd, kd->program, "%s", mf);
185                     goto failed;
186           }
187           if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) {
188                     _kvm_syserr(kd, kd->program, "%s", mf);
189                     goto failed;
190           }
191           if (S_ISCHR(st.st_mode)) {
192                     /*
193                      * If this is a character special device, then check that
194                      * it's /dev/mem.  If so, open kmem too.  (Maybe we should
195                      * make it work for either /dev/mem or /dev/kmem -- in either
196                      * case you're working with a live kernel.)
197                      */
198                     if (strcmp(mf, _PATH_DEVNULL) == 0) {
199                               kd->vmfd = open(_PATH_DEVNULL, O_RDONLY);
200                     } else {
201                               if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
202                                         _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
203                                         goto failed;
204                               }
205                               if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) {
206                                         _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
207                                         goto failed;
208                               }
209                     }
210                     kd->flags |= KVMF_HOST;
211           } else {
212                     /*
213                      * Crash dump or vkernel /proc/$pid/mem file:
214                      * can't use kldsym, we are going to need ->nlfd
215                      */
216                     if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
217                               _kvm_syserr(kd, kd->program, "%s", uf);
218                               goto failed;
219                     }
220                     if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) {
221                               _kvm_syserr(kd, kd->program, "%s", uf);
222                               goto failed;
223                     }
224                     if(is_proc_mem(mf)) {
225                               /*
226                                * It's /proc/$pid/mem, so we rely on the host
227                                * kernel to do address translation for us.
228                                */
229                               kd->vmfd = kd->pmfd;
230                               kd->pmfd = -1;
231                               kd->flags |= KVMF_VKERN;
232                     } else {
233                               if (st.st_size <= 0) {
234                                         errno = EINVAL;
235                                         _kvm_syserr(kd, kd->program, "empty file");
236                                         goto failed;
237                               }
238 
239                               /*
240                                * This is a crash dump.
241                                * Initialize the virtual address translation machinery,
242                                * but first setup the namelist fd.
243                                */
244                               if (_kvm_initvtop(kd) < 0)
245                                         goto failed;
246                     }
247           }
248           return (kd);
249 failed:
250           /*
251            * Copy out the error if doing sane error semantics.
252            */
253           if (errout != NULL)
254                     strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX);
255           (void)kvm_close(kd);
256           return (0);
257 }
258 
259 kvm_t *
kvm_openfiles(const char * uf,const char * mf,const char * sf __unused,int flag,char * errout)260 kvm_openfiles(const char *uf, const char *mf, const char *sf __unused, int flag,
261                 char *errout)
262 {
263           kvm_t *kd;
264 
265           if ((kd = malloc(sizeof(*kd))) == NULL) {
266                     (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX);
267                     return (0);
268           }
269           memset(kd, 0, sizeof(*kd));
270           kd->program = 0;
271           return (_kvm_open(kd, uf, mf, flag, errout));
272 }
273 
274 kvm_t *
kvm_open(const char * uf,const char * mf,const char * sf __unused,int flag,const char * errstr)275 kvm_open(const char *uf, const char *mf, const char *sf __unused, int flag,
276            const char *errstr)
277 {
278           kvm_t *kd;
279 
280           if ((kd = malloc(sizeof(*kd))) == NULL) {
281                     if (errstr != NULL)
282                               (void)fprintf(stderr, "%s: %s\n",
283                                               errstr, strerror(errno));
284                     return (0);
285           }
286           memset(kd, 0, sizeof(*kd));
287           kd->program = errstr;
288           return (_kvm_open(kd, uf, mf, flag, NULL));
289 }
290 
291 int
kvm_close(kvm_t * kd)292 kvm_close(kvm_t *kd)
293 {
294           int error = 0;
295 
296           if (kd->pmfd >= 0)
297                     error |= close(kd->pmfd);
298           if (kd->vmfd >= 0)
299                     error |= close(kd->vmfd);
300           if (kd->nlfd >= 0)
301                     error |= close(kd->nlfd);
302           if (kd->vmst)
303                     _kvm_freevtop(kd);
304           if (kd->procbase != NULL)
305                     free(kd->procbase);
306           if (kd->argv != 0)
307                     free((void *)kd->argv);
308           free((void *)kd);
309 
310           return (0);
311 }
312 
313 int
kvm_nlist(kvm_t * kd,struct nlist * nl)314 kvm_nlist(kvm_t *kd, struct nlist *nl)
315 {
316           struct nlist *p;
317           int nvalid;
318           struct kld_sym_lookup lookup;
319           int error;
320 
321           /*
322            * If we can't use the kld symbol lookup, revert to the
323            * slow library call.
324            */
325           if (!kvm_ishost(kd))
326                     return (__fdnlist(kd->nlfd, nl));
327 
328           /*
329            * We can use the kld lookup syscall.  Go through each nlist entry
330            * and look it up with a kldsym(2) syscall.
331            */
332           nvalid = 0;
333           for (p = nl; p->n_name && p->n_name[0]; ++p) {
334                     lookup.version = sizeof(lookup);
335                     lookup.symname = p->n_name;
336                     lookup.symvalue = 0;
337                     lookup.symsize = 0;
338 
339                     if (lookup.symname[0] == '_')
340                               lookup.symname++;
341 
342                     if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) {
343                               p->n_type = N_TEXT;
344                               p->n_other = 0;
345                               p->n_desc = 0;
346                               p->n_value = lookup.symvalue;
347                               ++nvalid;
348                               /* lookup.symsize */
349                     }
350           }
351           /*
352            * Return the number of entries that weren't found. If they exist,
353            * also fill internal error buffer.
354            */
355           error = ((p - nl) - nvalid);
356           if (error)
357                     _kvm_syserr(kd, kd->program, "kvm_nlist");
358           return (error);
359 }
360 
361 ssize_t
kvm_read(kvm_t * kd,u_long kva,void * buf,size_t len)362 kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len)
363 {
364           int cc;
365           void *cp;
366 
367           if (kvm_notrans(kd)) {
368                     /*
369                      * We're using /dev/kmem.  Just read straight from the
370                      * device and let the active kernel do the address translation.
371                      */
372                     errno = 0;
373                     if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
374                               _kvm_err(kd, 0, "invalid address (%lx)", kva);
375                               return (-1);
376                     }
377 
378                     /*
379                      * Try to pre-fault the user memory to reduce instances of
380                      * races within the kernel.  XXX workaround for kernel bug
381                      * where kernel does a sanity check, but user faults during
382                      * the copy can block and race against another kernel entity
383                      * unmapping the memory in question.
384                      */
385                     bzero(buf, len);
386                     cc = read(kd->vmfd, buf, len);
387                     if (cc < 0) {
388                               _kvm_syserr(kd, 0, "kvm_read");
389                               return (-1);
390                     } else if (cc < (ssize_t)len)
391                               _kvm_err(kd, kd->program, "short read");
392                     return (cc);
393           } else {
394                     cp = buf;
395                     while (len > 0) {
396                               off_t pa;
397 
398                               cc = _kvm_kvatop(kd, kva, &pa);
399                               if (cc == 0)
400                                         return (-1);
401                               if (cc > (ssize_t)len)
402                                         cc = len;
403                               errno = 0;
404                               if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
405                                         _kvm_syserr(kd, 0, _PATH_MEM);
406                                         break;
407                               }
408                               bzero(cp, cc);
409                               cc = read(kd->pmfd, cp, cc);
410                               if (cc < 0) {
411                                         _kvm_syserr(kd, kd->program, "kvm_read");
412                                         break;
413                               }
414                               /*
415                                * If kvm_kvatop returns a bogus value or our core
416                                * file is truncated, we might wind up seeking beyond
417                                * the end of the core file in which case the read will
418                                * return 0 (EOF).
419                                */
420                               if (cc == 0)
421                                         break;
422                               cp = (char *)cp + cc;
423                               kva += cc;
424                               len -= cc;
425                     }
426                     return ((char *)cp - (char *)buf);
427           }
428           /* NOTREACHED */
429 }
430 
431 char *
kvm_readstr(kvm_t * kd,u_long kva,char * buf,size_t * lenp)432 kvm_readstr(kvm_t *kd, u_long kva, char *buf, size_t *lenp)
433 {
434           size_t len, cc, pos;
435           char ch;
436           int asize = -1;
437 
438           if (buf == NULL) {
439                     asize = len = 16;
440                     buf = malloc(len);
441                     if (buf == NULL) {
442                               _kvm_syserr(kd, kd->program, "kvm_readstr");
443                               return NULL;
444                     }
445           } else {
446                     len = *lenp;
447           }
448 
449           if (kvm_notrans(kd)) {
450                     /*
451                      * We're using /dev/kmem.  Just read straight from the
452                      * device and let the active kernel do the address translation.
453                      */
454                     errno = 0;
455                     if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
456                               _kvm_err(kd, 0, "invalid address (%lx)", kva);
457                               return NULL;
458                     }
459 
460                     for (pos = 0, ch = -1; ch != 0; pos++) {
461                               cc = read(kd->vmfd, &ch, 1);
462                               if ((ssize_t)cc < 0) {
463                                         _kvm_syserr(kd, 0, "kvm_readstr");
464                                         return NULL;
465                               } else if (cc < 1)
466                                         _kvm_err(kd, kd->program, "short read");
467                               if (asize > 0 && asize == (ssize_t)pos) {
468                                         buf = realloc(buf, asize *= 2);
469                                         if (buf == NULL) {
470                                                   _kvm_syserr(kd, kd->program, "kvm_readstr");
471                                                   return NULL;
472                                         }
473                                         len = asize;
474                               }
475                               if (pos < len)
476                                         buf[pos] = ch;
477                     }
478 
479                     if (lenp != NULL)
480                               *lenp = pos;
481                     if (pos > len)
482                               return NULL;
483                     else
484                               return buf;
485           } else {
486                     size_t left = 0;
487                     for (pos = 0, ch = -1; ch != 0; pos++, left--, kva++) {
488                               if (left == 0) {
489                                         off_t pa;
490 
491                                         left = _kvm_kvatop(kd, kva, &pa);
492                                         if (left == 0)
493                                                   return NULL;
494                                         errno = 0;
495                                         if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
496                                                   _kvm_syserr(kd, 0, _PATH_MEM);
497                                                   return NULL;
498                                         }
499                               }
500                               cc = read(kd->pmfd, &ch, 1);
501                               if ((ssize_t)cc < 0) {
502                                         _kvm_syserr(kd, 0, "kvm_readstr");
503                                         return NULL;
504                               } else if (cc < 1)
505                                         _kvm_err(kd, kd->program, "short read");
506                               if (asize > 0 && asize == (ssize_t)pos) {
507                                         buf = realloc(buf, asize *= 2);
508                                         if (buf == NULL) {
509                                                   _kvm_syserr(kd, kd->program, "kvm_readstr");
510                                                   return NULL;
511                                         }
512                                         len = asize;
513                               }
514                               if (pos < len)
515                                         buf[pos] = ch;
516                     }
517 
518                     if (lenp != NULL)
519                               *lenp = pos;
520                     if (pos > len)
521                               return NULL;
522                     else
523                               return buf;
524           }
525           /* NOTREACHED */
526 }
527 
528 ssize_t
kvm_write(kvm_t * kd,u_long kva,const void * buf,size_t len)529 kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
530 {
531           int cc;
532 
533           if (kvm_notrans(kd)) {
534                     /*
535                      * Just like kvm_read, only we write.
536                      */
537                     errno = 0;
538                     if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
539                               _kvm_err(kd, 0, "invalid address (%lx)", kva);
540                               return (-1);
541                     }
542                     cc = write(kd->vmfd, buf, len);
543                     if (cc < 0) {
544                               _kvm_syserr(kd, 0, "kvm_write");
545                               return (-1);
546                     } else if (cc < (ssize_t)len)
547                               _kvm_err(kd, kd->program, "short write");
548                     return (cc);
549           } else {
550                     _kvm_err(kd, kd->program,
551                         "kvm_write not implemented for dead kernels");
552                     return (-1);
553           }
554           /* NOTREACHED */
555 }
556