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