1 /* $NetBSD: main.c,v 1.26 2015/12/14 03:15:10 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.26 2015/12/14 03:15:10 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, *ncp, *oncp; 471 struct nchashhead _ncpp, *ncpp; 472 u_long lnchash; 473 size_t nchash, i; 474 475 LIST_INIT(&lcache); 476 477 _KDEREF(kd, nchash_addr, &lnchash, sizeof(lnchash)); 478 nchash = (size_t)lnchash + 1; 479 nchashtbl = ecalloc(nchash, sizeof(*nchashtbl)); 480 _KDEREF(kd, nchashtbl_addr, nchashtbl, sizeof(*nchashtbl) * nchash); 481 482 ncpp = &_ncpp; 483 484 for (i = 0; i < nchash; i++) { 485 ncpp = &nchashtbl[i]; 486 oncp = NULL; 487 LIST_FOREACH(ncp, ncpp, nc_hash) { 488 if (ncp == oncp || 489 ncp == (void*)0xdeadbeef) 490 break; 491 oncp = ncp; 492 _KDEREF(kd, (u_long)ncp, &_ncp, sizeof(*ncp)); 493 ncp = &_ncp; 494 if (ncp->nc_nlen > 0) { 495 if (ncp->nc_nlen > 2 || 496 ncp->nc_name[0] != '.' || 497 (ncp->nc_name[1] != '.' && 498 ncp->nc_nlen != 1)) 499 cache_enter(i, ncp); 500 } 501 } 502 } 503 } 504 505 void 506 cache_enter(u_long i, struct namecache *ncp) 507 { 508 struct cache_entry *ce; 509 510 if (debug & DUMP_NAMEI_CACHE) 511 printf("[%lu] ncp->nc_vp %10p, ncp->nc_dvp %10p, " 512 "ncp->nc_nlen %3d [%.*s]\n", 513 i, ncp->nc_vp, ncp->nc_dvp, 514 ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); 515 516 ce = emalloc(sizeof(struct cache_entry)); 517 518 ce->ce_vp = ncp->nc_vp; 519 ce->ce_pvp = ncp->nc_dvp; 520 ce->ce_nlen = ncp->nc_nlen; 521 strncpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name)); 522 ce->ce_name[MIN(ce->ce_nlen, (int)(sizeof(ce->ce_name) - 1))] = '\0'; 523 524 LIST_INSERT_HEAD(&lcache, ce, ce_next); 525 } 526