xref: /original-bsd/lib/libkvm/kvm.c (revision f737e041)
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 *
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__
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__
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 *
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 *
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 *
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 *
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
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
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
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
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
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