size_t dump_vm_map_entry(kvm_t *kd, struct kbit *vmspace, struct vm_map_entry *vme, struct sum *sum) { struct kbit kbit[4], *uvm_obj, *vp, *vfs, *amap; ino_t inode = 0; dev_t dev = 0; size_t sz = 0; char *name; uvm_obj = &kbit[0]; vp = &kbit[1]; vfs = &kbit[2]; amap = &kbit[3]; A(uvm_obj) = 0; A(vp) = 0; A(vfs) = 0; if (debug & PRINT_VM_MAP_ENTRY) { printf("%s = {", "vm_map_entry"); printf(" start = %lx,", vme->start); printf(" end = %lx,", vme->end); printf(" object.uvm_obj/sub_map = %p,\n", vme->object.uvm_obj); printf(" offset = %lx,", (unsigned long)vme->offset); printf(" etype = %x <%s%s%s%s%s >,", vme->etype, vme->etype & UVM_ET_OBJ ? " OBJ" : "", vme->etype & UVM_ET_SUBMAP ? " SUBMAP" : "", vme->etype & UVM_ET_COPYONWRITE ? " COW" : "", vme->etype & UVM_ET_NEEDSCOPY ? " NEEDSCOPY" : "", vme->etype & UVM_ET_HOLE ? " HOLE" : ""); printf(" protection = %x,\n", vme->protection); printf(" max_protection = %x,", vme->max_protection); printf(" inheritance = %d,", vme->inheritance); printf(" wired_count = %d,\n", vme->wired_count); printf(" aref = <struct vm_aref>,"); printf(" advice = %d,", vme->advice); printf(" flags = %x <%s%s > }\n", vme->flags, vme->flags & UVM_MAP_STATIC ? " STATIC" : "", vme->flags & UVM_MAP_KMEM ? " KMEM" : ""); } A(vp) = 0; A(uvm_obj) = 0; if (vme->object.uvm_obj != NULL) { P(uvm_obj) = vme->object.uvm_obj; S(uvm_obj) = sizeof(struct uvm_object); KDEREF(kd, uvm_obj); if (UVM_ET_ISOBJ(vme) && UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) { P(vp) = P(uvm_obj); S(vp) = sizeof(struct vnode); KDEREF(kd, vp); } } if (vme->aref.ar_amap != NULL) { P(amap) = vme->aref.ar_amap; S(amap) = sizeof(struct vm_amap); KDEREF(kd, amap); } A(vfs) = 0; if (P(vp) != NULL && D(vp, vnode)->v_mount != NULL) { P(vfs) = D(vp, vnode)->v_mount; S(vfs) = sizeof(struct mount); KDEREF(kd, vfs); D(vp, vnode)->v_mount = D(vfs, mount); } /* * dig out the device number and inode number from certain * file system types. */ #define V_DATA_IS(vp, type, d, i) do { \ struct kbit data; \ P(&data) = D(vp, vnode)->v_data; \ S(&data) = sizeof(*D(&data, type)); \ KDEREF(kd, &data); \ dev = D(&data, type)->d; \ inode = D(&data, type)->i; \ } while (0/*CONSTCOND*/) if (A(vp) && D(vp, vnode)->v_type == VREG && D(vp, vnode)->v_data != NULL) { switch (D(vp, vnode)->v_tag) { case VT_UFS: case VT_EXT2FS: V_DATA_IS(vp, inode, i_dev, i_number); break; case VT_ISOFS: V_DATA_IS(vp, iso_node, i_dev, i_number); break; case VT_NON: case VT_NFS: case VT_MFS: case VT_MSDOSFS: case VT_PROCFS: default: break; } } name = findname(kd, vmspace, vme, vp, vfs, uvm_obj); if (print_map) { printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d", vme->start, vme->end, (vme->protection & VM_PROT_READ) ? 'r' : '-', (vme->protection & VM_PROT_WRITE) ? 'w' : '-', (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-', (vme->max_protection & VM_PROT_READ) ? 'r' : '-', (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-', (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-', (vme->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW", (vme->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC", vme->inheritance, vme->wired_count, vme->advice); if (verbose) { if (inode) printf(" %d,%d %llu", major(dev), minor(dev), (unsigned long long)inode); if (name[0]) printf(" %s", name); } printf("\n"); } if (print_maps) printf("%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %llu %s\n", (int)sizeof(void *) * 2, vme->start, (int)sizeof(void *) * 2, vme->end, (vme->protection & VM_PROT_READ) ? 'r' : '-', (vme->protection & VM_PROT_WRITE) ? 'w' : '-', (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-', (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', (int)sizeof(void *) * 2, (unsigned long)vme->offset, major(dev), minor(dev), (unsigned long long)inode, inode ? name : ""); if (print_ddb) { printf(" - <lost address>: 0x%lx->0x%lx: " "obj=%p/0x%lx, amap=%p/%d\n", vme->start, vme->end, vme->object.uvm_obj, (unsigned long)vme->offset, vme->aref.ar_amap, vme->aref.ar_pageoff); printf("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, " "wc=%d, adv=%d\n", (vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F', (vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F', (vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F', vme->protection, vme->max_protection, vme->inheritance, vme->wired_count, vme->advice); if (inode && verbose) printf("\t(dev=%d,%d ino=%llu [%s] [%p])\n", major(dev), minor(dev), (unsigned long long)inode, inode ? name : "", P(vp)); else if (name[0] == ' ' && verbose) printf("\t(%s)\n", &name[2]); } if (print_solaris) { char prot[30]; prot[0] = '\0'; prot[1] = '\0'; if (vme->protection & VM_PROT_READ) strlcat(prot, "/read", sizeof(prot)); if (vme->protection & VM_PROT_WRITE) strlcat(prot, "/write", sizeof(prot)); if (vme->protection & VM_PROT_EXECUTE) strlcat(prot, "/exec", sizeof(prot)); sz = (size_t)((vme->end - vme->start) / 1024); printf("%0*lX %6luK %-15s %s\n", (int)sizeof(void *) * 2, (unsigned long)vme->start, (unsigned long)sz, &prot[1], name); } if (print_all) { sz = (size_t)((vme->end - vme->start) / 1024); printf("%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7llu - %s", (int)sizeof(void *) * 2, vme->start, (int)sizeof(void *) * 2, vme->end - (vme->start != vme->end ? 1 : 0), (unsigned long)sz, (int)sizeof(void *) * 2, (unsigned long)vme->offset, (vme->protection & VM_PROT_READ) ? 'r' : '-', (vme->protection & VM_PROT_WRITE) ? 'w' : '-', (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-', (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', (vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-', (vme->max_protection & VM_PROT_READ) ? 'r' : '-', (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-', (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-', vme->inheritance, vme->wired_count, vme->advice, major(dev), minor(dev), (unsigned long long)inode, name); if (A(vp)) printf(" [%p]", P(vp)); printf("\n"); } if (print_amap && vme->aref.ar_amap) { printf(" amap - ref: %d fl: 0x%x maxsl: %d nsl: %d nuse: %d\n", D(amap, vm_amap)->am_ref, D(amap, vm_amap)->am_flags, D(amap, vm_amap)->am_maxslot, D(amap, vm_amap)->am_nslot, D(amap, vm_amap)->am_nused); if (sum) { sum->s_am_nslots += D(amap, vm_amap)->am_nslot; sum->s_am_maxslots += D(amap, vm_amap)->am_maxslot; sum->s_am_nusedslots += D(amap, vm_amap)->am_nused; } } /* no access allowed, don't count space */ if ((vme->protection & rwx) == 0) sz = 0; return (sz); }
char * findname(kvm_t *kd, struct kbit *vmspace, struct vm_map_entry *vme, struct kbit *vp, struct kbit *vfs, struct kbit *uvm_obj) { static char buf[1024], *name; size_t l; if (UVM_ET_ISOBJ(vme)) { if (A(vfs)) { l = strlen(D(vfs, mount)->mnt_stat.f_mntonname); switch (search_cache(kd, vp, &name, buf, sizeof(buf))) { case 0: /* found something */ if (name - (1 + 11 + l) < buf) break; name--; *name = '/'; /*FALLTHROUGH*/ case 2: /* found nothing */ name -= 11; memcpy(name, " -unknown- ", (size_t)11); name -= l; memcpy(name, D(vfs, mount)->mnt_stat.f_mntonname, l); break; case 1: /* all is well */ if (name - (1 + l) < buf) break; name--; *name = '/'; if (l != 1) { name -= l; memcpy(name, D(vfs, mount)->mnt_stat.f_mntonname, l); } break; } } else if (UVM_OBJ_IS_DEVICE(D(uvm_obj, uvm_object))) { struct kbit kdev; dev_t dev; P(&kdev) = P(uvm_obj); S(&kdev) = sizeof(struct uvm_device); KDEREF(kd, &kdev); dev = D(&kdev, uvm_device)->u_device; name = devname(dev, S_IFCHR); if (name != NULL) snprintf(buf, sizeof(buf), "/dev/%s", name); else snprintf(buf, sizeof(buf), " [ device %d,%d ]", major(dev), minor(dev)); name = buf; } else if (UVM_OBJ_IS_AOBJ(D(uvm_obj, uvm_object))) name = " [ uvm_aobj ]"; else if (UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) name = " [ ?VNODE? ]"; else { snprintf(buf, sizeof(buf), " [ unknown (%p) ]", D(uvm_obj, uvm_object)->pgops); name = buf; } } else if (D(vmspace, vmspace)->vm_maxsaddr <= (caddr_t)vme->start && (D(vmspace, vmspace)->vm_maxsaddr + (size_t)maxssiz) >= (caddr_t)vme->end) { name = " [ stack ]"; } else if (D(vmspace, vmspace)->vm_daddr <= (caddr_t)vme->start && D(vmspace, vmspace)->vm_daddr + BRKSIZ >= (caddr_t)vme->end) { name = " [ heap ]"; } else if (UVM_ET_ISHOLE(vme)) name = " [ hole ]"; else name = " [ anon ]"; return (name); }
/* * The map entries can *almost* be read with programs like cat. However, * large maps need special programs to read. It is not easy to implement * a program that can sense the required size of the buffer, and then * subsequently do a read with the appropriate size. This operation cannot * be atomic. The best that we can do is to allow the program to do a read * with an arbitrarily large buffer, and return as much as we can. We can * return an error code if the buffer is too small (EFBIG), then the program * can try a bigger buffer. */ int procfs_domap(struct lwp *curl, struct proc *p, struct pfsnode *pfs, struct uio *uio, int linuxmode) { int error; struct vmspace *vm; struct vm_map *map; struct vm_map_entry *entry; char *buffer = NULL; size_t bufsize = BUFFERSIZE; char *path; struct vnode *vp; struct vattr va; dev_t dev; long fileid; size_t pos; int width = (int)((curl->l_proc->p_flag & PK_32) ? sizeof(int32_t) : sizeof(void *)) * 2; if (uio->uio_rw != UIO_READ) return EOPNOTSUPP; if (uio->uio_offset != 0) { /* * we return 0 here, so that the second read returns EOF * we don't support reading from an offset because the * map could have changed between the two reads. */ return 0; } error = 0; if (linuxmode != 0) path = malloc(MAXPATHLEN * 4, M_TEMP, M_WAITOK); else path = NULL; if ((error = proc_vmspace_getref(p, &vm)) != 0) goto out; map = &vm->vm_map; vm_map_lock_read(map); again: buffer = malloc(bufsize, M_TEMP, M_WAITOK); pos = 0; for (entry = map->header.next; entry != &map->header; entry = entry->next) { if (UVM_ET_ISSUBMAP(entry)) continue; if (linuxmode != 0) { *path = 0; dev = (dev_t)0; fileid = 0; if (UVM_ET_ISOBJ(entry) && UVM_OBJ_IS_VNODE(entry->object.uvm_obj)) { vp = (struct vnode *)entry->object.uvm_obj; vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &va, curl->l_cred); VOP_UNLOCK(vp); if (error == 0 && vp != pfs->pfs_vnode) { fileid = va.va_fileid; dev = va.va_fsid; error = vnode_to_path(path, MAXPATHLEN * 4, vp, curl, p); } } pos += snprintf(buffer + pos, bufsize - pos, "%.*"PRIxVADDR"-%.*"PRIxVADDR" %c%c%c%c " "%.*lx %.2llx:%.2llx %-8ld %25.s %s\n", width, entry->start, width, entry->end, (entry->protection & VM_PROT_READ) ? 'r' : '-', (entry->protection & VM_PROT_WRITE) ? 'w' : '-', (entry->protection & VM_PROT_EXECUTE) ? 'x' : '-', (entry->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', width, (unsigned long)entry->offset, (unsigned long long)major(dev), (unsigned long long)minor(dev), fileid, "", path); } else { pos += snprintf(buffer + pos, bufsize - pos, "%#"PRIxVADDR" %#"PRIxVADDR" " "%c%c%c %c%c%c %s %s %d %d %d\n", entry->start, entry->end, (entry->protection & VM_PROT_READ) ? 'r' : '-', (entry->protection & VM_PROT_WRITE) ? 'w' : '-', (entry->protection & VM_PROT_EXECUTE) ? 'x' : '-', (entry->max_protection & VM_PROT_READ) ? 'r' : '-', (entry->max_protection & VM_PROT_WRITE) ? 'w' : '-', (entry->max_protection & VM_PROT_EXECUTE) ? 'x' : '-', (entry->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW", (entry->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC", entry->inheritance, entry->wired_count, entry->advice); } if (pos >= bufsize) { bufsize <<= 1; if (bufsize > MAXBUFFERSIZE) { error = ENOMEM; vm_map_unlock_read(map); uvmspace_free(vm); goto out; } free(buffer, M_TEMP); goto again; } } vm_map_unlock_read(map); uvmspace_free(vm); error = uiomove(buffer, pos, uio); out: if (path != NULL) free(path, M_TEMP); if (buffer != NULL) free(buffer, M_TEMP); return error; }