diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h
--- a/lib/libprocstat/core.h
+++ b/lib/libprocstat/core.h
@@ -31,7 +31,7 @@
 #define _CORE_H
 
 enum psc_type {
-	PSC_TYPE_PROC,
+	PSC_TYPE_PROC = 0,
 	PSC_TYPE_FILES,
 	PSC_TYPE_VMMAP,
 	PSC_TYPE_GROUPS,
@@ -43,6 +43,7 @@
 	PSC_TYPE_ENVV,
 	PSC_TYPE_AUXV,
 	PSC_TYPE_PTLWPINFO,
+	PSC_TYPE_KQUEUES,
 	PSC_TYPE_MAX
 };
 
diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c
--- a/lib/libprocstat/core.c
+++ b/lib/libprocstat/core.c
@@ -57,22 +57,62 @@
 	GElf_Phdr	pc_phdr;
 };
 
-static struct psc_type_info {
+static const struct psc_type_info {
 	unsigned int	n_type;
 	int		structsize;
 } psc_type_info[PSC_TYPE_MAX] = {
-	{ .n_type  = NT_PROCSTAT_PROC, .structsize = sizeof(struct kinfo_proc) },
-	{ .n_type = NT_PROCSTAT_FILES, .structsize = sizeof(struct kinfo_file) },
-	{ .n_type = NT_PROCSTAT_VMMAP, .structsize = sizeof(struct kinfo_vmentry) },
-	{ .n_type = NT_PROCSTAT_GROUPS, .structsize = sizeof(gid_t) },
-	{ .n_type = NT_PROCSTAT_UMASK, .structsize = sizeof(u_short) },
-	{ .n_type = NT_PROCSTAT_RLIMIT, .structsize = sizeof(struct rlimit) * RLIM_NLIMITS },
-	{ .n_type = NT_PROCSTAT_OSREL, .structsize = sizeof(int) },
-	{ .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
-	{ .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
-	{ .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
-	{ .n_type = NT_PROCSTAT_AUXV, .structsize = sizeof(Elf_Auxinfo) },
-	{ .n_type = NT_PTLWPINFO, .structsize = sizeof(struct ptrace_lwpinfo) },
+	[PSC_TYPE_PROC] = {
+		.n_type  = NT_PROCSTAT_PROC,
+		.structsize = sizeof(struct kinfo_proc)
+	},
+	[PSC_TYPE_FILES] = {
+		.n_type = NT_PROCSTAT_FILES,
+		.structsize = sizeof(struct kinfo_file)
+	},
+	[PSC_TYPE_VMMAP] = {
+		.n_type = NT_PROCSTAT_VMMAP,
+		.structsize = sizeof(struct kinfo_vmentry)
+	},
+	[PSC_TYPE_GROUPS] = {
+		.n_type = NT_PROCSTAT_GROUPS,
+		.structsize = sizeof(gid_t)
+	},
+	[PSC_TYPE_UMASK] = {
+		.n_type = NT_PROCSTAT_UMASK,
+		.structsize = sizeof(u_short)
+	},
+	[PSC_TYPE_RLIMIT] = {
+		.n_type = NT_PROCSTAT_RLIMIT,
+		.structsize = sizeof(struct rlimit) * RLIM_NLIMITS
+	},
+	[PSC_TYPE_OSREL] = {
+		.n_type = NT_PROCSTAT_OSREL,
+		.structsize = sizeof(int)
+	},
+	[PSC_TYPE_PSSTRINGS] = {
+		.n_type = NT_PROCSTAT_PSSTRINGS,
+		.structsize = sizeof(vm_offset_t)
+	},
+	[PSC_TYPE_ARGV] = {
+		.n_type = NT_PROCSTAT_PSSTRINGS,
+		.structsize = sizeof(vm_offset_t)
+	},
+	[PSC_TYPE_ENVV] = {
+		.n_type = NT_PROCSTAT_PSSTRINGS,
+		.structsize = sizeof(vm_offset_t)
+	},
+	[PSC_TYPE_AUXV] = {
+		.n_type = NT_PROCSTAT_AUXV,
+		.structsize = sizeof(Elf_Auxinfo)
+	},
+	[PSC_TYPE_PTLWPINFO] = {
+		.n_type = NT_PTLWPINFO,
+		.structsize = sizeof(struct ptrace_lwpinfo)
+	},
+	[PSC_TYPE_KQUEUES] = {
+		.n_type = NT_PROCSTAT_KQUEUES,
+		.structsize = sizeof(struct kinfo_knote)
+	},
 };
 
 static bool	core_offset(struct procstat_core *core, off_t offset);
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -2862,6 +2862,9 @@
 procstat_get_kqueue_info(struct procstat *procstat,
     struct kinfo_proc *kp, int kqfd, unsigned int *count, char *errbuf)
 {
+	struct kinfo_knote *kn, *k, *res, *rn;
+	size_t len, kqn;
+
 	switch (procstat->type) {
 	case PROCSTAT_KVM:
 		warnx("kvm method is not supported");
@@ -2870,8 +2873,34 @@
 		return (procstat_get_kqueue_info_sysctl(kp->ki_pid, kqfd,
 		    count, errbuf));
 	case PROCSTAT_CORE:
-		warnx("core method is not supported");
-		return (NULL);
+		k = procstat_core_get(procstat->core, PSC_TYPE_KQUEUES,
+		    NULL, &len);
+		if (k == NULL) {
+			snprintf(errbuf, _POSIX2_LINE_MAX,
+			    "getting NT_PROCSTAT_KQUEUES note failed");
+			*count = 0;
+			return (NULL);
+		}
+		for (kqn = 0, kn = k; kn < k + len / sizeof(*kn); kn++) {
+			if (kn->knt_kq_fd == kqfd)
+				kqn++;
+		}
+		res = calloc(kqn, sizeof(*res));
+		if (res == NULL) {
+			free(k);
+			snprintf(errbuf, _POSIX2_LINE_MAX,
+			    "no memory");
+			return (NULL);
+		}
+		for (kn = k, rn = res; kn < k + len / sizeof(*kn); kn++) {
+			if (kn->knt_kq_fd != kqfd)
+				continue;
+			*rn = *kn;
+			rn++;
+		}
+		*count = kqn;
+		free(k);
+		return (res);
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -446,6 +446,25 @@
 	uint32_t	kvm_spare[12];
 };
 
+struct kinfo_knote32 {
+	int		knt_kq_fd;
+	struct kevent32	knt_event;
+	int		knt_status;
+	int		knt_extdata;
+	uint32_t	knt_spare0[8];
+	union {
+		struct {
+			int		knt_vnode_type;
+			uint32_t	knt_vnode_fsid[2];
+			uint32_t	knt_vnode_fileid[2];
+			char		knt_vnode_fullpath[PATH_MAX];
+		} knt_vnode;
+		struct {
+			uint32_t	knt_pipe_ino[2];
+		} knt_pipe;
+	};
+};
+
 struct kld_file_stat_1_32 {
 	int	version;	/* set to sizeof(struct kld_file_stat_1) */
 	char	name[MAXPATHLEN];
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -679,6 +679,86 @@
 	return (error);
 }
 
+static void
+freebsd32_kevent_to_kevent32(const struct kevent *kevp, struct kevent32 *ks32)
+{
+	uint64_t e;
+	int j;
+
+	CP(*kevp, *ks32, ident);
+	CP(*kevp, *ks32, filter);
+	CP(*kevp, *ks32, flags);
+	CP(*kevp, *ks32, fflags);
+#if BYTE_ORDER == LITTLE_ENDIAN
+	ks32->data1 = kevp->data;
+	ks32->data2 = kevp->data >> 32;
+#else
+	ks32->data1 = kevp->data >> 32;
+	ks32->data2 = kevp->data;
+#endif
+	PTROUT_CP(*kevp, *ks32, udata);
+	for (j = 0; j < nitems(kevp->ext); j++) {
+		e = kevp->ext[j];
+#if BYTE_ORDER == LITTLE_ENDIAN
+		ks32->ext64[2 * j] = e;
+		ks32->ext64[2 * j + 1] = e >> 32;
+#else
+		ks32->ext64[2 * j] = e >> 32;
+		ks32->ext64[2 * j + 1] = e;
+#endif
+	}
+}
+
+void
+freebsd32_kinfo_knote_to_32(const struct kinfo_knote *kin,
+    struct kinfo_knote32 *kin32)
+{
+	memset(kin32, 0, sizeof(*kin32));
+	CP(*kin, *kin32, knt_kq_fd);
+	freebsd32_kevent_to_kevent32(&kin->knt_event, &kin32->knt_event);
+	CP(*kin, *kin32, knt_status);
+	CP(*kin, *kin32, knt_extdata);
+	switch (kin->knt_extdata) {
+	case KNOTE_EXTDATA_NONE:
+		break;
+	case KNOTE_EXTDATA_VNODE:
+		CP(*kin, *kin32, knt_vnode.knt_vnode_type);
+#if BYTE_ORDER == LITTLE_ENDIAN
+		kin32->knt_vnode.knt_vnode_fsid[0] = kin->knt_vnode.
+		    knt_vnode_fsid;
+		kin32->knt_vnode.knt_vnode_fsid[1] = kin->knt_vnode.
+		    knt_vnode_fsid >> 32;
+		kin32->knt_vnode.knt_vnode_fileid[0] = kin->knt_vnode.
+		    knt_vnode_fileid;
+		kin32->knt_vnode.knt_vnode_fileid[1] = kin->knt_vnode.
+		    knt_vnode_fileid >> 32;
+#else
+		kin32->knt_vnode.knt_vnode_fsid[1] = kin->knt_vnode.
+		    knt_vnode_fsid;
+		kin32->knt_vnode.knt_vnode_fsid[0] = kin->knt_vnode.
+		    knt_vnode_fsid >> 32;
+		kin32->knt_vnode.knt_vnode_fileid[1] = kin->knt_vnode.
+		    knt_vnode_fileid;
+		kin32->knt_vnode.knt_vnode_fileid[0] = kin->knt_vnode.
+		    knt_vnode_fileid >> 32;
+#endif
+		memcpy(kin32->knt_vnode.knt_vnode_fullpath,
+		    kin->knt_vnode.knt_vnode_fullpath, PATH_MAX);
+		break;
+	case KNOTE_EXTDATA_PIPE:
+#if BYTE_ORDER == LITTLE_ENDIAN
+		kin32->knt_pipe.knt_pipe_ino[0] = kin->knt_pipe.knt_pipe_ino;
+		kin32->knt_pipe.knt_pipe_ino[1] = kin->knt_pipe.
+		    knt_pipe_ino >> 32;
+#else
+		kin32->knt_pipe.knt_pipe_ino[1] = kin->knt_pipe.knt_pipe_ino;
+		kin32->knt_pipe.knt_pipe_ino[0] = kin->knt_pipe.
+		    knt_pipe_ino >> 32;
+#endif
+		break;
+	}
+}
+
 /*
  * Copy 'count' items into the destination list pointed to by uap->eventlist.
  */
@@ -687,36 +767,13 @@
 {
 	struct freebsd32_kevent_args *uap;
 	struct kevent32	ks32[KQ_NEVENTS];
-	uint64_t e;
-	int i, j, error;
+	int i, error;
 
 	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
 	uap = (struct freebsd32_kevent_args *)arg;
 
-	for (i = 0; i < count; i++) {
-		CP(kevp[i], ks32[i], ident);
-		CP(kevp[i], ks32[i], filter);
-		CP(kevp[i], ks32[i], flags);
-		CP(kevp[i], ks32[i], fflags);
-#if BYTE_ORDER == LITTLE_ENDIAN
-		ks32[i].data1 = kevp[i].data;
-		ks32[i].data2 = kevp[i].data >> 32;
-#else
-		ks32[i].data1 = kevp[i].data >> 32;
-		ks32[i].data2 = kevp[i].data;
-#endif
-		PTROUT_CP(kevp[i], ks32[i], udata);
-		for (j = 0; j < nitems(kevp->ext); j++) {
-			e = kevp[i].ext[j];
-#if BYTE_ORDER == LITTLE_ENDIAN
-			ks32[i].ext64[2 * j] = e;
-			ks32[i].ext64[2 * j + 1] = e >> 32;
-#else
-			ks32[i].ext64[2 * j] = e >> 32;
-			ks32[i].ext64[2 * j + 1] = e;
-#endif
-		}
-	}
+	for (i = 0; i < count; i++)
+		freebsd32_kevent_to_kevent32(&kevp[i], &ks32[i]);
 	error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
 	if (error == 0)
 		uap->eventlist += count;
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
--- a/sys/compat/freebsd32/freebsd32_util.h
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -122,6 +122,11 @@
 int freebsd32_exec_copyin_args(struct image_args *args, const char *fname,
 	    enum uio_seg segflg, uint32_t *argv, uint32_t *envv);
 
+struct kinfo_knote;
+struct kinfo_knote32;
+void	freebsd32_kinfo_knote_to_32(const struct kinfo_knote *kin,
+	    struct kinfo_knote32 *kin32);
+
 extern int compat_freebsd_32bit;
 
 #endif /* !_COMPAT_FREEBSD32_FREEBSD32_UTIL_H_ */
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1574,6 +1574,7 @@
 static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *);
 static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *);
 static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *);
+static void __elfN(note_procstat_kqueues)(void *, struct sbuf *, size_t *);
 static void note_procstat_files(void *, struct sbuf *, size_t *);
 static void note_procstat_groups(void *, struct sbuf *, size_t *);
 static void note_procstat_osrel(void *, struct sbuf *, size_t *);
@@ -1899,6 +1900,8 @@
 	    __elfN(note_procstat_psstrings), p);
 	size += __elfN(register_note)(td, list, NT_PROCSTAT_AUXV,
 	    __elfN(note_procstat_auxv), p);
+	size += __elfN(register_note)(td, list, NT_PROCSTAT_KQUEUES,
+	    __elfN(note_procstat_kqueues), p);
 
 	*sizep = size;
 }
@@ -2719,6 +2722,54 @@
 	}
 }
 
+static void
+__elfN(note_procstat_kqueues)(void *arg, struct sbuf *sb, size_t *sizep)
+{
+	struct proc *p;
+	size_t size, sect_sz, i;
+	ssize_t start_len, sect_len;
+	int structsize;
+	bool compat32;
+
+#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32
+	compat32 = true;
+	structsize = sizeof(struct kinfo_knote32);
+#else
+	compat32 = false;
+	structsize = sizeof(struct kinfo_knote);
+#endif
+	p = arg;
+	if (sb == NULL) {
+		size = 0;
+		sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN);
+		sbuf_set_drain(sb, sbuf_count_drain, &size);
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		kern_proc_kqueues_out(p, sb, -1, compat32);
+		sbuf_finish(sb);
+		sbuf_delete(sb);
+		*sizep = size;
+	} else {
+		sbuf_start_section(sb, &start_len);
+
+		sbuf_bcat(sb, &structsize, sizeof(structsize));
+		kern_proc_kqueues_out(p, sb, *sizep - sizeof(structsize),
+		    compat32);
+
+		sect_len = sbuf_end_section(sb, start_len, 0, 0);
+		if (sect_len < 0)
+			return;
+		sect_sz = sect_len;
+
+		KASSERT(sect_sz <= *sizep,
+		    ("kern_proc_kqueue_out did not respect maxlen; "
+		     "requested %zu, got %zu", *sizep - sizeof(structsize),
+		     sect_sz - sizeof(structsize)));
+
+		for (i = 0; i < *sizep - sect_sz && sb->s_error == 0; i++)
+			sbuf_putc(sb, 0);
+	}
+}
+
 #define	MAX_NOTES_LOOP	4096
 bool
 __elfN(parse_notes)(const struct image_params *imgp, const Elf_Note *checknote,
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -34,14 +34,11 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #include "opt_capsicum.h"
 #include "opt_ddb.h"
 #include "opt_ktrace.h"
 
-#include <sys/param.h>
 #include <sys/systm.h>
-
 #include <sys/capsicum.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
@@ -2996,6 +2993,47 @@
 	return (error);
 }
 
+int
+fget_remote_foreach(struct thread *td, struct proc *p,
+    int (*fn)(struct proc *, int, struct file *, void *), void *arg)
+{
+	struct filedesc *fdp;
+	struct fdescenttbl *fdt;
+	struct file *fp;
+	int error, error1, fd, highfd;
+
+	error = 0;
+	PROC_LOCK(p);
+	fdp = fdhold(p);
+	PROC_UNLOCK(p);
+	if (fdp == NULL)
+		return (ENOENT);
+
+	FILEDESC_SLOCK(fdp);
+	if (refcount_load(&fdp->fd_refcnt) != 0) {
+		fdt = atomic_load_ptr(&fdp->fd_files);
+		highfd = fdt->fdt_nfiles - 1;
+		FILEDESC_SUNLOCK(fdp);
+	} else {
+		error = ENOENT;
+		FILEDESC_SUNLOCK(fdp);
+		goto out;
+	}
+
+	for (fd = 0; fd <= highfd; fd++) {
+		error1 = fget_remote(td, p, fd, &fp);
+		if (error1 != 0)
+			continue;
+		error = fn(p, fd, fp, arg);
+		fdrop(fp, td);
+		if (error != 0)
+			break;
+	}
+out:
+	fddrop(fdp);
+	return (error);
+}
+
 #ifdef CAPABILITIES
 int
 fgetvp_lookup_smr(struct nameidata *ndp, struct vnode **vpp, bool *fsearch)
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -58,6 +58,7 @@
 #include <sys/poll.h>
 #include <sys/protosw.h>
 #include <sys/resourcevar.h>
+#include <sys/sbuf.h>
 #include <sys/sigio.h>
 #include <sys/signalvar.h>
 #include <sys/socket.h>
@@ -74,6 +75,10 @@
 #include <sys/ktrace.h>
 #endif
 #include <machine/atomic.h>
+#ifdef COMPAT_FREEBSD32
+#include <compat/freebsd32/freebsd32.h>
+#include <compat/freebsd32/freebsd32_util.h>
+#endif
 
 #include <vm/uma.h>
 
@@ -2871,94 +2876,181 @@
 }
 
 static int
-sysctl_kern_proc_kqueue_report_one(struct proc *p, struct sysctl_req *req,
-    struct kqueue *kq, struct knote *kn)
+kern_proc_kqueue_report_one(struct sbuf *s, struct proc *p,
+    int kq_fd, struct kqueue *kq, struct knote *kn, bool compat32 __unused)
 {
 	struct kinfo_knote kin;
+#ifdef COMPAT_FREEBSD32
+	struct kinfo_knote32 kin32;
+#endif
 	int error;
 
 	if (kn->kn_status == KN_MARKER)
 		return (0);
 
 	memset(&kin, 0, sizeof(kin));
+	kin.knt_kq_fd = kq_fd;
 	memcpy(&kin.knt_event, &kn->kn_kevent, sizeof(struct kevent));
 	kin.knt_status = knote_status_export(kn->kn_status);
 	kn_enter_flux(kn);
 	KQ_UNLOCK_FLUX(kq);
 	if (kn->kn_fop->f_userdump != NULL)
 		(void)kn->kn_fop->f_userdump(p, kn, &kin);
-	error = SYSCTL_OUT(req, &kin, sizeof(kin));
-	maybe_yield();
+#ifdef COMPAT_FREEBSD32
+	if (compat32) {
+		freebsd32_kinfo_knote_to_32(&kin, &kin32);
+		error = sbuf_bcat(s, &kin32, sizeof(kin32));
+	} else
+#endif
+		error = sbuf_bcat(s, &kin, sizeof(kin));
 	KQ_LOCK(kq);
 	kn_leave_flux(kn);
 	return (error);
 }
 
+static int
+kern_proc_kqueue_report(struct sbuf *s, struct proc *p, int kq_fd,
+    struct kqueue *kq, bool compat32)
+{
+	struct knote *kn;
+	int error, i;
+
+	error = 0;
+	KQ_LOCK(kq);
+	for (i = 0; i < kq->kq_knlistsize; i++) {
+		SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) {
+			error = kern_proc_kqueue_report_one(s, p, kq_fd,
+			    kq, kn, compat32);
+			if (error != 0)
+				goto out;
+		}
+	}
+	if (kq->kq_knhashmask == 0)
+		goto out;
+	for (i = 0; i <= kq->kq_knhashmask; i++) {
+		SLIST_FOREACH(kn, &kq->kq_knhash[i], kn_link) {
+			error = kern_proc_kqueue_report_one(s, p, kq_fd,
+			    kq, kn, compat32);
+			if (error != 0)
+				goto out;
+		}
+	}
+out:
+	KQ_UNLOCK_FLUX(kq);
+	return (error);
+}
+
+struct kern_proc_kqueues_out1_cb_args {
+	struct sbuf *s;
+	bool compat32;
+};
+
+static int
+kern_proc_kqueues_out1_cb(struct proc *p, int fd, struct file *fp, void *arg)
+{
+	struct kqueue *kq;
+	struct kern_proc_kqueues_out1_cb_args *a;
+
+	if (fp->f_type != DTYPE_KQUEUE)
+		return (0);
+	a = arg;
+	kq = fp->f_data;
+	return (kern_proc_kqueue_report(a->s, p, fd, kq, a->compat32));
+}
+
+static int
+kern_proc_kqueues_out1(struct thread *td, struct proc *p, struct sbuf *s,
+    bool compat32)
+{
+	struct kern_proc_kqueues_out1_cb_args a;
+
+	a.s = s;
+	a.compat32 = compat32;
+	return (fget_remote_foreach(td, p, kern_proc_kqueues_out1_cb, &a));
+}
+
+int
+kern_proc_kqueues_out(struct proc *p, struct sbuf *sb, size_t maxlen,
+    bool compat32)
+{
+	struct sbuf *s, sm;
+	int error;
+
+	s = sbuf_new(&sm, NULL, maxlen, SBUF_FIXEDLEN);
+	error = kern_proc_kqueues_out1(curthread, p, s, compat32);
+	sbuf_finish(s);
+	if (error == 0)
+		sbuf_bcat(sb, sbuf_data(s), MIN(sbuf_len(s), maxlen));
+	sbuf_delete(s);
+	return (error);
+}
+
+static int
+sysctl_kern_proc_kqueue_one(struct thread *td, struct sbuf *s, struct proc *p,
+    int kq_fd, bool compat32)
+{
+	struct file *fp;
+	struct kqueue *kq;
+	int error;
+
+	error = fget_remote(td, p, kq_fd, &fp);
+	if (error == 0) {
+		if (fp->f_type != DTYPE_KQUEUE) {
+			error = EINVAL;
+		} else {
+			kq = fp->f_data;
+			error = kern_proc_kqueue_report(s, p, kq_fd, kq,
+			    compat32);
+		}
+		fdrop(fp, td);
+	}
+	return (error);
+}
+
 static int
 sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS)
 {
 	struct thread *td;
 	struct proc *p;
-	struct file *fp;
-	struct kqueue *kq;
-	struct knote *kn;
-	int error, i, *name;
+	struct sbuf *s, sm;
+	int error, error1, *name;
+	bool compat32;
 
 	name = (int *)arg1;
-	if ((u_int)arg2 != 2)
+	if ((u_int)arg2 > 2 || (u_int)arg2 == 0)
 		return (EINVAL);
 
 	error = pget((pid_t)name[0], PGET_HOLD | PGET_CANDEBUG, &p);
 	if (error != 0)
 		return (error);
-#ifdef COMPAT_FREEBSD32
-	if (SV_CURPROC_FLAG(SV_ILP32)) {
-		/* XXXKIB */
-		error = EOPNOTSUPP;
-		goto out1;
-	}
-#endif
 
 	td = curthread;
-	error = fget_remote(td, p, name[1] /* kqfd */, &fp);
-	if (error != 0)
-		goto out1;
-	if (fp->f_type != DTYPE_KQUEUE) {
-		error = EINVAL;
-		goto out2;
+#ifdef FREEBSD_COMPAT32
+	compat32 = SV_CURPROC_FLAG(SV_ILP32);
+#else
+	compat32 = false;
+#endif
+
+	s = sbuf_new_for_sysctl(&sm, NULL, 0, req);
+	if (s == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+	sbuf_clear_flags(s, SBUF_INCLUDENUL);
+
+	if ((u_int)arg2 == 1) {
+		error = kern_proc_kqueues_out1(td, p, s, compat32);
+	} else {
+		error = sysctl_kern_proc_kqueue_one(td, s, p,
+		    name[1] /* kq_fd */, compat32);
 	}
 
-	kq = fp->f_data;
-	if (req->oldptr == NULL) {
-		error = SYSCTL_OUT(req, NULL, sizeof(struct kinfo_knote) *
-		    kq->kq_knlistsize * 11 / 10);
-		goto out2;
-	}
+	error1 = sbuf_finish(s);
+	if (error == 0)
+		error = error1;
+	sbuf_delete(s);
 
-	KQ_LOCK(kq);
-	for (i = 0; i < kq->kq_knlistsize; i++) {
-		SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) {
-			error = sysctl_kern_proc_kqueue_report_one(p, req,
-			    kq, kn);
-			if (error != 0)
-				goto out3;
-		}
-	}
-	if (kq->kq_knhashmask == 0)
-		goto out3;
-	for (i = 0; i <= kq->kq_knhashmask; i++) {
-		SLIST_FOREACH(kn, &kq->kq_knhash[i], kn_link) {
-			error = sysctl_kern_proc_kqueue_report_one(p, req,
-			    kq, kn);
-			if (error != 0)
-				goto out3;
-		}
-	}
-out3:
-	KQ_UNLOCK_FLUX(kq);
-out2:
-	fdrop(fp, td);
-out1:
+out:
 	PRELE(p);
 	return (error);
 }
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -840,6 +840,7 @@
 #define	NT_PROCSTAT_PSSTRINGS	15	/* Procstat ps_strings data. */
 #define	NT_PROCSTAT_AUXV	16	/* Procstat auxv data. */
 #define	NT_PTLWPINFO		17	/* Thread ptrace miscellaneous info. */
+#define	NT_PROCSTAT_KQUEUES	18	/* Procstat kqueues events. */
 #define	NT_PPC_VMX	0x100	/* PowerPC Altivec/VMX registers */
 #define	NT_PPC_VSX	0x102	/* PowerPC VSX registers */
 #define	NT_X86_SEGBASES	0x200	/* x86 FS/GS base addresses. */
diff --git a/sys/sys/file.h b/sys/sys/file.h
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -267,6 +267,8 @@
     int needfcntl, struct file **fpp);
 int _fdrop(struct file *fp, struct thread *td);
 int fget_remote(struct thread *td, struct proc *p, int fd, struct file **fpp);
+int fget_remote_foreach(struct thread *td, struct proc *p,
+    int (*fn)(struct proc *, int, struct file *, void *), void *arg);
 
 fo_rdwr_t	invfo_rdwr;
 fo_truncate_t	invfo_truncate;
diff --git a/sys/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -677,9 +677,11 @@
 #define	KNOTE_EXTDATA_PIPE		2
 
 struct kinfo_knote {
+	int		knt_kq_fd;
 	struct kevent	knt_event;
 	int		knt_status;
 	int		knt_extdata;
+	uint64_t	knt_spare0[4];
 	union {
 		struct {
 			int		knt_vnode_type;
@@ -720,6 +722,8 @@
 int	kern_proc_out(struct proc *p, struct sbuf *sb, int flags);
 int	kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen,
 	int flags);
+int	kern_proc_kqueues_out(struct proc *p, struct sbuf *s, size_t maxlen,
+	bool compat32);
 
 int	vntype_to_kinfo(int vtype);
 void	pack_kinfo(struct kinfo_file *kif);
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
--- a/usr.bin/gcore/elfcore.c
+++ b/usr.bin/gcore/elfcore.c
@@ -105,6 +105,7 @@
 static void *elf_note_procstat_auxv(void *, size_t *);
 static void *elf_note_procstat_files(void *, size_t *);
 static void *elf_note_procstat_groups(void *, size_t *);
+static void *elf_note_procstat_kqueues(void *, size_t *);
 static void *elf_note_procstat_osrel(void *, size_t *);
 static void *elf_note_procstat_proc(void *, size_t *);
 static void *elf_note_procstat_psstrings(void *, size_t *);
@@ -388,6 +389,7 @@
 	elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid,
 	    sb);
 	elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb);
+	elf_putnote(NT_PROCSTAT_KQUEUES, elf_note_procstat_kqueues, &pid, sb);
 #endif
 
 	size = sbuf_end_section(sb, old_len, 1, 0);
@@ -756,7 +758,7 @@
 {
 	size_t len;
 	pid_t pid;
-	int name[4], structsize;
+	int name[5], structsize;
 	void *buf, *p;
 
 	pid = *(pid_t *)arg;
@@ -841,6 +843,14 @@
 	    sizeof(Elf_Auxinfo), sizep));
 }
 
+static void *
+elf_note_procstat_kqueues(void *arg, size_t *sizep)
+{
+
+	return (procstat_sysctl(arg, KERN_PROC_KQUEUE,
+	    sizeof(struct kinfo_knote), sizep));
+}
+
 static void *
 elf_note_procstat_rlimit(void *arg, size_t *sizep)
 {