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