procmap.c revision 1.62
1/* $OpenBSD: procmap.c,v 1.62 2016/05/26 17:23:50 stefan Exp $ */ 2/* $NetBSD: pmap.c,v 1.1 2002/09/01 20:32:44 atatat Exp $ */ 3 4/* 5 * Copyright (c) 2002 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Andrew Brown. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> /* MAXCOMLEN */ 34#include <sys/types.h> 35#include <sys/time.h> 36#include <sys/exec.h> 37#include <sys/proc.h> 38#include <sys/vnode.h> 39#include <sys/mount.h> 40#include <sys/uio.h> 41#include <sys/namei.h> 42#include <sys/sysctl.h> 43 44/* XXX until uvm gets cleaned up */ 45typedef int boolean_t; 46 47#include <uvm/uvm.h> 48#include <uvm/uvm_device.h> 49#include <uvm/uvm_amap.h> 50#include <uvm/uvm_vnode.h> 51 52#include <ufs/ufs/quota.h> 53#include <ufs/ufs/inode.h> 54#undef doff_t 55#undef IN_ACCESS 56#undef i_size 57#undef i_devvp 58#include <isofs/cd9660/iso.h> 59#include <isofs/cd9660/cd9660_node.h> 60 61#include <kvm.h> 62#include <fcntl.h> 63#include <errno.h> 64#include <err.h> 65#include <stdlib.h> 66#include <stddef.h> 67#include <unistd.h> 68#include <stdio.h> 69#include <limits.h> 70#include <string.h> 71 72/* 73 * stolen (and munged) from #include <uvm/uvm_object.h> 74 */ 75#define UVM_OBJ_IS_VNODE(uobj) ((uobj)->pgops == uvm_vnodeops) 76#define UVM_OBJ_IS_AOBJ(uobj) ((uobj)->pgops == aobj_pager) 77#define UVM_OBJ_IS_DEVICE(uobj) ((uobj)->pgops == uvm_deviceops) 78 79#define PRINT_VMSPACE 0x00000001 80#define PRINT_VM_MAP 0x00000002 81#define PRINT_VM_MAP_HEADER 0x00000004 82#define PRINT_VM_MAP_ENTRY 0x00000008 83#define DUMP_NAMEI_CACHE 0x00000010 84 85struct cache_entry { 86 LIST_ENTRY(cache_entry) ce_next; 87 struct vnode *ce_vp, *ce_pvp; 88 u_long ce_cid, ce_pcid; 89 unsigned int ce_nlen; 90 char ce_name[256]; 91}; 92 93LIST_HEAD(cache_head, cache_entry) lcache; 94TAILQ_HEAD(namecache_head, namecache) nclruhead; 95int namecache_loaded; 96void *uvm_vnodeops, *uvm_deviceops, *aobj_pager; 97u_long kernel_map_addr, nclruhead_addr; 98int debug, verbose; 99int print_all, print_map, print_maps, print_solaris, print_ddb, print_amap; 100int rwx = PROT_READ | PROT_WRITE | PROT_EXEC; 101rlim_t maxssiz; 102 103struct sum { 104 unsigned long s_am_nslots; 105 unsigned long s_am_nusedslots; 106}; 107 108struct kbit { 109 /* 110 * size of data chunk 111 */ 112 size_t k_size; 113 114 /* 115 * something for printf() and something for kvm_read() 116 */ 117 union { 118 void *k_addr_p; 119 u_long k_addr_ul; 120 } k_addr; 121 122 /* 123 * where we actually put the "stuff" 124 */ 125 union { 126 char data[1]; 127 struct vmspace vmspace; 128 struct vm_map vm_map; 129 struct vm_map_entry vm_map_entry; 130 struct uvm_vnode uvm_vnode; 131 struct vnode vnode; 132 struct uvm_object uvm_object; 133 struct mount mount; 134 struct inode inode; 135 struct iso_node iso_node; 136 struct uvm_device uvm_device; 137 struct vm_amap vm_amap; 138 } k_data; 139}; 140 141/* the size of the object in the kernel */ 142#define S(x) ((x)->k_size) 143/* the address of the object in kernel, two forms */ 144#define A(x) ((x)->k_addr.k_addr_ul) 145#define P(x) ((x)->k_addr.k_addr_p) 146/* the data from the kernel */ 147#define D(x,d) (&((x)->k_data.d)) 148 149/* suck the data from the kernel */ 150#define _KDEREF(kd, addr, dst, sz) do { \ 151 ssize_t len; \ 152 len = kvm_read((kd), (addr), (dst), (sz)); \ 153 if (len != (sz)) \ 154 errx(1, "%s == %ld vs. %lu @ %lx", \ 155 kvm_geterr(kd), (long)len, (unsigned long)(sz), (addr)); \ 156} while (0/*CONSTCOND*/) 157 158/* suck the data using the structure */ 159#define KDEREF(kd, item) _KDEREF((kd), A(item), D(item, data), S(item)) 160 161struct nlist nl[] = { 162 { "_maxsmap" }, 163#define NL_MAXSSIZ 0 164 { "_uvm_vnodeops" }, 165#define NL_UVM_VNODEOPS 1 166 { "_uvm_deviceops" }, 167#define NL_UVM_DEVICEOPS 2 168 { "_aobj_pager" }, 169#define NL_AOBJ_PAGER 3 170 { "_kernel_map" }, 171#define NL_KERNEL_MAP 4 172 { "_nclruhead" }, 173#define NL_NCLRUHEAD 5 174 { NULL } 175}; 176 177void load_symbols(kvm_t *); 178void process_map(kvm_t *, pid_t, struct kinfo_proc *, struct sum *); 179struct vm_map_entry *load_vm_map_entries(kvm_t *, struct vm_map_entry *, 180 struct vm_map_entry *); 181void unload_vm_map_entries(struct vm_map_entry *); 182size_t dump_vm_map_entry(kvm_t *, struct kbit *, struct vm_map_entry *, 183 struct sum *); 184char *findname(kvm_t *, struct kbit *, struct vm_map_entry *, struct kbit *, 185 struct kbit *, struct kbit *); 186int search_cache(kvm_t *, struct kbit *, char **, char *, size_t); 187void load_name_cache(kvm_t *); 188void cache_enter(struct namecache *); 189static void __dead usage(void); 190static pid_t strtopid(const char *); 191void print_sum(struct sum *, struct sum *); 192 193/* 194 * uvm_map address tree implementation. 195 */ 196static int no_impl(void *, void *); 197static int 198no_impl(void *p, void *q) 199{ 200 errx(1, "uvm_map address comparison not implemented"); 201 return 0; 202} 203 204RB_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl); 205 206int 207main(int argc, char *argv[]) 208{ 209 const char *errstr; 210 char errbuf[_POSIX2_LINE_MAX], *kmem = NULL, *kernel = NULL; 211 struct kinfo_proc *kproc; 212 struct sum total_sum; 213 int many, ch, rc; 214 kvm_t *kd; 215 pid_t pid = -1; 216 gid_t gid; 217 218 while ((ch = getopt(argc, argv, "AaD:dlmM:N:p:Prsvx")) != -1) { 219 switch (ch) { 220 case 'A': 221 print_amap = 1; 222 break; 223 case 'a': 224 print_all = 1; 225 break; 226 case 'd': 227 print_ddb = 1; 228 break; 229 case 'D': 230 debug = strtonum(optarg, 0, 0x1f, &errstr); 231 if (errstr) 232 errx(1, "invalid debug mask"); 233 break; 234 case 'l': 235 print_maps = 1; 236 break; 237 case 'm': 238 print_map = 1; 239 break; 240 case 'M': 241 kmem = optarg; 242 break; 243 case 'N': 244 kernel = optarg; 245 break; 246 case 'p': 247 pid = strtopid(optarg); 248 break; 249 case 'P': 250 pid = getpid(); 251 break; 252 case 's': 253 print_solaris = 1; 254 break; 255 case 'v': 256 verbose = 1; 257 break; 258 case 'r': 259 case 'x': 260 errx(1, "-%c option not implemented, sorry", ch); 261 /*NOTREACHED*/ 262 default: 263 usage(); 264 } 265 } 266 267 /* 268 * Discard setgid privileges if not the running kernel so that bad 269 * guys can't print interesting stuff from kernel memory. 270 */ 271 gid = getgid(); 272 if (kernel != NULL || kmem != NULL) 273 if (setresgid(gid, gid, gid) == -1) 274 err(1, "setresgid"); 275 276 argc -= optind; 277 argv += optind; 278 279 /* more than one "process" to dump? */ 280 many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0; 281 282 /* apply default */ 283 if (print_all + print_map + print_maps + print_solaris + 284 print_ddb == 0) 285 print_solaris = 1; 286 287 /* start by opening libkvm */ 288 kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf); 289 290 if (kernel == NULL && kmem == NULL) 291 if (setresgid(gid, gid, gid) == -1) 292 err(1, "setresgid"); 293 294 if (kd == NULL) 295 errx(1, "%s", errbuf); 296 297 /* get "bootstrap" addresses from kernel */ 298 load_symbols(kd); 299 300 memset(&total_sum, 0, sizeof(total_sum)); 301 302 do { 303 struct sum sum; 304 305 memset(&sum, 0, sizeof(sum)); 306 307 if (pid == -1) { 308 if (argc == 0) 309 pid = getppid(); 310 else { 311 pid = strtopid(argv[0]); 312 argv++; 313 argc--; 314 } 315 } 316 317 /* find the process id */ 318 if (pid == 0) 319 kproc = NULL; 320 else { 321 kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, 322 sizeof(struct kinfo_proc), &rc); 323 if (kproc == NULL || rc == 0) { 324 warnc(ESRCH, "%d", pid); 325 pid = -1; 326 continue; 327 } 328 } 329 330 /* dump it */ 331 if (many) { 332 if (kproc) 333 printf("process %d:\n", pid); 334 else 335 printf("kernel:\n"); 336 } 337 338 process_map(kd, pid, kproc, &sum); 339 if (print_amap) 340 print_sum(&sum, &total_sum); 341 pid = -1; 342 } while (argc > 0); 343 344 if (print_amap) 345 print_sum(&total_sum, NULL); 346 347 /* done. go away. */ 348 rc = kvm_close(kd); 349 if (rc == -1) 350 err(1, "kvm_close"); 351 352 return (0); 353} 354 355void 356print_sum(struct sum *sum, struct sum *total_sum) 357{ 358 const char *t = total_sum == NULL ? "total " : ""; 359 printf("%samap mapped slots: %lu\n", t, sum->s_am_nslots); 360 printf("%samap used slots: %lu\n", t, sum->s_am_nusedslots); 361 362 if (total_sum) { 363 total_sum->s_am_nslots += sum->s_am_nslots; 364 total_sum->s_am_nusedslots += sum->s_am_nusedslots; 365 } 366} 367 368void 369process_map(kvm_t *kd, pid_t pid, struct kinfo_proc *proc, struct sum *sum) 370{ 371 struct kbit kbit[3], *vmspace, *vm_map; 372 struct vm_map_entry *vm_map_entry; 373 size_t total = 0; 374 char *thing; 375 uid_t uid; 376 int vmmap_flags; 377 378 if ((uid = getuid())) { 379 if (pid == 0) { 380 warnx("kernel map is restricted"); 381 return; 382 } 383 if (uid != proc->p_uid) { 384 warnx("other users' process maps are restricted"); 385 return; 386 } 387 } 388 389 vmspace = &kbit[0]; 390 vm_map = &kbit[1]; 391 392 A(vmspace) = 0; 393 A(vm_map) = 0; 394 395 if (pid > 0) { 396 A(vmspace) = (u_long)proc->p_vmspace; 397 S(vmspace) = sizeof(struct vmspace); 398 KDEREF(kd, vmspace); 399 thing = "proc->p_vmspace.vm_map"; 400 } else { 401 A(vmspace) = 0; 402 S(vmspace) = 0; 403 thing = "kernel_map"; 404 } 405 406 if (pid > 0 && (debug & PRINT_VMSPACE)) { 407 printf("proc->p_vmspace %p = {", P(vmspace)); 408 printf(" vm_refcnt = %d,", D(vmspace, vmspace)->vm_refcnt); 409 printf(" vm_shm = %p,\n", D(vmspace, vmspace)->vm_shm); 410 printf(" vm_rssize = %d,", D(vmspace, vmspace)->vm_rssize); 411#if 0 412 printf(" vm_swrss = %d,", D(vmspace, vmspace)->vm_swrss); 413#endif 414 printf(" vm_tsize = %d,", D(vmspace, vmspace)->vm_tsize); 415 printf(" vm_dsize = %d,\n", D(vmspace, vmspace)->vm_dsize); 416 printf(" vm_ssize = %d,", D(vmspace, vmspace)->vm_ssize); 417 printf(" vm_taddr = %p,", D(vmspace, vmspace)->vm_taddr); 418 printf(" vm_daddr = %p,\n", D(vmspace, vmspace)->vm_daddr); 419 printf(" vm_maxsaddr = %p,", 420 D(vmspace, vmspace)->vm_maxsaddr); 421 printf(" vm_minsaddr = %p }\n", 422 D(vmspace, vmspace)->vm_minsaddr); 423 } 424 425 S(vm_map) = sizeof(struct vm_map); 426 if (pid > 0) { 427 A(vm_map) = A(vmspace); 428 memcpy(D(vm_map, vm_map), &D(vmspace, vmspace)->vm_map, 429 S(vm_map)); 430 } else { 431 A(vm_map) = kernel_map_addr; 432 KDEREF(kd, vm_map); 433 } 434 if (debug & PRINT_VM_MAP) { 435 printf("%s %p = {", thing, P(vm_map)); 436 437 printf(" pmap = %p,\n", D(vm_map, vm_map)->pmap); 438 printf(" lock = <struct lock>\n"); 439 printf(" size = %lx,", D(vm_map, vm_map)->size); 440 printf(" ref_count = %d,", D(vm_map, vm_map)->ref_count); 441 printf(" ref_lock = <struct simplelock>,\n"); 442 printf(" min_offset-max_offset = 0x%lx-0x%lx\n", 443 D(vm_map, vm_map)->min_offset, 444 D(vm_map, vm_map)->max_offset); 445 printf(" b_start-b_end = 0x%lx-0x%lx\n", 446 D(vm_map, vm_map)->b_start, 447 D(vm_map, vm_map)->b_end); 448 printf(" s_start-s_end = 0x%lx-0x%lx\n", 449 D(vm_map, vm_map)->s_start, 450 D(vm_map, vm_map)->s_end); 451 vmmap_flags = D(vm_map, vm_map)->flags; 452 printf(" flags = %x <%s%s%s%s%s%s >,\n", 453 vmmap_flags, 454 vmmap_flags & VM_MAP_PAGEABLE ? " PAGEABLE" : "", 455 vmmap_flags & VM_MAP_INTRSAFE ? " INTRSAFE" : "", 456 vmmap_flags & VM_MAP_WIREFUTURE ? " WIREFUTURE" : "", 457 vmmap_flags & VM_MAP_BUSY ? " BUSY" : "", 458 vmmap_flags & VM_MAP_WANTLOCK ? " WANTLOCK" : "", 459#if VM_MAP_TOPDOWN > 0 460 vmmap_flags & VM_MAP_TOPDOWN ? " TOPDOWN" : 461#endif 462 ""); 463 printf(" timestamp = %u }\n", D(vm_map, vm_map)->timestamp); 464 } 465 if (print_ddb) { 466 printf("MAP %p: [0x%lx->0x%lx]\n", P(vm_map), 467 D(vm_map, vm_map)->min_offset, 468 D(vm_map, vm_map)->max_offset); 469 printf("\tsz=%ld, ref=%d, version=%d, flags=0x%x\n", 470 D(vm_map, vm_map)->size, 471 D(vm_map, vm_map)->ref_count, 472 D(vm_map, vm_map)->timestamp, 473 D(vm_map, vm_map)->flags); 474 printf("\tpmap=%p(resident=<unknown>)\n", 475 D(vm_map, vm_map)->pmap); 476 } 477 478 /* headers */ 479#ifdef DISABLED_HEADERS 480 if (print_map) 481 printf("%-*s %-*s rwx RWX CPY NCP I W A\n", 482 (int)sizeof(long) * 2 + 2, "Start", 483 (int)sizeof(long) * 2 + 2, "End"); 484 if (print_maps) 485 printf("%-*s %-*s rwxp %-*s Dev Inode File\n", 486 (int)sizeof(long) * 2 + 0, "Start", 487 (int)sizeof(long) * 2 + 0, "End", 488 (int)sizeof(long) * 2 + 0, "Offset"); 489 if (print_solaris) 490 printf("%-*s %*s Protection File\n", 491 (int)sizeof(long) * 2 + 0, "Start", 492 (int)sizeof(int) * 2 - 1, "Size "); 493#endif 494 if (print_all) 495 printf("%-*s %-*s %*s %-*s rwxpc RWX I/W/A Dev %*s - File\n", 496 (int)sizeof(long) * 2, "Start", 497 (int)sizeof(long) * 2, "End", 498 (int)sizeof(int) * 2, "Size ", 499 (int)sizeof(long) * 2, "Offset", 500 (int)sizeof(int) * 2, "Inode"); 501 502 /* these are the "sub entries" */ 503 RB_ROOT(&D(vm_map, vm_map)->addr) = 504 load_vm_map_entries(kd, RB_ROOT(&D(vm_map, vm_map)->addr), NULL); 505 RB_FOREACH(vm_map_entry, uvm_map_addr, &D(vm_map, vm_map)->addr) 506 total += dump_vm_map_entry(kd, vmspace, vm_map_entry, sum); 507 unload_vm_map_entries(RB_ROOT(&D(vm_map, vm_map)->addr)); 508 509 if (print_solaris) 510 printf("%-*s %8luK\n", 511 (int)sizeof(void *) * 2 - 2, " total", 512 (unsigned long)total); 513 if (print_all) 514 printf("%-*s %9luk\n", 515 (int)sizeof(void *) * 4 - 1, " total", 516 (unsigned long)total); 517} 518 519void 520load_symbols(kvm_t *kd) 521{ 522 int rc, i; 523 524 rc = kvm_nlist(kd, &nl[0]); 525 if (rc == -1) 526 errx(1, "%s == %d", kvm_geterr(kd), rc); 527 for (i = 0; i < sizeof(nl)/sizeof(nl[0]); i++) 528 if (nl[i].n_value == 0 && nl[i].n_name) 529 printf("%s not found\n", nl[i].n_name); 530 531 uvm_vnodeops = (void*)nl[NL_UVM_VNODEOPS].n_value; 532 uvm_deviceops = (void*)nl[NL_UVM_DEVICEOPS].n_value; 533 aobj_pager = (void*)nl[NL_AOBJ_PAGER].n_value; 534 535 nclruhead_addr = nl[NL_NCLRUHEAD].n_value; 536 537 _KDEREF(kd, nl[NL_MAXSSIZ].n_value, &maxssiz, 538 sizeof(maxssiz)); 539 _KDEREF(kd, nl[NL_KERNEL_MAP].n_value, &kernel_map_addr, 540 sizeof(kernel_map_addr)); 541} 542 543/* 544 * Recreate the addr tree of vm_map in local memory. 545 */ 546struct vm_map_entry * 547load_vm_map_entries(kvm_t *kd, struct vm_map_entry *kptr, 548 struct vm_map_entry *parent) 549{ 550 static struct kbit map_ent; 551 struct vm_map_entry *result; 552 553 if (kptr == NULL) 554 return NULL; 555 556 A(&map_ent) = (u_long)kptr; 557 S(&map_ent) = sizeof(struct vm_map_entry); 558 KDEREF(kd, &map_ent); 559 560 result = malloc(sizeof(*result)); 561 if (result == NULL) 562 err(1, "malloc"); 563 memcpy(result, D(&map_ent, vm_map_entry), sizeof(struct vm_map_entry)); 564 565 /* 566 * Recurse to download rest of the tree. 567 */ 568 RB_LEFT(result, daddrs.addr_entry) = load_vm_map_entries(kd, 569 RB_LEFT(result, daddrs.addr_entry), result); 570 RB_RIGHT(result, daddrs.addr_entry) = load_vm_map_entries(kd, 571 RB_RIGHT(result, daddrs.addr_entry), result); 572 RB_PARENT(result, daddrs.addr_entry) = parent; 573 return result; 574} 575 576/* 577 * Release the addr tree of vm_map. 578 */ 579void 580unload_vm_map_entries(struct vm_map_entry *ent) 581{ 582 if (ent == NULL) 583 return; 584 585 unload_vm_map_entries(RB_LEFT(ent, daddrs.addr_entry)); 586 unload_vm_map_entries(RB_RIGHT(ent, daddrs.addr_entry)); 587 free(ent); 588} 589 590size_t 591dump_vm_map_entry(kvm_t *kd, struct kbit *vmspace, 592 struct vm_map_entry *vme, struct sum *sum) 593{ 594 struct kbit kbit[5], *uvm_obj, *vp, *vfs, *amap, *uvn; 595 ino_t inode = 0; 596 dev_t dev = 0; 597 size_t sz = 0; 598 char *name; 599 600 uvm_obj = &kbit[0]; 601 vp = &kbit[1]; 602 vfs = &kbit[2]; 603 amap = &kbit[3]; 604 uvn = &kbit[4]; 605 606 A(uvm_obj) = 0; 607 A(vp) = 0; 608 A(vfs) = 0; 609 A(uvn) = 0; 610 611 if (debug & PRINT_VM_MAP_ENTRY) { 612 printf("%s = {", "vm_map_entry"); 613 printf(" start = %lx,", vme->start); 614 printf(" end = %lx,", vme->end); 615 printf(" fspace = %lx,\n", vme->fspace); 616 printf(" object.uvm_obj/sub_map = %p,\n", 617 vme->object.uvm_obj); 618 printf(" offset = %lx,", (unsigned long)vme->offset); 619 printf(" etype = %x <%s%s%s%s%s >,", vme->etype, 620 vme->etype & UVM_ET_OBJ ? " OBJ" : "", 621 vme->etype & UVM_ET_SUBMAP ? " SUBMAP" : "", 622 vme->etype & UVM_ET_COPYONWRITE ? " COW" : "", 623 vme->etype & UVM_ET_NEEDSCOPY ? " NEEDSCOPY" : "", 624 vme->etype & UVM_ET_HOLE ? " HOLE" : ""); 625 printf(" protection = %x,\n", vme->protection); 626 printf(" max_protection = %x,", vme->max_protection); 627 printf(" inheritance = %d,", vme->inheritance); 628 printf(" wired_count = %d,\n", vme->wired_count); 629 printf(" aref = <struct vm_aref>,"); 630 printf(" advice = %d,", vme->advice); 631 printf(" flags = %x <%s%s > }\n", vme->flags, 632 vme->flags & UVM_MAP_STATIC ? " STATIC" : "", 633 vme->flags & UVM_MAP_KMEM ? " KMEM" : ""); 634 } 635 636 A(vp) = 0; 637 A(uvm_obj) = 0; 638 639 if (vme->object.uvm_obj != NULL) { 640 P(uvm_obj) = vme->object.uvm_obj; 641 S(uvm_obj) = sizeof(struct uvm_object); 642 KDEREF(kd, uvm_obj); 643 if (UVM_ET_ISOBJ(vme) && 644 UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) { 645 P(uvn) = P(uvm_obj); 646 S(uvn) = sizeof(struct uvm_vnode); 647 KDEREF(kd, uvn); 648 649 P(vp) = D(uvn, uvm_vnode)->u_vnode; 650 S(vp) = sizeof(struct vnode); 651 KDEREF(kd, vp); 652 } 653 } 654 655 if (vme->aref.ar_amap != NULL) { 656 P(amap) = vme->aref.ar_amap; 657 S(amap) = sizeof(struct vm_amap); 658 KDEREF(kd, amap); 659 } 660 661 A(vfs) = 0; 662 663 if (P(vp) != NULL && D(vp, vnode)->v_mount != NULL) { 664 P(vfs) = D(vp, vnode)->v_mount; 665 S(vfs) = sizeof(struct mount); 666 KDEREF(kd, vfs); 667 D(vp, vnode)->v_mount = D(vfs, mount); 668 } 669 670 /* 671 * dig out the device number and inode number from certain 672 * file system types. 673 */ 674#define V_DATA_IS(vp, type, d, i) do { \ 675 struct kbit data; \ 676 P(&data) = D(vp, vnode)->v_data; \ 677 S(&data) = sizeof(*D(&data, type)); \ 678 KDEREF(kd, &data); \ 679 dev = D(&data, type)->d; \ 680 inode = D(&data, type)->i; \ 681} while (0/*CONSTCOND*/) 682 683 if (A(vp) && 684 D(vp, vnode)->v_type == VREG && 685 D(vp, vnode)->v_data != NULL) { 686 switch (D(vp, vnode)->v_tag) { 687 case VT_UFS: 688 case VT_EXT2FS: 689 V_DATA_IS(vp, inode, i_dev, i_number); 690 break; 691 case VT_ISOFS: 692 V_DATA_IS(vp, iso_node, i_dev, i_number); 693 break; 694 case VT_NON: 695 case VT_NFS: 696 case VT_MFS: 697 case VT_MSDOSFS: 698 default: 699 break; 700 } 701 } 702 703 name = findname(kd, vmspace, vme, vp, vfs, uvm_obj); 704 705 if (print_map) { 706 printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d", 707 vme->start, vme->end, 708 (vme->protection & PROT_READ) ? 'r' : '-', 709 (vme->protection & PROT_WRITE) ? 'w' : '-', 710 (vme->protection & PROT_EXEC) ? 'x' : '-', 711 (vme->max_protection & PROT_READ) ? 'r' : '-', 712 (vme->max_protection & PROT_WRITE) ? 'w' : '-', 713 (vme->max_protection & PROT_EXEC) ? 'x' : '-', 714 (vme->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW", 715 (vme->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC", 716 vme->inheritance, vme->wired_count, 717 vme->advice); 718 if (verbose) { 719 if (inode) 720 printf(" %d,%d %llu", 721 major(dev), minor(dev), 722 (unsigned long long)inode); 723 if (name[0]) 724 printf(" %s", name); 725 } 726 printf("\n"); 727 } 728 729 if (print_maps) 730 printf("%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %llu %s\n", 731 (int)sizeof(void *) * 2, vme->start, 732 (int)sizeof(void *) * 2, vme->end, 733 (vme->protection & PROT_READ) ? 'r' : '-', 734 (vme->protection & PROT_WRITE) ? 'w' : '-', 735 (vme->protection & PROT_EXEC) ? 'x' : '-', 736 (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', 737 (int)sizeof(void *) * 2, 738 (unsigned long)vme->offset, 739 major(dev), minor(dev), (unsigned long long)inode, 740 inode ? name : ""); 741 742 if (print_ddb) { 743 printf(" - <lost address>: 0x%lx->0x%lx: " 744 "obj=%p/0x%lx, amap=%p/%d\n", 745 vme->start, vme->end, 746 vme->object.uvm_obj, (unsigned long)vme->offset, 747 vme->aref.ar_amap, vme->aref.ar_pageoff); 748 printf("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, " 749 "wc=%d, adv=%d\n", 750 (vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F', 751 (vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F', 752 (vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F', 753 vme->protection, vme->max_protection, 754 vme->inheritance, vme->wired_count, vme->advice); 755 if (inode && verbose) 756 printf("\t(dev=%d,%d ino=%llu [%s] [%p])\n", 757 major(dev), minor(dev), (unsigned long long)inode, 758 inode ? name : "", P(vp)); 759 else if (name[0] == ' ' && verbose) 760 printf("\t(%s)\n", &name[2]); 761 } 762 763 if (print_solaris) { 764 char prot[30]; 765 766 prot[0] = '\0'; 767 prot[1] = '\0'; 768 if (vme->protection & PROT_READ) 769 strlcat(prot, "/read", sizeof(prot)); 770 if (vme->protection & PROT_WRITE) 771 strlcat(prot, "/write", sizeof(prot)); 772 if (vme->protection & PROT_EXEC) 773 strlcat(prot, "/exec", sizeof(prot)); 774 775 sz = (size_t)((vme->end - vme->start) / 1024); 776 printf("%0*lX %6luK %-15s %s\n", 777 (int)sizeof(void *) * 2, (unsigned long)vme->start, 778 (unsigned long)sz, &prot[1], name); 779 } 780 781 if (print_all) { 782 sz = (size_t)((vme->end - vme->start) / 1024); 783 printf("%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7llu - %s", 784 (int)sizeof(void *) * 2, vme->start, (int)sizeof(void *) * 2, 785 vme->end - (vme->start != vme->end ? 1 : 0), (unsigned long)sz, 786 (int)sizeof(void *) * 2, (unsigned long)vme->offset, 787 (vme->protection & PROT_READ) ? 'r' : '-', 788 (vme->protection & PROT_WRITE) ? 'w' : '-', 789 (vme->protection & PROT_EXEC) ? 'x' : '-', 790 (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', 791 (vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-', 792 (vme->max_protection & PROT_READ) ? 'r' : '-', 793 (vme->max_protection & PROT_WRITE) ? 'w' : '-', 794 (vme->max_protection & PROT_EXEC) ? 'x' : '-', 795 vme->inheritance, vme->wired_count, vme->advice, 796 major(dev), minor(dev), (unsigned long long)inode, name); 797 if (A(vp)) 798 printf(" [%p]", P(vp)); 799 printf("\n"); 800 } 801 802 if (print_amap && vme->aref.ar_amap) { 803 printf(" amap - ref: %d fl: 0x%x nsl: %d nuse: %d\n", 804 D(amap, vm_amap)->am_ref, 805 D(amap, vm_amap)->am_flags, 806 D(amap, vm_amap)->am_nslot, 807 D(amap, vm_amap)->am_nused); 808 if (sum) { 809 sum->s_am_nslots += D(amap, vm_amap)->am_nslot; 810 sum->s_am_nusedslots += D(amap, vm_amap)->am_nused; 811 } 812 } 813 814 /* no access allowed, don't count space */ 815 if ((vme->protection & rwx) == 0) 816 sz = 0; 817 818 return (sz); 819} 820 821char * 822findname(kvm_t *kd, struct kbit *vmspace, 823 struct vm_map_entry *vme, struct kbit *vp, 824 struct kbit *vfs, struct kbit *uvm_obj) 825{ 826 static char buf[1024], *name; 827 size_t l; 828 829 if (UVM_ET_ISOBJ(vme)) { 830 if (A(vfs)) { 831 l = strlen(D(vfs, mount)->mnt_stat.f_mntonname); 832 switch (search_cache(kd, vp, &name, buf, sizeof(buf))) { 833 case 0: /* found something */ 834 if (name - (1 + 11 + l) < buf) 835 break; 836 name--; 837 *name = '/'; 838 /*FALLTHROUGH*/ 839 case 2: /* found nothing */ 840 name -= 11; 841 memcpy(name, " -unknown- ", (size_t)11); 842 name -= l; 843 memcpy(name, 844 D(vfs, mount)->mnt_stat.f_mntonname, l); 845 break; 846 case 1: /* all is well */ 847 if (name - (1 + l) < buf) 848 break; 849 name--; 850 *name = '/'; 851 if (l != 1) { 852 name -= l; 853 memcpy(name, 854 D(vfs, mount)->mnt_stat.f_mntonname, l); 855 } 856 break; 857 } 858 } else if (UVM_OBJ_IS_DEVICE(D(uvm_obj, uvm_object))) { 859 struct kbit kdev; 860 dev_t dev; 861 862 P(&kdev) = P(uvm_obj); 863 S(&kdev) = sizeof(struct uvm_device); 864 KDEREF(kd, &kdev); 865 dev = D(&kdev, uvm_device)->u_device; 866 name = devname(dev, S_IFCHR); 867 if (name != NULL) 868 snprintf(buf, sizeof(buf), "/dev/%s", name); 869 else 870 snprintf(buf, sizeof(buf), " [ device %d,%d ]", 871 major(dev), minor(dev)); 872 name = buf; 873 } else if (UVM_OBJ_IS_AOBJ(D(uvm_obj, uvm_object))) 874 name = " [ uvm_aobj ]"; 875 else if (UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) 876 name = " [ ?VNODE? ]"; 877 else { 878 snprintf(buf, sizeof(buf), " [ unknown (%p) ]", 879 D(uvm_obj, uvm_object)->pgops); 880 name = buf; 881 } 882 } else if (D(vmspace, vmspace)->vm_maxsaddr <= (caddr_t)vme->start && 883 (D(vmspace, vmspace)->vm_maxsaddr + (size_t)maxssiz) >= 884 (caddr_t)vme->end) { 885 name = " [ stack ]"; 886 } else if (UVM_ET_ISHOLE(vme)) 887 name = " [ hole ]"; 888 else 889 name = " [ anon ]"; 890 891 return (name); 892} 893 894int 895search_cache(kvm_t *kd, struct kbit *vp, char **name, char *buf, size_t blen) 896{ 897 struct cache_entry *ce; 898 struct kbit svp; 899 char *o, *e; 900 u_long cid; 901 902 if (!namecache_loaded) 903 load_name_cache(kd); 904 905 P(&svp) = P(vp); 906 S(&svp) = sizeof(struct vnode); 907 cid = D(vp, vnode)->v_id; 908 909 e = &buf[blen - 1]; 910 o = e; 911 do { 912 LIST_FOREACH(ce, &lcache, ce_next) 913 if (ce->ce_vp == P(&svp) && ce->ce_cid == cid) 914 break; 915 if (ce && ce->ce_vp == P(&svp) && ce->ce_cid == cid) { 916 if (o != e) { 917 if (o <= buf) 918 break; 919 *(--o) = '/'; 920 } 921 if (o - ce->ce_nlen <= buf) 922 break; 923 o -= ce->ce_nlen; 924 memcpy(o, ce->ce_name, ce->ce_nlen); 925 P(&svp) = ce->ce_pvp; 926 cid = ce->ce_pcid; 927 } else 928 break; 929 } while (1/*CONSTCOND*/); 930 *e = '\0'; 931 *name = o; 932 933 if (e == o) 934 return (2); 935 936 KDEREF(kd, &svp); 937 return (D(&svp, vnode)->v_flag & VROOT); 938} 939 940void 941load_name_cache(kvm_t *kd) 942{ 943 struct namecache n, *tmp; 944 struct namecache_head nchead; 945 946 LIST_INIT(&lcache); 947 _KDEREF(kd, nclruhead_addr, &nchead, sizeof(nchead)); 948 tmp = TAILQ_FIRST(&nchead); 949 while (tmp != NULL) { 950 _KDEREF(kd, (u_long)tmp, &n, sizeof(n)); 951 952 if (n.nc_nlen > 0) { 953 if (n.nc_nlen > 2 || 954 n.nc_name[0] != '.' || 955 (n.nc_nlen != 1 && n.nc_name[1] != '.')) 956 cache_enter(&n); 957 } 958 tmp = TAILQ_NEXT(&n, nc_lru); 959 } 960 961 namecache_loaded = 1; 962} 963 964void 965cache_enter(struct namecache *ncp) 966{ 967 struct cache_entry *ce; 968 969 if (debug & DUMP_NAMEI_CACHE) 970 printf("ncp->nc_vp %10p, ncp->nc_dvp %10p, ncp->nc_nlen " 971 "%3d [%.*s] (nc_dvpid=%lu, nc_vpid=%lu)\n", 972 ncp->nc_vp, ncp->nc_dvp, 973 ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name, 974 ncp->nc_dvpid, ncp->nc_vpid); 975 976 ce = malloc(sizeof(struct cache_entry)); 977 if (ce == NULL) 978 err(1, "cache_enter"); 979 980 ce->ce_vp = ncp->nc_vp; 981 ce->ce_pvp = ncp->nc_dvp; 982 ce->ce_cid = ncp->nc_vpid; 983 ce->ce_pcid = ncp->nc_dvpid; 984 ce->ce_nlen = (unsigned)ncp->nc_nlen; 985 strlcpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name)); 986 987 LIST_INSERT_HEAD(&lcache, ce, ce_next); 988} 989 990static void __dead 991usage(void) 992{ 993 extern char *__progname; 994 fprintf(stderr, "usage: %s [-AadlmPsv] [-D number] " 995 "[-M core] [-N system] [-p pid] [pid ...]\n", 996 __progname); 997 exit(1); 998} 999 1000static pid_t 1001strtopid(const char *str) 1002{ 1003 pid_t pid; 1004 1005 errno = 0; 1006 pid = (pid_t)strtonum(str, 0, INT_MAX, NULL); 1007 if (errno != 0) 1008 usage(); 1009 return (pid); 1010} 1011