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 * %sccs.include.redist.c%
10 */
11
12 #if defined(LIBC_SCCS) && !defined(lint)
13 static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 02/13/94";
14 #endif /* LIBC_SCCS and not lint */
15
16 #include <sys/param.h>
17 #include <sys/user.h>
18 #include <sys/proc.h>
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #include <sys/sysctl.h>
22
23 #include <vm/vm.h>
24 #include <vm/vm_param.h>
25 #include <vm/swap_pager.h>
26
27 #include <machine/vmparam.h>
28
29 #include <ctype.h>
30 #include <db.h>
31 #include <fcntl.h>
32 #include <kvm.h>
33 #include <limits.h>
34 #include <nlist.h>
35 #include <paths.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "kvm_private.h"
42
43 static int kvm_dbopen __P((kvm_t *, const char *));
44
45 char *
kvm_geterr(kd)46 kvm_geterr(kd)
47 kvm_t *kd;
48 {
49 return (kd->errbuf);
50 }
51
52 #if __STDC__
53 #include <stdarg.h>
54 #else
55 #include <varargs.h>
56 #endif
57
58 /*
59 * Report an error using printf style arguments. "program" is kd->program
60 * on hard errors, and 0 on soft errors, so that under sun error emulation,
61 * only hard errors are printed out (otherwise, programs like gdb will
62 * generate tons of error messages when trying to access bogus pointers).
63 */
64 void
65 #if __STDC__
_kvm_err(kvm_t * kd,const char * program,const char * fmt,...)66 _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...)
67 #else
68 _kvm_err(kd, program, fmt, va_alist)
69 kvm_t *kd;
70 char *program, *fmt;
71 va_dcl
72 #endif
73 {
74 va_list ap;
75
76 #ifdef __STDC__
77 va_start(ap, fmt);
78 #else
79 va_start(ap);
80 #endif
81 if (program != NULL) {
82 (void)fprintf(stderr, "%s: ", program);
83 (void)vfprintf(stderr, fmt, ap);
84 (void)fputc('\n', stderr);
85 } else
86 (void)vsnprintf(kd->errbuf,
87 sizeof(kd->errbuf), (char *)fmt, ap);
88
89 va_end(ap);
90 }
91
92 void
93 #if __STDC__
_kvm_syserr(kvm_t * kd,const char * program,const char * fmt,...)94 _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...)
95 #else
96 _kvm_syserr(kd, program, fmt, va_alist)
97 kvm_t *kd;
98 char *program, *fmt;
99 va_dcl
100 #endif
101 {
102 va_list ap;
103 register int n;
104
105 #if __STDC__
106 va_start(ap, fmt);
107 #else
108 va_start(ap);
109 #endif
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 register char *cp = kd->errbuf;
116
117 (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)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 *
_kvm_malloc(kd,n)126 _kvm_malloc(kd, n)
127 register kvm_t *kd;
128 register size_t n;
129 {
130 void *p;
131
132 if ((p = malloc(n)) == NULL)
133 _kvm_err(kd, kd->program, strerror(errno));
134 return (p);
135 }
136
137 static kvm_t *
_kvm_open(kd,uf,mf,sf,flag,errout)138 _kvm_open(kd, uf, mf, sf, flag, errout)
139 register kvm_t *kd;
140 const char *uf;
141 const char *mf;
142 const char *sf;
143 int flag;
144 char *errout;
145 {
146 struct stat st;
147
148 kd->vmfd = -1;
149 kd->pmfd = -1;
150 kd->swfd = -1;
151 kd->nlfd = -1;
152 kd->vmst = 0;
153 kd->db = 0;
154 kd->procbase = 0;
155 kd->argspc = 0;
156 kd->argv = 0;
157
158 if (uf == 0)
159 uf = _PATH_UNIX;
160 else if (strlen(uf) >= MAXPATHLEN) {
161 _kvm_err(kd, kd->program, "exec file name too long");
162 goto failed;
163 }
164 if (flag & ~O_RDWR) {
165 _kvm_err(kd, kd->program, "bad flags arg");
166 goto failed;
167 }
168 if (mf == 0)
169 mf = _PATH_MEM;
170 if (sf == 0)
171 sf = _PATH_DRUM;
172
173 if ((kd->pmfd = open(mf, flag, 0)) < 0) {
174 _kvm_syserr(kd, kd->program, "%s", mf);
175 goto failed;
176 }
177 if (fstat(kd->pmfd, &st) < 0) {
178 _kvm_syserr(kd, kd->program, "%s", mf);
179 goto failed;
180 }
181 if (S_ISCHR(st.st_mode)) {
182 /*
183 * If this is a character special device, then check that
184 * it's /dev/mem. If so, open kmem too. (Maybe we should
185 * make it work for either /dev/mem or /dev/kmem -- in either
186 * case you're working with a live kernel.)
187 */
188 if (strcmp(mf, _PATH_MEM) != 0) { /* XXX */
189 _kvm_err(kd, kd->program,
190 "%s: not physical memory device", mf);
191 goto failed;
192 }
193 if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) {
194 _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM);
195 goto failed;
196 }
197 if ((kd->swfd = open(sf, flag, 0)) < 0) {
198 _kvm_syserr(kd, kd->program, "%s", sf);
199 goto failed;
200 }
201 /*
202 * Open kvm nlist database. We go ahead and do this
203 * here so that we don't have to hold on to the vmunix
204 * path name. Since a kvm application will surely do
205 * a kvm_nlist(), this probably won't be a wasted effort.
206 * If the database cannot be opened, open the namelist
207 * argument so we revert to slow nlist() calls.
208 */
209 if (kvm_dbopen(kd, uf) < 0 &&
210 (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
211 _kvm_syserr(kd, kd->program, "%s", uf);
212 goto failed;
213 }
214 } else {
215 /*
216 * This is a crash dump.
217 * Initalize the virtual address translation machinery,
218 * but first setup the namelist fd.
219 */
220 if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) {
221 _kvm_syserr(kd, kd->program, "%s", uf);
222 goto failed;
223 }
224 if (_kvm_initvtop(kd) < 0)
225 goto failed;
226 }
227 return (kd);
228 failed:
229 /*
230 * Copy out the error if doing sane error semantics.
231 */
232 if (errout != 0)
233 strcpy(errout, kd->errbuf);
234 (void)kvm_close(kd);
235 return (0);
236 }
237
238 kvm_t *
kvm_openfiles(uf,mf,sf,flag,errout)239 kvm_openfiles(uf, mf, sf, flag, errout)
240 const char *uf;
241 const char *mf;
242 const char *sf;
243 int flag;
244 char *errout;
245 {
246 register kvm_t *kd;
247
248 if ((kd = malloc(sizeof(*kd))) == NULL) {
249 (void)strcpy(errout, strerror(errno));
250 return (0);
251 }
252 kd->program = 0;
253 return (_kvm_open(kd, uf, mf, sf, flag, errout));
254 }
255
256 kvm_t *
kvm_open(uf,mf,sf,flag,program)257 kvm_open(uf, mf, sf, flag, program)
258 const char *uf;
259 const char *mf;
260 const char *sf;
261 int flag;
262 const char *program;
263 {
264 register kvm_t *kd;
265
266 if ((kd = malloc(sizeof(*kd))) == NULL && program != NULL) {
267 (void)fprintf(stderr, "%s: %s\n", strerror(errno));
268 return (0);
269 }
270 kd->program = program;
271 return (_kvm_open(kd, uf, mf, sf, flag, NULL));
272 }
273
274 int
kvm_close(kd)275 kvm_close(kd)
276 kvm_t *kd;
277 {
278 register int error = 0;
279
280 if (kd->pmfd >= 0)
281 error |= close(kd->pmfd);
282 if (kd->vmfd >= 0)
283 error |= close(kd->vmfd);
284 if (kd->nlfd >= 0)
285 error |= close(kd->nlfd);
286 if (kd->swfd >= 0)
287 error |= close(kd->swfd);
288 if (kd->db != 0)
289 error |= (kd->db->close)(kd->db);
290 if (kd->vmst)
291 _kvm_freevtop(kd);
292 if (kd->procbase != 0)
293 free((void *)kd->procbase);
294 if (kd->argv != 0)
295 free((void *)kd->argv);
296 free((void *)kd);
297
298 return (0);
299 }
300
301 /*
302 * Set up state necessary to do queries on the kernel namelist
303 * data base. If the data base is out-of-data/incompatible with
304 * given executable, set up things so we revert to standard nlist call.
305 * Only called for live kernels. Return 0 on success, -1 on failure.
306 */
307 static int
kvm_dbopen(kd,uf)308 kvm_dbopen(kd, uf)
309 kvm_t *kd;
310 const char *uf;
311 {
312 char *cp;
313 DBT rec;
314 int dbversionlen;
315 struct nlist nitem;
316 char dbversion[_POSIX2_LINE_MAX];
317 char kversion[_POSIX2_LINE_MAX];
318 char dbname[MAXPATHLEN];
319
320 if ((cp = rindex(uf, '/')) != 0)
321 uf = cp + 1;
322
323 (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf);
324 kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL);
325 if (kd->db == 0)
326 return (-1);
327 /*
328 * read version out of database
329 */
330 rec.data = VRS_KEY;
331 rec.size = sizeof(VRS_KEY) - 1;
332 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
333 goto close;
334 if (rec.data == 0 || rec.size > sizeof(dbversion))
335 goto close;
336
337 bcopy(rec.data, dbversion, rec.size);
338 dbversionlen = rec.size;
339 /*
340 * Read version string from kernel memory.
341 * Since we are dealing with a live kernel, we can call kvm_read()
342 * at this point.
343 */
344 rec.data = VRS_SYM;
345 rec.size = sizeof(VRS_SYM) - 1;
346 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
347 goto close;
348 if (rec.data == 0 || rec.size != sizeof(struct nlist))
349 goto close;
350 bcopy((char *)rec.data, (char *)&nitem, sizeof(nitem));
351 if (kvm_read(kd, (u_long)nitem.n_value, kversion, dbversionlen) !=
352 dbversionlen)
353 goto close;
354 /*
355 * If they match, we win - otherwise clear out kd->db so
356 * we revert to slow nlist().
357 */
358 if (bcmp(dbversion, kversion, dbversionlen) == 0)
359 return (0);
360 close:
361 (void)(kd->db->close)(kd->db);
362 kd->db = 0;
363
364 return (-1);
365 }
366
367 int
kvm_nlist(kd,nl)368 kvm_nlist(kd, nl)
369 kvm_t *kd;
370 struct nlist *nl;
371 {
372 register struct nlist *p;
373 register int nvalid;
374
375 /*
376 * If we can't use the data base, revert to the
377 * slow library call.
378 */
379 if (kd->db == 0)
380 return (__fdnlist(kd->nlfd, nl));
381
382 /*
383 * We can use the kvm data base. Go through each nlist entry
384 * and look it up with a db query.
385 */
386 nvalid = 0;
387 for (p = nl; p->n_name && p->n_name[0]; ++p) {
388 register int len;
389 DBT rec;
390
391 if ((len = strlen(p->n_name)) > 4096) {
392 /* sanity */
393 _kvm_err(kd, kd->program, "symbol too large");
394 return (-1);
395 }
396 rec.data = p->n_name;
397 rec.size = len;
398 if ((kd->db->get)(kd->db, (DBT *)&rec, (DBT *)&rec, 0))
399 continue;
400 if (rec.data == 0 || rec.size != sizeof(struct nlist))
401 continue;
402 ++nvalid;
403 /*
404 * Avoid alignment issues.
405 */
406 bcopy((char *)&((struct nlist *)rec.data)->n_type,
407 (char *)&p->n_type,
408 sizeof(p->n_type));
409 bcopy((char *)&((struct nlist *)rec.data)->n_value,
410 (char *)&p->n_value,
411 sizeof(p->n_value));
412 }
413 /*
414 * Return the number of entries that weren't found.
415 */
416 return ((p - nl) - nvalid);
417 }
418
419 ssize_t
kvm_read(kd,kva,buf,len)420 kvm_read(kd, kva, buf, len)
421 kvm_t *kd;
422 register u_long kva;
423 register void *buf;
424 register size_t len;
425 {
426 register int cc;
427 register void *cp;
428
429 if (ISALIVE(kd)) {
430 /*
431 * We're using /dev/kmem. Just read straight from the
432 * device and let the active kernel do the address translation.
433 */
434 errno = 0;
435 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
436 _kvm_err(kd, 0, "invalid address (%x)", kva);
437 return (0);
438 }
439 cc = read(kd->vmfd, buf, len);
440 if (cc < 0) {
441 _kvm_syserr(kd, 0, "kvm_read");
442 return (0);
443 } else if (cc < len)
444 _kvm_err(kd, kd->program, "short read");
445 return (cc);
446 } else {
447 cp = buf;
448 while (len > 0) {
449 u_long pa;
450
451 cc = _kvm_kvatop(kd, kva, &pa);
452 if (cc == 0)
453 return (0);
454 if (cc > len)
455 cc = len;
456 errno = 0;
457 if (lseek(kd->pmfd, (off_t)pa, 0) == -1 && errno != 0) {
458 _kvm_syserr(kd, 0, _PATH_MEM);
459 break;
460 }
461 cc = read(kd->pmfd, cp, cc);
462 if (cc < 0) {
463 _kvm_syserr(kd, kd->program, "kvm_read");
464 break;
465 }
466 /*
467 * If kvm_kvatop returns a bogus value or our core
468 * file is truncated, we might wind up seeking beyond
469 * the end of the core file in which case the read will
470 * return 0 (EOF).
471 */
472 if (cc == 0)
473 break;
474 (char *)cp += cc;
475 kva += cc;
476 len -= cc;
477 }
478 return ((char *)cp - (char *)buf);
479 }
480 /* NOTREACHED */
481 }
482
483 ssize_t
kvm_write(kd,kva,buf,len)484 kvm_write(kd, kva, buf, len)
485 kvm_t *kd;
486 register u_long kva;
487 register const void *buf;
488 register size_t len;
489 {
490 register int cc;
491
492 if (ISALIVE(kd)) {
493 /*
494 * Just like kvm_read, only we write.
495 */
496 errno = 0;
497 if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) {
498 _kvm_err(kd, 0, "invalid address (%x)", kva);
499 return (0);
500 }
501 cc = write(kd->vmfd, buf, len);
502 if (cc < 0) {
503 _kvm_syserr(kd, 0, "kvm_write");
504 return (0);
505 } else if (cc < len)
506 _kvm_err(kd, kd->program, "short write");
507 return (cc);
508 } else {
509 _kvm_err(kd, kd->program,
510 "kvm_write not implemented for dead kernels");
511 return (0);
512 }
513 /* NOTREACHED */
514 }
515