main.c revision 1.6 1 /* $NetBSD: main.c,v 1.6 2003/03/29 18:01:21 he Exp $ */
2
3 /*
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Brown.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: main.c,v 1.6 2003/03/29 18:01:21 he Exp $");
42 #endif
43
44 #include <sys/param.h>
45
46 #ifndef __NetBSD_Version__
47 #error go away, you fool
48 #elif (__NetBSD_Version__ < 105000000)
49 #error only works with uvm
50 #endif
51
52 #include <fcntl.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <limits.h>
56 #include <string.h>
57
58 #include "pmap.h"
59 #include "main.h"
60
61 /*
62 * strange gyrations to get the prototype for the lockdebug version of
63 * the process_map function
64 */
65 #undef VERSION
66 #define VERSION lockdebug
67 #include "pmap.h"
68 #undef VERSION
69 #define VERSION regular
70
71 struct cache_head lcache;
72 struct nchashhead *nchashtbl;
73 void *uvm_vnodeops, *uvm_deviceops, *aobj_pager, *ubc_pager;
74 void *kernel_floor;
75 struct vm_map *kmem_map, *mb_map, *phys_map, *exec_map, *pager_map;
76 struct vm_map *st_map, *pt_map, *lkm_map;
77 u_long nchash_addr, nchashtbl_addr, kernel_map_addr;
78 int debug, verbose, recurse, page_size;
79 int print_all, print_map, print_maps, print_solaris, print_ddb;
80 rlim_t maxssiz;
81
82 struct nlist ksyms[] = {
83 { "_maxsmap" },
84 #define NL_MAXSSIZ 0
85 { "_uvm_vnodeops" },
86 #define NL_UVM_VNODEOPS 1
87 { "_uvm_deviceops" },
88 #define NL_UVM_DEVICEOPS 2
89 { "_aobj_pager" },
90 #define NL_AOBJ_PAGER 3
91 { "_ubc_pager" },
92 #define NL_UBC_PAGER 4
93 { "_kernel_map" },
94 #define NL_KERNEL_MAP 5
95 { "_nchashtbl" },
96 #define NL_NCHASHTBL 6
97 { "_nchash" },
98 #define NL_NCHASH 7
99 { "_kernel_text" },
100 #define NL_KENTER 8
101 { NULL }
102 };
103
104 struct nlist kmaps[] = {
105 { "_kmem_map" },
106 #define NL_kmem_map 0
107 { "_mb_map" },
108 #define NL_mb_map 1
109 { "_phys_map" },
110 #define NL_phys_map 2
111 { "_exec_map" },
112 #define NL_exec_map 3
113 { "_pager_map" },
114 #define NL_pager_map 4
115 { "_st_map" },
116 #define NL_st_map 5
117 { "_pt_map" },
118 #define NL_pt_map 6
119 { "_lkm_map" },
120 #define NL_lkm_map 7
121 { NULL }
122 };
123
124 void check_fd(int);
125 int using_lockdebug(kvm_t *);
126 void load_symbols(kvm_t *);
127 void cache_enter(int, struct namecache *);
128
129 int
130 main(int argc, char *argv[])
131 {
132 kvm_t *kd;
133 pid_t pid;
134 int many, ch, rc;
135 char errbuf[_POSIX2_LINE_MAX + 1];
136 struct kinfo_proc2 *kproc;
137 char *kmem, *kernel;
138 gid_t egid;
139
140 egid = getegid();
141 if (setegid(getgid()) == -1)
142 err(1, "failed to reset privileges");
143
144 check_fd(STDIN_FILENO);
145 check_fd(STDOUT_FILENO);
146 check_fd(STDERR_FILENO);
147
148 pid = -1;
149 verbose = debug = 0;
150 print_all = print_map = print_maps = print_solaris = print_ddb = 0;
151 recurse = 0;
152 kmem = kernel = NULL;
153
154 while ((ch = getopt(argc, argv, "aD:dlmM:N:p:PRrsvx")) != -1) {
155 switch (ch) {
156 case 'a':
157 print_all = 1;
158 break;
159 case 'd':
160 print_ddb = 1;
161 break;
162 case 'D':
163 debug = strtol(optarg, NULL, 0);
164 break;
165 case 'l':
166 print_maps = 1;
167 break;
168 case 'm':
169 print_map = 1;
170 break;
171 case 'M':
172 kmem = optarg;
173 break;
174 case 'N':
175 kernel = optarg;
176 break;
177 case 'p':
178 pid = strtol(optarg, NULL, 0);
179 break;
180 case 'P':
181 pid = getpid();
182 break;
183 case 'R':
184 recurse = 1;
185 break;
186 case 's':
187 print_solaris = 1;
188 break;
189 case 'v':
190 verbose++;
191 break;
192 case 'r':
193 case 'x':
194 errx(1, "-%c option not implemented, sorry", optopt);
195 /*NOTREACHED*/
196 case '?':
197 default:
198 fprintf(stderr, "usage: %s [-adlmPsv] [-D number] "
199 "[-M core] [-N system] [-p pid] [pid ...]\n",
200 getprogname());
201 exit(1);
202 }
203 }
204 argc -= optind;
205 argv += optind;
206
207 /* more than one "process" to dump? */
208 many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0;
209
210 /* apply default */
211 if (print_all + print_map + print_maps + print_solaris +
212 print_ddb == 0)
213 print_solaris = 1;
214
215 /* get privs back if it appears to be safe, otherwise toss them */
216 if (kernel == NULL && kmem == NULL)
217 rc = setegid(egid);
218 else
219 rc = setgid(getgid());
220 if (rc == -1)
221 err(1, "failed to reset privileges");
222
223 /* start by opening libkvm */
224 kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf);
225 errbuf[_POSIX2_LINE_MAX] = '\0';
226 if (kd == NULL)
227 errx(1, "%s", errbuf);
228
229 /* get "bootstrap" addresses from kernel */
230 load_symbols(kd);
231
232 if (! using_lockdebug(kd))
233 process_map = PMAPFUNC(process_map,regular);
234 else
235 process_map = PMAPFUNC(process_map,lockdebug);
236
237 do {
238 if (pid == -1) {
239 if (argc == 0)
240 pid = getppid();
241 else {
242 pid = strtol(argv[0], NULL, 0);
243 argv++;
244 argc--;
245 }
246 }
247
248 /* find the process id */
249 if (pid == 0)
250 kproc = NULL;
251 else {
252 kproc = kvm_getproc2(kd, KERN_PROC_PID, pid,
253 sizeof(struct kinfo_proc2), &rc);
254 if (kproc == NULL || rc == 0) {
255 errno = ESRCH;
256 warn("%d", pid);
257 pid = -1;
258 continue;
259 }
260 }
261
262 /* dump it */
263 if (many) {
264 if (kproc)
265 printf("process %d:\n", kproc->p_pid);
266 else
267 printf("kernel:\n");
268 }
269
270 (*process_map)(kd, pid, kproc);
271 pid = -1;
272 } while (argc > 0);
273
274 /* done. go away. */
275 rc = kvm_close(kd);
276 if (rc == -1)
277 err(1, "kvm_close");
278
279 return (0);
280 }
281
282 void
283 check_fd(int fd)
284 {
285 struct stat st;
286 int n;
287
288 if (fstat(fd, &st) == -1) {
289 (void)close(fd);
290 n = open("/dev/null", O_RDWR);
291 if (n == fd || n == -1)
292 /* we're either done or we can do no more */
293 return;
294 /* if either of these fail, there's not much we can do */
295 (void)dup2(n, fd);
296 (void)close(n);
297 /* XXX should we exit if it fails? */
298 }
299 }
300
301 int
302 using_lockdebug(kvm_t *kd)
303 {
304 struct kbit kbit[3];
305 struct kbit *vm_map, *header, *vm_map_entry;
306
307 vm_map = &kbit[0];
308 header = &kbit[1];
309 vm_map_entry = &kbit[2];
310
311 A(vm_map) = kernel_map_addr;
312 S(vm_map) = sizeof(struct vm_map);
313 KDEREF(kd, vm_map);
314
315 A(header) = A(vm_map) + offsetof(struct vm_map, header);
316 S(header) = sizeof(struct vm_map_entry);
317 memcpy(D(header, vm_map_entry), &D(vm_map, vm_map)->header, S(header));
318
319 /*
320 * the kernel *always* has map entries, but we might see a
321 * zero if we're using a lockdebug kernel and haven't noticed
322 * yet.
323 */
324 if (D(vm_map, vm_map)->nentries == 0) {
325
326 /* no entries -> all pointers must point to the header */
327 if (P(header) == D(header, vm_map_entry)->next &&
328 P(header) == D(header, vm_map_entry)->prev &&
329 P(header) == D(vm_map, vm_map)->hint &&
330 P(header) == D(vm_map, vm_map)->first_free)
331 return (0);
332 }
333 else {
334
335 P(vm_map_entry) = D(header, vm_map_entry)->next;
336 S(vm_map_entry) = sizeof(struct vm_map_entry);
337 KDEREF(kd, vm_map_entry);
338
339 /* we have entries, so there must be referential integrity */
340 if (D(vm_map_entry, vm_map_entry)->prev == P(header) &&
341 D(header, vm_map_entry)->start <=
342 D(vm_map_entry, vm_map_entry)->start &&
343 D(vm_map_entry, vm_map_entry)->end <=
344 D(header, vm_map_entry)->end)
345 return (0);
346 }
347
348 return (1);
349 }
350
351 void
352 load_symbols(kvm_t *kd)
353 {
354 int rc, i, mib[2];
355 size_t sz;
356
357 rc = kvm_nlist(kd, &ksyms[0]);
358 if (rc != 0) {
359 for (i = 0; ksyms[i].n_name != NULL; i++)
360 if (ksyms[i].n_value == 0)
361 warnx("symbol %s: not found", ksyms[i].n_name);
362 exit(1);
363 }
364
365 uvm_vnodeops = (void*)ksyms[NL_UVM_VNODEOPS].n_value;
366 uvm_deviceops = (void*)ksyms[NL_UVM_DEVICEOPS].n_value;
367 aobj_pager = (void*)ksyms[NL_AOBJ_PAGER].n_value;
368 ubc_pager = (void*)ksyms[NL_UBC_PAGER].n_value;
369
370 kernel_floor = (void*)ksyms[NL_KENTER].n_value;
371 nchash_addr = ksyms[NL_NCHASH].n_value;
372
373 _KDEREF(kd, ksyms[NL_MAXSSIZ].n_value, &maxssiz,
374 sizeof(maxssiz));
375 _KDEREF(kd, ksyms[NL_NCHASHTBL].n_value, &nchashtbl_addr,
376 sizeof(nchashtbl_addr));
377 _KDEREF(kd, ksyms[NL_KERNEL_MAP].n_value, &kernel_map_addr,
378 sizeof(kernel_map_addr));
379
380 /*
381 * Some of these may be missing from some platforms, for
382 * example sparc, sh3, and most powerpc platforms don't
383 * have a "phys_map", etc.
384 */
385 (void)kvm_nlist(kd, &kmaps[0]);
386
387 #define get_map_address(m) \
388 if (kmaps[CONCAT(NL_,m)].n_value != 0) \
389 _KDEREF(kd, kmaps[CONCAT(NL_,m)].n_value, &m, sizeof(m))
390
391 get_map_address(kmem_map);
392 get_map_address(mb_map);
393 get_map_address(phys_map);
394 get_map_address(exec_map);
395 get_map_address(pager_map);
396 get_map_address(st_map);
397 get_map_address(pt_map);
398 get_map_address(lkm_map);
399
400 mib[0] = CTL_HW;
401 mib[1] = HW_PAGESIZE;
402 sz = sizeof(page_size);
403 if (sysctl(&mib[0], 2, &page_size, &sz, NULL, 0) == -1)
404 err(1, "sysctl: hw.pagesize");
405 }
406
407 const char *
408 mapname(void *addr)
409 {
410
411 if (addr == (void*)kernel_map_addr)
412 return ("kernel_map");
413 else if (addr == kmem_map)
414 return ("kmem_map");
415 else if (addr == mb_map)
416 return ("mb_map");
417 else if (addr == phys_map)
418 return ("phys_map");
419 else if (addr == exec_map)
420 return ("exec_map");
421 else if (addr == pager_map)
422 return ("pager_map");
423 else if (addr == st_map)
424 return ("st_map");
425 else if (addr == pt_map)
426 return ("pt_map");
427 else if (addr == lkm_map)
428 return ("lkm_map");
429 else
430 return (NULL);
431 }
432
433 void
434 load_name_cache(kvm_t *kd)
435 {
436 struct namecache _ncp, *ncp, *oncp;
437 struct nchashhead _ncpp, *ncpp;
438 u_long nchash;
439 int i;
440
441 LIST_INIT(&lcache);
442
443 _KDEREF(kd, nchash_addr, &nchash, sizeof(nchash));
444 nchashtbl = malloc(sizeof(nchashtbl) * (int)nchash);
445 _KDEREF(kd, nchashtbl_addr, nchashtbl,
446 sizeof(nchashtbl) * (int)nchash);
447
448 ncpp = &_ncpp;
449
450 for (i = 0; i <= nchash; i++) {
451 ncpp = &nchashtbl[i];
452 oncp = NULL;
453 LIST_FOREACH(ncp, ncpp, nc_hash) {
454 if (ncp == oncp ||
455 (void*)ncp < kernel_floor ||
456 ncp == (void*)0xdeadbeef)
457 break;
458 oncp = ncp;
459 _KDEREF(kd, (u_long)ncp, &_ncp, sizeof(*ncp));
460 ncp = &_ncp;
461 if ((void*)ncp->nc_vp > kernel_floor &&
462 ncp->nc_nlen > 0) {
463 if (ncp->nc_nlen > 2 ||
464 ncp->nc_name[0] != '.' ||
465 (ncp->nc_name[1] != '.' &&
466 ncp->nc_nlen != 1))
467 cache_enter(i, ncp);
468 }
469 }
470 }
471 }
472
473 void
474 cache_enter(int i, struct namecache *ncp)
475 {
476 struct cache_entry *ce;
477
478 if (debug & DUMP_NAMEI_CACHE)
479 printf("[%d] ncp->nc_vp %10p, ncp->nc_dvp %10p, "
480 "ncp->nc_nlen %3d [%.*s] (nc_dvpid=%lu, nc_vpid=%lu)\n",
481 i, ncp->nc_vp, ncp->nc_dvp,
482 ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name,
483 ncp->nc_dvpid, ncp->nc_vpid);
484
485 ce = malloc(sizeof(struct cache_entry));
486
487 ce->ce_vp = ncp->nc_vp;
488 ce->ce_pvp = ncp->nc_dvp;
489 ce->ce_cid = ncp->nc_vpid;
490 ce->ce_pcid = ncp->nc_dvpid;
491 ce->ce_nlen = ncp->nc_nlen;
492 strncpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name));
493 ce->ce_name[MIN(ce->ce_nlen, sizeof(ce->ce_name) - 1)] = '\0';
494
495 LIST_INSERT_HEAD(&lcache, ce, ce_next);
496 }
497