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