1 /* $NetBSD: main.c,v 1.19 2008/06/17 15:54:45 christos Exp $ */
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: main.c,v 1.19 2008/06/17 15:54:45 christos Exp $");
37 #include <sys/param.h>
39 #ifndef __NetBSD_Version__
40 #error go away, you fool
41 #elif (__NetBSD_Version__ < 105000000)
42 #error only works with uvm
54 struct cache_head lcache
;
55 struct nchashhead
*nchashtbl
;
56 void *uvm_vnodeops
, *uvm_deviceops
, *aobj_pager
, *ubc_pager
;
57 struct vm_map
*kmem_map
, *mb_map
, *phys_map
, *exec_map
, *pager_map
;
58 struct vm_map
*st_map
, *pt_map
, *lkm_map
, *buf_map
;
59 u_long nchash_addr
, nchashtbl_addr
, kernel_map_addr
;
60 int debug
, verbose
, recurse
, page_size
;
61 int print_all
, print_map
, print_maps
, print_solaris
, print_ddb
;
64 struct nlist ksyms
[] = {
65 { "_maxsmap", 0, 0, 0, 0 },
67 { "_uvm_vnodeops", 0, 0, 0, 0 },
68 #define NL_UVM_VNODEOPS 1
69 { "_uvm_deviceops", 0, 0, 0, 0 },
70 #define NL_UVM_DEVICEOPS 2
71 { "_aobj_pager", 0, 0, 0, 0 },
72 #define NL_AOBJ_PAGER 3
73 { "_ubc_pager", 0, 0, 0, 0 },
74 #define NL_UBC_PAGER 4
75 { "_kernel_map", 0, 0, 0, 0 },
76 #define NL_KERNEL_MAP 5
77 { "_nchashtbl", 0, 0, 0, 0 },
78 #define NL_NCHASHTBL 6
79 { "_nchash", 0, 0, 0, 0 },
84 struct nlist kmaps
[] = {
85 { "_kmem_map", 0, 0, 0, 0 },
87 { "_mb_map", 0, 0, 0, 0 },
89 { "_phys_map", 0, 0, 0, 0 },
91 { "_exec_map", 0, 0, 0, 0 },
93 { "_pager_map", 0, 0, 0, 0 },
94 #define NL_pager_map 4
95 { "_st_map", 0, 0, 0, 0 },
97 { "_pt_map", 0, 0, 0, 0 },
99 { "_lkm_map", 0, 0, 0, 0 },
101 { "_buf_map", 0, 0, 0, 0 },
103 { NULL
, 0, 0, 0, 0 },
106 #define VMSPACE_ADDRESS 1
107 #define VM_MAP_ADDRESS 2
108 #define VM_MAP_ENTRY_ADDRESS 3
109 #define AMAP_ADDRESS 4
112 void load_symbols(kvm_t
*);
113 void cache_enter(u_long
, struct namecache
*);
116 main(int argc
, char *argv
[])
120 int which
, many
, ch
, rc
;
121 char errbuf
[_POSIX2_LINE_MAX
+ 1];
122 struct kinfo_proc2
*kproc
;
123 char *kmem
, *kernel
, *t
;
125 struct kbit kbit
, *vmspace
;
129 if (setegid(getgid()) == -1)
130 err(1, "failed to reset privileges");
132 check_fd(STDIN_FILENO
);
133 check_fd(STDOUT_FILENO
);
134 check_fd(STDERR_FILENO
);
137 which
= verbose
= debug
= 0;
138 print_all
= print_map
= print_maps
= print_solaris
= print_ddb
= 0;
140 kmem
= kernel
= NULL
;
144 while ((ch
= getopt(argc
, argv
, "A:aD:dE:lM:mN:Pp:RrS:sV:vx")) != -1) {
151 errx(1, "use only one of -A, -E, -S, or -V");
153 address
= strtoul(optarg
, &t
, 0);
155 errx(1, "%s is not a valid address", optarg
);
157 err(1, "%s is not a valid address", optarg
);
159 case 'A': which
= AMAP_ADDRESS
; break;
160 case 'E': which
= VM_MAP_ENTRY_ADDRESS
; break;
161 case 'S': which
= VMSPACE_ADDRESS
; break;
162 case 'V': which
= VM_MAP_ADDRESS
; break;
173 debug
= strtoul(optarg
, &t
, 0);
175 errx(1, "%s is not a valid number", optarg
);
177 err(1, "%s is not a valid number", optarg
);
193 pid
= strtol(optarg
, &t
, 0);
197 errx(1, "%s is not a valid pid", optarg
);
199 err(1, "%s is not a valid pid", optarg
);
215 errx(1, "-%c option not implemented, sorry", optopt
);
219 fprintf(stderr
, "usage: %s [-adlmPRsv] [-A address] "
220 "[-D number] [-E address] [-M core]\n"
221 "\t[-N system] [-p pid] [-S address] "
222 "[-V address] [pid ...]\n",
230 /* more than one "process" to dump? */
231 many
= (argc
> 1 - (pid
== -1 ? 0 : 1)) ? 1 : 0;
234 if (print_all
+ print_map
+ print_maps
+ print_solaris
+
238 /* get privs back if it appears to be safe, otherwise toss them */
239 if (kernel
== NULL
&& kmem
== NULL
&& address
== 0)
242 rc
= setgid(getgid());
244 err(1, "failed to reset privileges");
246 /* start by opening libkvm */
247 kd
= kvm_openfiles(kernel
, kmem
, NULL
, O_RDONLY
, errbuf
);
249 /* we're completely done with privileges now */
250 rc
= setgid(getgid());
252 err(1, "failed to reset privileges");
254 /* print the kvm_open error, if any */
255 errbuf
[_POSIX2_LINE_MAX
] = '\0';
257 errx(1, "%s", errbuf
);
259 /* get "bootstrap" addresses from kernel */
263 struct kbit kbit2
, *at
= &kbit2
;
265 memset(vmspace
, 0, sizeof(*vmspace
));
270 case VMSPACE_ADDRESS
:
271 /* (kd, kproc, vmspace, thing) */
272 (*process_map
)(kd
, NULL
, at
, "vm_map");
275 /* (kd, proc, vmspace, vm_map, thing) */
276 (*dump_vm_map
)(kd
, NULL
, vmspace
, at
, "vm_map");
278 case VM_MAP_ENTRY_ADDRESS
:
279 /* (kd, proc, vmspace, vm_map_entry, 0) */
280 (*dump_vm_map_entry
)(kd
, NULL
, vmspace
, at
, 0);
284 (*dump_amap
)(kd
, at
);
296 pid
= strtol(argv
[0], &t
, 0);
300 errx(1, "%s is not a valid pid",
303 err(1, "%s is not a valid pid",
310 /* find the process id */
314 kproc
= kvm_getproc2(kd
, KERN_PROC_PID
, pid
,
315 sizeof(struct kinfo_proc2
), &rc
);
316 if (kproc
== NULL
|| rc
== 0) {
327 printf("process %d:\n", kproc
->p_pid
);
332 (*process_map
)(kd
, kproc
, vmspace
, NULL
);
350 if (fstat(fd
, &st
) == -1) {
352 n
= open("/dev/null", O_RDWR
);
353 if (n
== fd
|| n
== -1)
354 /* we're either done or we can do no more */
356 /* if either of these fail, there's not much we can do */
359 /* XXX should we exit if it fails? */
364 load_symbols(kvm_t
*kd
)
369 rc
= kvm_nlist(kd
, &ksyms
[0]);
371 for (i
= 0; ksyms
[i
].n_name
!= NULL
; i
++)
372 if (ksyms
[i
].n_value
== 0)
373 warnx("symbol %s: not found", ksyms
[i
].n_name
);
377 uvm_vnodeops
= (void*)ksyms
[NL_UVM_VNODEOPS
].n_value
;
378 uvm_deviceops
= (void*)ksyms
[NL_UVM_DEVICEOPS
].n_value
;
379 aobj_pager
= (void*)ksyms
[NL_AOBJ_PAGER
].n_value
;
380 ubc_pager
= (void*)ksyms
[NL_UBC_PAGER
].n_value
;
382 nchash_addr
= ksyms
[NL_NCHASH
].n_value
;
384 _KDEREF(kd
, ksyms
[NL_MAXSSIZ
].n_value
, &maxssiz
,
386 _KDEREF(kd
, ksyms
[NL_NCHASHTBL
].n_value
, &nchashtbl_addr
,
387 sizeof(nchashtbl_addr
));
388 _KDEREF(kd
, ksyms
[NL_KERNEL_MAP
].n_value
, &kernel_map_addr
,
389 sizeof(kernel_map_addr
));
392 * Some of these may be missing from some platforms, for
393 * example sparc, sh3, and most powerpc platforms don't
394 * have a "phys_map", etc.
396 (void)kvm_nlist(kd
, &kmaps
[0]);
398 #define get_map_address(m) do {\
399 if (kmaps[__CONCAT(NL_,m)].n_value != 0) \
400 _KDEREF(kd, kmaps[__CONCAT(NL_,m)].n_value, &m, sizeof(m)); \
401 } while (0/*CONSTCOND*/)
403 get_map_address(kmem_map
);
404 get_map_address(mb_map
);
405 get_map_address(phys_map
);
406 get_map_address(exec_map
);
407 get_map_address(pager_map
);
408 get_map_address(st_map
);
409 get_map_address(pt_map
);
410 get_map_address(lkm_map
);
411 get_map_address(buf_map
);
414 mib
[1] = HW_PAGESIZE
;
415 sz
= sizeof(page_size
);
416 if (sysctl(&mib
[0], 2, &page_size
, &sz
, NULL
, 0) == -1)
417 err(1, "sysctl: hw.pagesize");
424 if (addr
== (void*)kernel_map_addr
)
425 return ("kernel_map");
426 else if (addr
== kmem_map
)
428 else if (addr
== mb_map
)
430 else if (addr
== phys_map
)
432 else if (addr
== exec_map
)
434 else if (addr
== pager_map
)
435 return ("pager_map");
436 else if (addr
== st_map
)
438 else if (addr
== pt_map
)
440 else if (addr
== lkm_map
)
442 else if (addr
== buf_map
)
449 load_name_cache(kvm_t
*kd
)
451 struct namecache _ncp
, *ncp
, *oncp
;
452 struct nchashhead _ncpp
, *ncpp
;
457 _KDEREF(kd
, nchash_addr
, &nchash
, sizeof(nchash
));
458 nchashtbl
= malloc(sizeof(nchashtbl
) * (int)(nchash
+ 1));
459 _KDEREF(kd
, nchashtbl_addr
, nchashtbl
,
460 sizeof(nchashtbl
) * (int)(nchash
+ 1));
464 for (i
= 0; i
<= nchash
; i
++) {
465 ncpp
= &nchashtbl
[i
];
467 LIST_FOREACH(ncp
, ncpp
, nc_hash
) {
469 ncp
== (void*)0xdeadbeef)
472 _KDEREF(kd
, (u_long
)ncp
, &_ncp
, sizeof(*ncp
));
474 if (ncp
->nc_nlen
> 0) {
475 if (ncp
->nc_nlen
> 2 ||
476 ncp
->nc_name
[0] != '.' ||
477 (ncp
->nc_name
[1] != '.' &&
486 cache_enter(u_long i
, struct namecache
*ncp
)
488 struct cache_entry
*ce
;
490 if (debug
& DUMP_NAMEI_CACHE
)
491 printf("[%lu] ncp->nc_vp %10p, ncp->nc_dvp %10p, "
492 "ncp->nc_nlen %3d [%.*s]\n",
493 i
, ncp
->nc_vp
, ncp
->nc_dvp
,
494 ncp
->nc_nlen
, ncp
->nc_nlen
, ncp
->nc_name
);
496 ce
= malloc(sizeof(struct cache_entry
));
498 ce
->ce_vp
= ncp
->nc_vp
;
499 ce
->ce_pvp
= ncp
->nc_dvp
;
500 ce
->ce_nlen
= ncp
->nc_nlen
;
501 strncpy(ce
->ce_name
, ncp
->nc_name
, sizeof(ce
->ce_name
));
502 ce
->ce_name
[MIN(ce
->ce_nlen
, (int)(sizeof(ce
->ce_name
) - 1))] = '\0';
504 LIST_INSERT_HEAD(&lcache
, ce
, ce_next
);