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