summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gen/sysctl.313
-rw-r--r--sys/kern/kern_sysctl.c102
-rw-r--r--sys/sys/sysctl.h50
-rw-r--r--sys/uvm/uvm_extern.h7
-rw-r--r--sys/uvm/uvm_glue.c17
-rw-r--r--sys/uvm/uvm_map.c58
-rw-r--r--sys/uvm/uvm_map.h7
7 files changed, 245 insertions, 9 deletions
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index 62d8e7c698a..eb6a2acedcb 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sysctl.3,v 1.243 2014/11/19 18:04:54 tedu Exp $
+.\" $OpenBSD: sysctl.3,v 1.244 2014/12/05 04:12:48 uebayasi Exp $
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd $Mdocdate: November 19 2014 $
+.Dd $Mdocdate: December 5 2014 $
.Dt SYSCTL 3
.Os
.Sh NAME
@@ -443,6 +443,7 @@ information.
.It Dv KERN_PROC_ARGS Ta "node" Ta "not applicable"
.It Dv KERN_PROC_CWD Ta "string" Ta "not applicable"
.It Dv KERN_PROC_NOBROADKILL Ta "string" Ta "not applicable"
+.It Dv KERN_PROC_VMMAP Ta "struct kinfo_vmentry" Ta "no"
.It Dv KERN_PROF Ta "node" Ta "not applicable"
.It Dv KERN_RAWPARTITION Ta "integer" Ta "no"
.It Dv KERN_RND Ta "struct rndstats" Ta "no"
@@ -739,6 +740,14 @@ A NUL-terminated string is returned.
.It Dv KERN_PROC_NOBROADKILL
When set, a process will no longer be signaled when sending broadcast signals.
The third level name is the target process ID.
+.It Dv KERN_PROC_VMMAP
+Return the entire process VM map entries.
+An array of
+.Li struct kinfo_vmentry
+structures is returned,
+whose size depends on the current number of VM map entries of the selected process.
+Iteration is possible by setting the base address in the first element of
+.Li struct kinfo_vmentry .
.It Dv KERN_PROF
Return profiling information about the kernel.
If the kernel is not compiled for profiling,
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 44d90ad07d3..b0bb84e35cd 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.272 2014/11/19 21:17:37 tedu Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.273 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -77,6 +77,8 @@
#include <sys/mount.h>
#include <sys/syscallargs.h>
+#include <uvm/uvm_extern.h>
+
#include <dev/cons.h>
#include <dev/rndvar.h>
#include <dev/systrace.h>
@@ -117,6 +119,7 @@ int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *);
int sysctl_proc_cwd(int *, u_int, void *, size_t *, struct proc *);
int sysctl_proc_nobroadcastkill(int *, u_int, void *, size_t, void *, size_t *,
struct proc *);
+int sysctl_proc_vmmap(int *, u_int, void *, size_t *, struct proc *);
int sysctl_intrcnt(int *, u_int, void *, size_t *);
int sysctl_sensors(int *, u_int, void *, size_t *, void *, size_t);
int sysctl_emul(int *, u_int, void *, size_t *, void *, size_t);
@@ -276,6 +279,7 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
case KERN_PROC_ARGS:
case KERN_PROC_CWD:
case KERN_PROC_NOBROADCASTKILL:
+ case KERN_PROC_VMMAP:
case KERN_SYSVIPC_INFO:
case KERN_SEMINFO:
case KERN_SHMINFO:
@@ -365,6 +369,9 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
case KERN_PROC_NOBROADCASTKILL:
return (sysctl_proc_nobroadcastkill(name + 1, namelen - 1,
newp, newlen, oldp, oldlenp, p));
+ case KERN_PROC_VMMAP:
+ return (sysctl_proc_vmmap(name + 1, namelen - 1, oldp, oldlenp,
+ p));
case KERN_FILE:
return (sysctl_file(name + 1, namelen - 1, oldp, oldlenp, p));
#endif
@@ -1838,6 +1845,99 @@ sysctl_proc_nobroadcastkill(int *name, u_int namelen, void *newp, size_t newlen,
return (error);
}
+
+/* Arbitrary but reasonable limit for one iteration. */
+#define VMMAP_MAXLEN MAXPHYS
+
+int
+sysctl_proc_vmmap(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ struct proc *cp)
+{
+ struct process *findpr;
+ pid_t pid;
+ int error;
+ size_t oldlen, len;
+ struct kinfo_vmentry *kve, *ukve;
+ u_long *ustart, start;
+
+ if (namelen > 1)
+ return (ENOTDIR);
+ if (namelen < 1)
+ return (EINVAL);
+
+ /* Provide max buffer length as hint. */
+ if (oldp == NULL) {
+ if (oldlenp == NULL)
+ return (EINVAL);
+ else {
+ *oldlenp = VMMAP_MAXLEN;
+ return (0);
+ }
+ }
+
+ pid = name[0];
+ if (pid > 0) {
+ if ((findpr = prfind(pid)) == NULL)
+ return (ESRCH);
+
+ /* Either system process or exiting/zombie */
+ if (findpr->ps_flags & (PS_SYSTEM | PS_EXITING))
+ return (EINVAL);
+
+ /* Only owner or root can get vmmap */
+ if (findpr->ps_ucred->cr_uid != cp->p_ucred->cr_uid &&
+ (error = suser(cp, 0)) != 0)
+ return (error);
+ } else {
+ /* Only root can get kernel_map */
+ if ((error = suser(cp, 0)) != 0)
+ return (error);
+ findpr = NULL;
+ }
+
+ /* Check the given size. */
+ oldlen = *oldlenp;
+ if (oldlen == 0 || oldlen % sizeof(*kve) != 0)
+ return (EINVAL);
+
+ /* Deny huge allocation. */
+ if (oldlen > VMMAP_MAXLEN)
+ return (EINVAL);
+
+ /*
+ * Iterate from the given address passed as the first element's
+ * kve_start via oldp.
+ */
+ ukve = (struct kinfo_vmentry *)oldp;
+ ustart = &ukve->kve_start;
+ error = copyin(ustart, &start, sizeof(start));
+ if (error != 0)
+ return (error);
+
+ /* Allocate wired memory to not block. */
+ kve = malloc(oldlen, M_TEMP, M_WAITOK);
+
+ /* Set the base address and read entries. */
+ kve[0].kve_start = start;
+ len = oldlen;
+ error = fill_vmmap(findpr, kve, &len);
+ if (error != 0 && error != ENOMEM)
+ goto done;
+ if (len == 0)
+ goto done;
+
+ KASSERT(len <= oldlen);
+ KASSERT((len % sizeof(struct kinfo_vmentry)) == 0);
+
+ error = copyout(kve, oldp, len);
+
+done:
+ *oldlenp = len;
+
+ free(kve, M_TEMP, oldlen);
+
+ return (error);
+}
#endif
/*
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index 52b3d2ca096..3b824fa7531 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sysctl.h,v 1.151 2014/11/19 18:04:54 tedu Exp $ */
+/* $OpenBSD: sysctl.h,v 1.152 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */
/*
@@ -180,7 +180,8 @@ struct ctlname {
#define KERN_POOL_DEBUG 77 /* int: enable pool_debug */
#define KERN_PROC_CWD 78 /* node: proc cwd */
#define KERN_PROC_NOBROADCASTKILL 79 /* node: proc no broadcast kill */
-#define KERN_MAXID 80 /* number of valid kern ids */
+#define KERN_PROC_VMMAP 80 /* node: proc vmmap */
+#define KERN_MAXID 81 /* number of valid kern ids */
#define CTL_KERN_NAMES { \
{ 0, 0 }, \
@@ -263,6 +264,7 @@ struct ctlname {
{ "pool_debug", CTLTYPE_INT }, \
{ "proc_cwd", CTLTYPE_NODE }, \
{ "proc_nobroadcastkill", CTLTYPE_NODE }, \
+ { "proc_vmmap", CTLTYPE_NODE }, \
}
/*
@@ -437,6 +439,50 @@ struct kinfo_proc {
u_int32_t p_rtableid; /* U_INT: Routing table identifier. */
};
+/*
+ * VM address range entry, matching struct vm_map_entry. Useful for
+ * debuggers to know process's addresses.
+ *
+ * To iterate entries, set the last kve_end as the base address into
+ * kve_start.
+ */
+struct kinfo_vmentry {
+ u_long kve_start; /* vaddr_t */
+ u_long kve_end; /* vaddr_t */
+ u_long kve_guard; /* vsize_t */
+ u_long kve_fspace; /* vsize_t */
+ u_long kve_fspace_augment; /* vsize_t */
+ u_int64_t kve_offset; /* voff_t */
+ int kve_wired_count;
+ int kve_etype;
+ int kve_protection;
+ int kve_max_protection;
+ int kve_advice;
+ int kve_inheritance;
+ u_int8_t kve_flags; /* u_int8_t */
+};
+
+#define KVE_ET_OBJ 0x00000001
+#define KVE_ET_SUBMAP 0x00000002
+#define KVE_ET_COPYONWRITE 0x00000004
+#define KVE_ET_NEEDSCOPY 0x00000008
+#define KVE_ET_HOLE 0x00000010
+#define KVE_ET_NOFAULT 0x00000020
+#define KVE_ET_FREEMAPPED 0x00000080
+#define KVE_PROT_NONE 0x00000000
+#define KVE_PROT_READ 0x00000001
+#define KVE_PROT_WRITE 0x00000002
+#define KVE_PROT_EXEC 0x00000004
+#define KVE_ADV_NORMAL 0x00000000
+#define KVE_ADV_RANDOM 0x00000001
+#define KVE_ADV_SEQUENTIAL 0x00000002
+#define KVE_INH_SHARE 0x00000000
+#define KVE_INH_COPY 0x00000010
+#define KVE_INH_NONE 0x00000020
+#define KVE_INH_ZERO 0x00000030
+#define KVE_F_STATIC 0x01
+#define KVE_F_KMEM 0x02
+
#if defined(_KERNEL) || defined(_LIBKVM)
/*
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index 3727296d325..8656b4cdad4 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.124 2014/11/21 06:40:40 deraadt Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.125 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -477,6 +477,11 @@ void kmeminit_nkmempages(void);
void kmeminit(void);
extern u_int nkmempages;
+struct process;
+struct kinfo_vmentry;
+int fill_vmmap(struct process *, struct kinfo_vmentry *,
+ size_t *);
+
#endif /* _KERNEL */
#endif /* _UVM_UVM_EXTERN_H_ */
diff --git a/sys/uvm/uvm_glue.c b/sys/uvm/uvm_glue.c
index 703cdd82b9e..7a9618aa496 100644
--- a/sys/uvm/uvm_glue.c
+++ b/sys/uvm/uvm_glue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_glue.c,v 1.67 2014/11/16 12:31:00 deraadt Exp $ */
+/* $OpenBSD: uvm_glue.c,v 1.68 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */
/*
@@ -472,3 +472,18 @@ uvm_pause(void)
if (curcpu()->ci_schedstate.spc_schedflags & SPCF_SHOULDYIELD)
preempt(NULL);
}
+
+#ifndef SMALL_KERNEL
+int
+fill_vmmap(struct process *pr, struct kinfo_vmentry *kve,
+ size_t *lenp)
+{
+ struct vm_map *map;
+
+ if (pr != NULL)
+ map = &pr->ps_vmspace->vm_map;
+ else
+ map = kernel_map;
+ return uvm_map_fill_vmmap(map, kve, lenp);
+}
+#endif
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index f715d8463c6..fe2ee760d5c 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.c,v 1.180 2014/11/30 19:50:53 deraadt Exp $ */
+/* $OpenBSD: uvm_map.c,v 1.181 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
/*
@@ -91,6 +91,7 @@
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/kernel.h>
+#include <sys/sysctl.h>
#ifdef SYSVSHM
#include <sys/shm.h>
@@ -4880,6 +4881,61 @@ vm_map_unbusy_ln(struct vm_map *map, char *file, int line)
wakeup(&map->flags);
}
+#ifndef SMALL_KERNEL
+int
+uvm_map_fill_vmmap(struct vm_map *map, struct kinfo_vmentry *kve,
+ size_t *lenp)
+{
+ struct vm_map_entry *entry;
+ vaddr_t start;
+ int cnt, maxcnt, error = 0;
+
+ KASSERT(*lenp > 0);
+ KASSERT((*lenp % sizeof(*kve)) == 0);
+ cnt = 0;
+ maxcnt = *lenp / sizeof(*kve);
+ KASSERT(maxcnt > 0);
+
+ /*
+ * Return only entries whose address is above the given base
+ * address. This allows userland to iterate without knowing the
+ * number of entries beforehand.
+ */
+ start = (vaddr_t)kve[0].kve_start;
+
+ vm_map_lock(map);
+ RB_FOREACH(entry, uvm_map_addr, &map->addr) {
+ if (cnt == maxcnt) {
+ error = ENOMEM;
+ break;
+ }
+ if (start != 0 && entry->start < start)
+ continue;
+ kve->kve_start = entry->start;
+ kve->kve_end = entry->end;
+ kve->kve_guard = entry->guard;
+ kve->kve_fspace = entry->fspace;
+ kve->kve_fspace_augment = entry->fspace_augment;
+ kve->kve_offset = entry->offset;
+ kve->kve_wired_count = entry->wired_count;
+ kve->kve_etype = entry->etype;
+ kve->kve_protection = entry->protection;
+ kve->kve_max_protection = entry->max_protection;
+ kve->kve_advice = entry->advice;
+ kve->kve_inheritance = entry->inheritance;
+ kve->kve_flags = entry->flags;
+ kve++;
+ cnt++;
+ }
+ vm_map_unlock(map);
+
+ KASSERT(cnt <= maxcnt);
+
+ *lenp = sizeof(*kve) * cnt;
+ return error;
+}
+#endif
+
#undef RB_AUGMENT
#define RB_AUGMENT(x) uvm_map_addr_augment((x))
diff --git a/sys/uvm/uvm_map.h b/sys/uvm/uvm_map.h
index c69c5f9e6d3..70c23e8c56b 100644
--- a/sys/uvm/uvm_map.h
+++ b/sys/uvm/uvm_map.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_map.h,v 1.51 2014/07/11 16:35:40 jsg Exp $ */
+/* $OpenBSD: uvm_map.h,v 1.52 2014/12/05 04:12:48 uebayasi Exp $ */
/* $NetBSD: uvm_map.h,v 1.24 2001/02/18 21:19:08 chs Exp $ */
/*
@@ -400,6 +400,11 @@ void uvm_unmap_detach(struct uvm_map_deadq*, int);
void uvm_unmap_remove(struct vm_map*, vaddr_t, vaddr_t,
struct uvm_map_deadq*, boolean_t, boolean_t);
+struct kinfo_vmentry;
+
+int uvm_map_fill_vmmap(struct vm_map *, struct kinfo_vmentry *,
+ size_t *);
+
#endif /* _KERNEL */
/*