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