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