static void get_proc_size_info(struct lwp *l, unsigned long *stext, unsigned long *etext, unsigned long *sstack) { struct proc *p = l->l_proc; struct vmspace *vm; struct vm_map *map; struct vm_map_entry *entry; *stext = 0; *etext = 0; *sstack = 0; proc_vmspace_getref(p, &vm); map = &vm->vm_map; vm_map_lock_read(map); for (entry = map->header.next; entry != &map->header; entry = entry->next) { if (UVM_ET_ISSUBMAP(entry)) continue; /* assume text is the first entry */ if (*stext == *etext) { *stext = entry->start; *etext = entry->end; break; } } #if defined(LINUX_USRSTACK32) && defined(USRSTACK32) if (strcmp(p->p_emul->e_name, "linux32") == 0 && LINUX_USRSTACK32 < USRSTACK32) *sstack = (unsigned long)LINUX_USRSTACK32; else #endif #ifdef LINUX_USRSTACK if (strcmp(p->p_emul->e_name, "linux") == 0 && LINUX_USRSTACK < USRSTACK) *sstack = (unsigned long)LINUX_USRSTACK; else #endif #ifdef USRSTACK32 if (strstr(p->p_emul->e_name, "32") != NULL) *sstack = (unsigned long)USRSTACK32; else #endif *sstack = (unsigned long)USRSTACK; /* * jdk 1.6 compares low <= addr && addr < high * if we put addr == high, then the test fails * so eat one page. */ *sstack -= PAGE_SIZE; vm_map_unlock_read(map); uvmspace_free(vm); }
/* * 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; }
/* ARGSUSED */ int sys_mincore(struct lwp *l, const struct sys_mincore_args *uap, register_t *retval) { /* { syscallarg(void *) addr; syscallarg(size_t) len; syscallarg(char *) vec; } */ struct proc *p = l->l_proc; struct vm_page *pg; char *vec, pgi; struct uvm_object *uobj; struct vm_amap *amap; struct vm_anon *anon; struct vm_map_entry *entry; vaddr_t start, end, lim; struct vm_map *map; vsize_t len; int error = 0, npgs; map = &p->p_vmspace->vm_map; start = (vaddr_t)SCARG(uap, addr); len = SCARG(uap, len); vec = SCARG(uap, vec); if (start & PAGE_MASK) return EINVAL; len = round_page(len); end = start + len; if (end <= start) return EINVAL; /* * Lock down vec, so our returned status isn't outdated by * storing the status byte for a page. */ npgs = len >> PAGE_SHIFT; error = uvm_vslock(p->p_vmspace, vec, npgs, VM_PROT_WRITE); if (error) { return error; } vm_map_lock_read(map); if (uvm_map_lookup_entry(map, start, &entry) == false) { error = ENOMEM; goto out; } for (/* nothing */; entry != &map->header && entry->start < end; entry = entry->next) { KASSERT(!UVM_ET_ISSUBMAP(entry)); KASSERT(start >= entry->start); /* Make sure there are no holes. */ if (entry->end < end && (entry->next == &map->header || entry->next->start > entry->end)) { error = ENOMEM; goto out; } lim = end < entry->end ? end : entry->end; /* * Special case for objects with no "real" pages. Those * are always considered resident (mapped devices). */ if (UVM_ET_ISOBJ(entry)) { KASSERT(!UVM_OBJ_IS_KERN_OBJECT(entry->object.uvm_obj)); if (UVM_OBJ_IS_DEVICE(entry->object.uvm_obj)) { for (/* nothing */; start < lim; start += PAGE_SIZE, vec++) subyte(vec, 1); continue; } } amap = entry->aref.ar_amap; /* upper layer */ uobj = entry->object.uvm_obj; /* lower layer */ if (amap != NULL) amap_lock(amap); if (uobj != NULL) mutex_enter(uobj->vmobjlock); for (/* nothing */; start < lim; start += PAGE_SIZE, vec++) { pgi = 0; if (amap != NULL) { /* Check the upper layer first. */ anon = amap_lookup(&entry->aref, start - entry->start); /* Don't need to lock anon here. */ if (anon != NULL && anon->an_page != NULL) { /* * Anon has the page for this entry * offset. */ pgi = 1; } } if (uobj != NULL && pgi == 0) { /* Check the lower layer. */ pg = uvm_pagelookup(uobj, entry->offset + (start - entry->start)); if (pg != NULL) { /* * Object has the page for this entry * offset. */ pgi = 1; } } (void) subyte(vec, pgi); } if (uobj != NULL) mutex_exit(uobj->vmobjlock); if (amap != NULL) amap_unlock(amap); } out: vm_map_unlock_read(map); uvm_vsunlock(p->p_vmspace, SCARG(uap, vec), npgs); return error; }
/* ARGSUSED */ int sys_mincore(struct proc *p, void *v, register_t *retval) { struct sys_mincore_args /* { syscallarg(void *) addr; syscallarg(size_t) len; syscallarg(char *) vec; } */ *uap = v; vm_page_t m; char *vec, pgi; struct uvm_object *uobj; struct vm_amap *amap; struct vm_anon *anon; vm_map_entry_t entry; vaddr_t start, end, lim; vm_map_t map; vsize_t len, npgs; int error = 0; map = &p->p_vmspace->vm_map; start = (vaddr_t)SCARG(uap, addr); len = SCARG(uap, len); vec = SCARG(uap, vec); if (start & PAGE_MASK) return (EINVAL); len = round_page(len); end = start + len; if (end <= start) return (EINVAL); npgs = len >> PAGE_SHIFT; /* * Lock down vec, so our returned status isn't outdated by * storing the status byte for a page. */ if ((error = uvm_vslock(p, vec, npgs, VM_PROT_WRITE)) != 0) return (error); vm_map_lock_read(map); if (uvm_map_lookup_entry(map, start, &entry) == FALSE) { error = ENOMEM; goto out; } for (/* nothing */; entry != &map->header && entry->start < end; entry = entry->next) { KASSERT(!UVM_ET_ISSUBMAP(entry)); KASSERT(start >= entry->start); /* Make sure there are no holes. */ if (entry->end < end && (entry->next == &map->header || entry->next->start > entry->end)) { error = ENOMEM; goto out; } lim = end < entry->end ? end : entry->end; /* * Special case for objects with no "real" pages. Those * are always considered resident (mapped devices). */ if (UVM_ET_ISOBJ(entry)) { KASSERT(!UVM_OBJ_IS_KERN_OBJECT(entry->object.uvm_obj)); if (entry->object.uvm_obj->pgops->pgo_releasepg == NULL) { pgi = 1; for (/* nothing */; start < lim; start += PAGE_SIZE, vec++) copyout(&pgi, vec, sizeof(char)); continue; } } amap = entry->aref.ar_amap; /* top layer */ uobj = entry->object.uvm_obj; /* bottom layer */ if (uobj != NULL) simple_lock(&uobj->vmobjlock); for (/* nothing */; start < lim; start += PAGE_SIZE, vec++) { pgi = 0; if (amap != NULL) { /* Check the top layer first. */ anon = amap_lookup(&entry->aref, start - entry->start); /* Don't need to lock anon here. */ if (anon != NULL && anon->an_page != NULL) { /* * Anon has the page for this entry * offset. */ pgi = 1; } } if (uobj != NULL && pgi == 0) { /* Check the bottom layer. */ m = uvm_pagelookup(uobj, entry->offset + (start - entry->start)); if (m != NULL) { /* * Object has the page for this entry * offset. */ pgi = 1; } } copyout(&pgi, vec, sizeof(char)); } if (uobj != NULL) simple_unlock(&uobj->vmobjlock); } out: vm_map_unlock_read(map); uvm_vsunlock(p, SCARG(uap, vec), npgs); return (error); }