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