main.c revision 1.27 1 /* $NetBSD: main.c,v 1.27 2019/09/13 13:55:24 christos 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 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: main.c,v 1.27 2019/09/13 13:55:24 christos Exp $");
35 #endif
36
37 #include <sys/param.h>
38
39 #ifndef __NetBSD_Version__
40 #error go away, you fool
41 #elif (__NetBSD_Version__ < 105000000)
42 #error only works with uvm
43 #endif
44
45 #include <fcntl.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <limits.h>
49 #include <string.h>
50 #include <signal.h>
51 #include <util.h>
52
53 #include "pmap.h"
54 #include "main.h"
55
56 struct cache_head lcache;
57 struct nchashhead *nchashtbl;
58 void *uvm_vnodeops, *uvm_deviceops, *aobj_pager, *ubc_pager;
59 struct vm_map *kmem_map, *mb_map, *phys_map, *exec_map, *pager_map;
60 struct vm_map *st_map, *pt_map, *lkm_map, *buf_map;
61 u_long nchash_addr, nchashtbl_addr, kernel_map_addr;
62 int debug, verbose, recurse, page_size;
63 int print_all, print_map, print_maps, print_solaris, print_ddb;
64 rlim_t maxssiz;
65
66 struct nlist ksyms[] = {
67 { "_maxsmap", 0, 0, 0, 0 },
68 #define NL_MAXSSIZ 0
69 { "_uvm_vnodeops", 0, 0, 0, 0 },
70 #define NL_UVM_VNODEOPS 1
71 { "_uvm_deviceops", 0, 0, 0, 0 },
72 #define NL_UVM_DEVICEOPS 2
73 { "_aobj_pager", 0, 0, 0, 0 },
74 #define NL_AOBJ_PAGER 3
75 { "_ubc_pager", 0, 0, 0, 0 },
76 #define NL_UBC_PAGER 4
77 { "_kernel_map", 0, 0, 0, 0 },
78 #define NL_KERNEL_MAP 5
79 { "_nchashtbl", 0, 0, 0, 0 },
80 #define NL_NCHASHTBL 6
81 { "_nchash", 0, 0, 0, 0 },
82 #define NL_NCHASH 7
83 { NULL, 0, 0, 0, 0 }
84 };
85
86 struct nlist kmaps[] = {
87 { "_kmem_map", 0, 0, 0, 0 },
88 #define NL_kmem_map 0
89 { "_mb_map", 0, 0, 0, 0 },
90 #define NL_mb_map 1
91 { "_phys_map", 0, 0, 0, 0 },
92 #define NL_phys_map 2
93 { "_exec_map", 0, 0, 0, 0 },
94 #define NL_exec_map 3
95 { "_pager_map", 0, 0, 0, 0 },
96 #define NL_pager_map 4
97 { "_st_map", 0, 0, 0, 0 },
98 #define NL_st_map 5
99 { "_pt_map", 0, 0, 0, 0 },
100 #define NL_pt_map 6
101 { "_lkm_map", 0, 0, 0, 0 },
102 #define NL_lkm_map 7
103 { "_buf_map", 0, 0, 0, 0 },
104 #define NL_buf_map 8
105 { NULL, 0, 0, 0, 0 },
106 };
107
108 #define VMSPACE_ADDRESS 1
109 #define VM_MAP_ADDRESS 2
110 #define VM_MAP_ENTRY_ADDRESS 3
111 #define AMAP_ADDRESS 4
112
113 void check_fd(int);
114 void load_symbols(kvm_t *);
115 void cache_enter(u_long, struct namecache *);
116
117 int
118 main(int argc, char *argv[])
119 {
120 kvm_t *kd;
121 pid_t pid;
122 uid_t uid;
123 int which, many, ch, rc;
124 char errbuf[_POSIX2_LINE_MAX + 1];
125 struct kinfo_proc2 *kproc;
126 char *kmem, *kernel, *t;
127 gid_t egid;
128 struct kbit kbit, *vmspace;
129 u_long address;
130
131 egid = getegid();
132 if (setegid(getgid()) == -1)
133 err(1, "failed to reset privileges");
134
135 check_fd(STDIN_FILENO);
136 check_fd(STDOUT_FILENO);
137 check_fd(STDERR_FILENO);
138
139 pid = -1;
140 which = verbose = debug = 0;
141 print_all = print_map = print_maps = print_solaris = print_ddb = 0;
142 recurse = 0;
143 kmem = kernel = NULL;
144 address = 0;
145 vmspace = &kbit;
146
147 while ((ch = getopt(argc, argv, "A:aD:dE:lM:mN:Pp:RrS:sV:vx")) != -1) {
148 switch (ch) {
149 case 'A':
150 case 'E':
151 case 'S':
152 case 'V':
153 if (which != 0)
154 errx(1, "use only one of -A, -E, -S, or -V");
155 errno = 0;
156 address = strtoul(optarg, &t, 0);
157 if (*t != '\0')
158 errx(1, "%s is not a valid address", optarg);
159 if (errno != 0)
160 err(1, "%s is not a valid address", optarg);
161 switch (ch) {
162 case 'A': which = AMAP_ADDRESS; break;
163 case 'E': which = VM_MAP_ENTRY_ADDRESS; break;
164 case 'S': which = VMSPACE_ADDRESS; break;
165 case 'V': which = VM_MAP_ADDRESS; break;
166 }
167 break;
168 case 'a':
169 print_all = 1;
170 break;
171 case 'd':
172 print_ddb = 1;
173 break;
174 case 'D':
175 errno = 0;
176 debug = strtoul(optarg, &t, 0);
177 if (*t != '\0')
178 errx(1, "%s is not a valid number", optarg);
179 if (errno != 0)
180 err(1, "%s is not a valid number", optarg);
181 break;
182 case 'l':
183 print_maps = 1;
184 break;
185 case 'm':
186 print_map = 1;
187 break;
188 case 'M':
189 kmem = optarg;
190 break;
191 case 'N':
192 kernel = optarg;
193 break;
194 case 'p':
195 errno = 0;
196 pid = strtol(optarg, &t, 0);
197 if (pid < 0)
198 errno = EINVAL;
199 if (*t != '\0')
200 errx(1, "%s is not a valid pid", optarg);
201 if (errno != 0)
202 err(1, "%s is not a valid pid", optarg);
203 break;
204 case 'P':
205 pid = getpid();
206 break;
207 case 'R':
208 recurse = 1;
209 break;
210 case 's':
211 print_solaris = 1;
212 break;
213 case 'v':
214 verbose++;
215 break;
216 case 'r':
217 case 'x':
218 errx(1, "-%c option not implemented, sorry", optopt);
219 /*NOTREACHED*/
220 case '?':
221 default:
222 fprintf(stderr, "usage: %s [-adlmPRsv] [-A address] "
223 "[-D number] [-E address] [-M core]\n"
224 "\t[-N system] [-p pid] [-S address] "
225 "[-V address] [pid ...]\n",
226 getprogname());
227 exit(1);
228 }
229 }
230 argc -= optind;
231 argv += optind;
232
233 /* more than one "process" to dump? */
234 many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0;
235
236 /* apply default */
237 if (print_all + print_map + print_maps + print_solaris +
238 print_ddb == 0)
239 print_solaris = 1;
240
241 /* get privs back if it appears to be safe, otherwise toss them */
242 if (kernel == NULL && kmem == NULL && address == 0)
243 rc = setegid(egid);
244 else
245 rc = setgid(getgid());
246 if (rc == -1)
247 err(1, "failed to reset privileges");
248
249 /* start by opening libkvm */
250 kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf);
251
252 /* we're completely done with privileges now */
253 rc = setgid(getgid());
254 if (rc == -1)
255 err(1, "failed to reset privileges");
256
257 /* print the kvm_open error, if any */
258 errbuf[_POSIX2_LINE_MAX] = '\0';
259 if (kd == NULL)
260 errx(1, "%s", errbuf);
261
262 /* get "bootstrap" addresses from kernel */
263 load_symbols(kd);
264
265 if (address) {
266 struct kbit kbit2, *at = &kbit2;
267
268 memset(vmspace, 0, sizeof(*vmspace));
269 A(at) = address;
270 S(at) = (size_t)-1;
271
272 switch (which) {
273 case VMSPACE_ADDRESS:
274 /* (kd, kproc, vmspace, thing) */
275 (*process_map)(kd, NULL, at, "vm_map");
276 break;
277 case VM_MAP_ADDRESS:
278 /* (kd, proc, vmspace, vm_map, thing) */
279 (*dump_vm_map)(kd, NULL, vmspace, at, "vm_map");
280 break;
281 case VM_MAP_ENTRY_ADDRESS:
282 /* (kd, proc, vmspace, vm_map_entry, 0) */
283 (*dump_vm_map_entry)(kd, NULL, vmspace, at, 0);
284 break;
285 case AMAP_ADDRESS:
286 /* (kd, amap) */
287 (*dump_amap)(kd, at);
288 break;
289 }
290 exit(0);
291 }
292
293 uid = getuid();
294
295 do {
296 if (pid == -1) {
297 if (argc == 0)
298 pid = getppid();
299 else {
300 errno = 0;
301 pid = strtol(argv[0], &t, 0);
302 if (pid < 0)
303 errno = EINVAL;
304 if (*t != '\0')
305 errx(1, "%s is not a valid pid",
306 argv[0]);
307 if (errno != 0)
308 err(1, "%s is not a valid pid",
309 argv[0]);
310 argv++;
311 argc--;
312 }
313 }
314
315 errno = 0;
316 /* find the process id */
317 if (pid == 0) {
318 kproc = NULL;
319 if (uid != 0) {
320 /* only root can print kernel mappings */
321 errno = EPERM;
322 }
323 } else {
324 kproc = kvm_getproc2(kd, KERN_PROC_PID, pid,
325 sizeof(struct kinfo_proc2), &rc);
326 if (kproc == NULL || rc == 0) {
327 errno = ESRCH;
328 } else if (uid != 0 && uid != kproc->p_uid) {
329 /*
330 * only the real owner of the process and
331 * root can print process mappings
332 */
333 errno = EPERM;
334 }
335 }
336
337 if (errno != 0) {
338 warn("%d", pid);
339 pid = -1;
340 continue;
341 }
342
343 /* dump it */
344 if (many) {
345 if (kproc != NULL)
346 printf("process %d:\n", kproc->p_pid);
347 else
348 printf("kernel:\n");
349 }
350
351 (*process_map)(kd, kproc, vmspace, NULL);
352 pid = -1;
353 } while (argc > 0);
354
355 /* done. go away. */
356 rc = kvm_close(kd);
357 if (rc == -1)
358 err(1, "kvm_close");
359
360 return (0);
361 }
362
363 void
364 check_fd(int fd)
365 {
366 struct stat st;
367 int n;
368
369 if (fstat(fd, &st) == -1) {
370 (void)close(fd);
371 n = open("/dev/null", O_RDWR);
372 if (n == fd || n == -1)
373 /* we're either done or we can do no more */
374 return;
375 /* if either of these fail, there's not much we can do */
376 (void)dup2(n, fd);
377 (void)close(n);
378 /* XXX should we exit if it fails? */
379 }
380 }
381
382 void
383 load_symbols(kvm_t *kd)
384 {
385 int rc, i, mib[2];
386 size_t sz;
387
388 rc = kvm_nlist(kd, &ksyms[0]);
389 if (rc != 0) {
390 for (i = 0; ksyms[i].n_name != NULL; i++)
391 if (ksyms[i].n_value == 0)
392 warnx("symbol %s: not found", ksyms[i].n_name);
393 exit(1);
394 }
395
396 uvm_vnodeops = (void*)ksyms[NL_UVM_VNODEOPS].n_value;
397 uvm_deviceops = (void*)ksyms[NL_UVM_DEVICEOPS].n_value;
398 aobj_pager = (void*)ksyms[NL_AOBJ_PAGER].n_value;
399 ubc_pager = (void*)ksyms[NL_UBC_PAGER].n_value;
400
401 nchash_addr = ksyms[NL_NCHASH].n_value;
402
403 _KDEREF(kd, ksyms[NL_MAXSSIZ].n_value, &maxssiz,
404 sizeof(maxssiz));
405 _KDEREF(kd, ksyms[NL_NCHASHTBL].n_value, &nchashtbl_addr,
406 sizeof(nchashtbl_addr));
407 _KDEREF(kd, ksyms[NL_KERNEL_MAP].n_value, &kernel_map_addr,
408 sizeof(kernel_map_addr));
409
410 /*
411 * Some of these may be missing from some platforms, for
412 * example sparc, sh3, and most powerpc platforms don't
413 * have a "phys_map", etc.
414 */
415 (void)kvm_nlist(kd, &kmaps[0]);
416
417 #define get_map_address(m) do {\
418 if (kmaps[__CONCAT(NL_,m)].n_value != 0) \
419 _KDEREF(kd, kmaps[__CONCAT(NL_,m)].n_value, &m, sizeof(m)); \
420 } while (0/*CONSTCOND*/)
421
422 get_map_address(kmem_map);
423 get_map_address(mb_map);
424 get_map_address(phys_map);
425 get_map_address(exec_map);
426 get_map_address(pager_map);
427 get_map_address(st_map);
428 get_map_address(pt_map);
429 get_map_address(lkm_map);
430 get_map_address(buf_map);
431
432 mib[0] = CTL_HW;
433 mib[1] = HW_PAGESIZE;
434 sz = sizeof(page_size);
435 if (sysctl(&mib[0], 2, &page_size, &sz, NULL, 0) == -1)
436 err(1, "sysctl: hw.pagesize");
437 }
438
439 const char *
440 mapname(void *addr)
441 {
442
443 if (addr == (void*)kernel_map_addr)
444 return ("kernel_map");
445 else if (addr == kmem_map)
446 return ("kmem_map");
447 else if (addr == mb_map)
448 return ("mb_map");
449 else if (addr == phys_map)
450 return ("phys_map");
451 else if (addr == exec_map)
452 return ("exec_map");
453 else if (addr == pager_map)
454 return ("pager_map");
455 else if (addr == st_map)
456 return ("st_map");
457 else if (addr == pt_map)
458 return ("pt_map");
459 else if (addr == lkm_map)
460 return ("lkm_map");
461 else if (addr == buf_map)
462 return ("buf_map");
463 else
464 return (NULL);
465 }
466
467 void
468 load_name_cache(kvm_t *kd)
469 {
470 struct namecache *ncp, *oncp;
471 union {
472 struct namecache ncp;
473 char buf[sizeof(*ncp) + USHRT_MAX];
474 } _n;
475 #define _ncp _n.ncp
476 struct nchashhead _ncpp, *ncpp;
477 u_long lnchash;
478 size_t nchash, i;
479
480 LIST_INIT(&lcache);
481
482 _KDEREF(kd, nchash_addr, &lnchash, sizeof(lnchash));
483 nchash = (size_t)lnchash + 1;
484 nchashtbl = ecalloc(nchash, sizeof(*nchashtbl));
485 _KDEREF(kd, nchashtbl_addr, nchashtbl, sizeof(*nchashtbl) * nchash);
486
487 ncpp = &_ncpp;
488
489 for (i = 0; i < nchash; i++) {
490 ncpp = &nchashtbl[i];
491 oncp = NULL;
492 LIST_FOREACH(ncp, ncpp, nc_hash) {
493 size_t len;
494
495 if (ncp == oncp ||
496 ncp == (void*)0xdeadbeef)
497 break;
498 oncp = ncp;
499 len = NCHNAMLEN;
500 again:
501 _KDEREF(kd, (u_long)ncp, &_ncp, (len + sizeof(*ncp)));
502 if (_ncp.nc_nlen > len && _ncp.nc_nlen < 1024) {
503 len = _ncp.nc_nlen;
504 goto again;
505 }
506 ncp = &_ncp;
507 if (ncp->nc_nlen > 0) {
508 if (ncp->nc_nlen > 2 ||
509 ncp->nc_name[0] != '.' ||
510 (ncp->nc_name[1] != '.' &&
511 ncp->nc_nlen != 1))
512 cache_enter(i, ncp);
513 }
514 }
515 }
516 }
517
518 void
519 cache_enter(u_long i, struct namecache *ncp)
520 {
521 struct cache_entry *ce;
522
523 if (debug & DUMP_NAMEI_CACHE)
524 printf("[%lu] ncp->nc_vp %10p, ncp->nc_dvp %10p, "
525 "ncp->nc_nlen %3d [%.*s]\n",
526 i, ncp->nc_vp, ncp->nc_dvp,
527 ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name);
528
529 ce = emalloc(sizeof(struct cache_entry));
530
531 ce->ce_vp = ncp->nc_vp;
532 ce->ce_pvp = ncp->nc_dvp;
533 ce->ce_nlen = ncp->nc_nlen;
534 strncpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name));
535 ce->ce_name[MIN(ce->ce_nlen, (int)(sizeof(ce->ce_name) - 1))] = '\0';
536
537 LIST_INSERT_HEAD(&lcache, ce, ce_next);
538 }
539