[rtems-libbsd commit] Add netstat command

Joel Sherrill joel at rtems.org
Wed Oct 17 16:11:19 UTC 2012


Module:    rtems-libbsd
Branch:    master
Commit:    b6ac989f8a189c24500efa9b54ec466badfd3072
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=b6ac989f8a189c24500efa9b54ec466badfd3072

Author:    Joel Sherrill <joel.sherrill at oarcorp.com>
Date:      Wed Oct 17 11:13:36 2012 -0500

Add netstat command

This adds the netstat command. All but one file is currently enabled.
That file does not currently build.

Also added libmemstat and libutil. libmemstat had a lot of code related
to kvm and kernel memory access disabled. This may or may not be an
issue.

---

 freebsd-userspace/Makefile                         |   18 +-
 freebsd-userspace/commands/usr.bin/netstat/if.c    |    8 +-
 freebsd-userspace/commands/usr.bin/netstat/inet.c  |   21 +
 freebsd-userspace/commands/usr.bin/netstat/main.c  |   39 ++
 freebsd-userspace/commands/usr.bin/netstat/mbuf.c  |    8 +-
 freebsd-userspace/commands/usr.bin/netstat/unix.c  |    6 +
 freebsd-userspace/include/nlist.h                  |   53 ++
 freebsd-userspace/lib/libmemstat/libmemstat.3      |  496 ++++++++++++++++++++
 freebsd-userspace/lib/libmemstat/memstat.c         |  421 +++++++++++++++++
 freebsd-userspace/lib/libmemstat/memstat.h         |  178 +++++++
 freebsd-userspace/lib/libmemstat/memstat_all.c     |   58 +++
 .../lib/libmemstat/memstat_internal.h              |  124 +++++
 freebsd-userspace/lib/libmemstat/memstat_malloc.c  |  417 ++++++++++++++++
 freebsd-userspace/lib/libmemstat/memstat_uma.c     |  478 +++++++++++++++++++
 freebsd-userspace/lib/libutil/expand_number.3      |   86 ++++
 freebsd-userspace/lib/libutil/expand_number.c      |  100 ++++
 freebsd-userspace/lib/libutil/humanize_number.3    |  157 ++++++
 freebsd-userspace/lib/libutil/humanize_number.c    |  146 ++++++
 freebsd-userspace/lib/libutil/libutil.h            |  188 ++++++++
 .../rtems/include/rtems/netcmds-config.h           |    2 +-
 freebsd-userspace/sys/sys/nlist_aout.h             |  113 +++++
 21 files changed, 3105 insertions(+), 12 deletions(-)

diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index 566e742..5cdc7ab 100644
--- a/freebsd-userspace/Makefile
+++ b/freebsd-userspace/Makefile
@@ -9,6 +9,8 @@ CFLAGS += -Irtems/include
 CFLAGS += -Ilib/libc/include 
 CFLAGS += -Ilib/libc/resolv 
 CFLAGS += -Ilib/netgraph
+CFLAGS += -Ilib/libmemstat
+CFLAGS += -Ilib/libutil
 CFLAGS += -Isys
 CFLAGS += -Ilocal 
 # XXX hack to find rpc
@@ -18,6 +20,8 @@ CFLAGS += -Ilib/libc/net
 
 CFLAGS += -I$(INSTALL_BASE)/include
 
+#Only needed for route
+# CFLAGS += -D__BSD_VISIBLE=1
 #Only Needed for db files
 CFLAGS += -D__DBINTERFACE_PRIVATE
 
@@ -128,6 +132,15 @@ C_FILES += lib/libc/db/recno/rec_utils.c
 
 C_FILES += lib/libc/db/mpool/mpool.c
 
+# libmemstat
+C_FILES += lib/libmemstat/memstat_all.c
+C_FILES += lib/libmemstat/memstat.c
+C_FILES += lib/libmemstat/memstat_malloc.c
+C_FILES += lib/libmemstat/memstat_uma.c
+
+# libutil
+C_FILES += lib/libutil/expand_number.c
+C_FILES += lib/libutil/humanize_number.c
 
 # libipsec files
 C_FILES += lib/libipsec/pfkey_dump.c
@@ -206,7 +219,6 @@ C_FILES += commands/sbin/ifconfig/ifpfsync.c
 # C_FILES += commands/sbin/ifconfig/regdomain.c
 # C_FILES += commands/sbin/ifconfig/af_ipx.c
 
-ifeq (1,0)
 # netstat command sources
 # no need to support AppleTalk yet
 # C_FILES += commands/usr.bin/netstat/atalk.c
@@ -218,7 +230,8 @@ C_FILES += commands/usr.bin/netstat/ipsec.c
 # no need to support IPX yet
 # C_FILES += commands/usr.bin/netstat/ipx.c
 C_FILES += commands/usr.bin/netstat/main.c
-C_FILES += commands/usr.bin/netstat/mbuf.c
+# XXX does not compile yet
+# C_FILES += commands/usr.bin/netstat/mbuf.c
 C_FILES += commands/usr.bin/netstat/mroute6.c
 C_FILES += commands/usr.bin/netstat/mroute.c
 # Disable netgraph support - this is a long thread to pull
@@ -227,7 +240,6 @@ C_FILES += commands/usr.bin/netstat/pfkey.c
 C_FILES += commands/usr.bin/netstat/route.c
 C_FILES += commands/usr.bin/netstat/sctp.c
 C_FILES += commands/usr.bin/netstat/unix.c
-endif
 
 C_O_FILES = $(C_FILES:%.c=%.o)
 C_D_FILES = $(C_FILES:%.c=%.d)
diff --git a/freebsd-userspace/commands/usr.bin/netstat/if.c b/freebsd-userspace/commands/usr.bin/netstat/if.c
index d91db8c..b487e10 100644
--- a/freebsd-userspace/commands/usr.bin/netstat/if.c
+++ b/freebsd-userspace/commands/usr.bin/netstat/if.c
@@ -80,11 +80,7 @@ __FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
-#ifdef __rtems__
-/* apparently libutil.h is not needed */
-#else
 #include <libutil.h>
-#endif
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -207,7 +203,9 @@ intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
 #ifdef INET6
 		struct in6_ifaddr in6;
 #endif
+#ifndef __rtems__
 		struct ipx_ifaddr ipx;
+#endif
 	} ifaddr;
 	u_long ifaddraddr;
 	u_long ifaddrfound;
@@ -380,6 +378,7 @@ intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
 				network_layer = 1;
 				break;
 #endif /*INET6*/
+#ifndef __rtems__
 			case AF_IPX:
 				{
 				struct sockaddr_ipx *sipx =
@@ -397,6 +396,7 @@ intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
 
 				network_layer = 1;
 				break;
+#endif
 
 			case AF_APPLETALK:
 				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
diff --git a/freebsd-userspace/commands/usr.bin/netstat/inet.c b/freebsd-userspace/commands/usr.bin/netstat/inet.c
index 37b650c..f6d111f 100644
--- a/freebsd-userspace/commands/usr.bin/netstat/inet.c
+++ b/freebsd-userspace/commands/usr.bin/netstat/inet.c
@@ -66,8 +66,28 @@ __FBSDID("$FreeBSD$");
 #ifdef INET6
 #include <netinet/ip6.h>
 #endif /* INET6 */
+#ifdef __rtems__
+#include <freebsd/netinet/in_pcb.h>
+#else
 #include <netinet/in_pcb.h>
+#endif
 #include <netinet/ip_icmp.h>
+#ifdef __rtems__
+#include <freebsd/netinet/icmp_var.h>
+#include <freebsd/netinet/igmp_var.h>
+#include <freebsd/netinet/ip_var.h>
+#include <freebsd/netinet/pim_var.h>
+#include <netinet/tcp.h>
+#include <freebsd/netinet/tcpip.h>
+#include <freebsd/netinet/tcp_seq.h>
+#define	TCPSTATES
+#include <freebsd/netinet/tcp_fsm.h>
+#include <freebsd/netinet/tcp_timer.h>
+#include <freebsd/netinet/tcp_var.h>
+#include <freebsd/netinet/tcp_debug.h>
+#include <netinet/udp.h>
+#include <freebsd/netinet/udp_var.h>
+#else
 #include <netinet/icmp_var.h>
 #include <netinet/igmp_var.h>
 #include <netinet/ip_var.h>
@@ -82,6 +102,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet/tcp_debug.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
+#endif
 
 #include <arpa/inet.h>
 #include <err.h>
diff --git a/freebsd-userspace/commands/usr.bin/netstat/main.c b/freebsd-userspace/commands/usr.bin/netstat/main.c
index 09b26a2..f191604 100644
--- a/freebsd-userspace/commands/usr.bin/netstat/main.c
+++ b/freebsd-userspace/commands/usr.bin/netstat/main.c
@@ -1,3 +1,7 @@
+#ifdef __rtems__
+#define __need_getopt_newlib
+#include <getopt.h>
+#endif
 /*-
  * Copyright (c) 1983, 1988, 1993
  *	Regents of the University of California.  All rights reserved.
@@ -65,7 +69,9 @@ __FBSDID("$FreeBSD$");
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#ifndef __rtems__
 #include <kvm.h>
+#endif
 #include <limits.h>
 #include <netdb.h>
 #include <nlist.h>
@@ -323,7 +329,9 @@ static void usage(void);
 static struct protox *name2protox(const char *);
 static struct protox *knownname(const char *);
 
+#ifndef __rtems__
 static kvm_t *kvmd;
+#endif
 static char *nlistf = NULL, *memf = NULL;
 
 int	Aflag;		/* show addresses of protocol control block */
@@ -356,14 +364,26 @@ int	af;		/* address family */
 int	live;		/* true if we are examining a live system */
 
 int
+#ifdef __rtems__
+main_netstat(int argc, char *argv[])
+#else
 main(int argc, char *argv[])
+#endif
 {
 	struct protox *tp = NULL;  /* for printing cblocks & stats */
 	int ch;
+#ifdef __rtems__
+	struct getopt_data getopt_reent;
+#endif
 
 	af = AF_UNSPEC;
 
+#ifdef __rtems__
+	memset(&getopt_reent, 0, sizeof(getopt_data));
+	while ((ch = getopt_r(argc, argv, "AaBbdf:ghI:iLlM:mN:np:q:rSstuWw:xz", &getopt_reent)) != -1)
+#else
 	while ((ch = getopt(argc, argv, "AaBbdf:ghI:iLlM:mN:np:q:rSstuWw:xz")) != -1)
+#endif
 		switch(ch) {
 		case 'A':
 			Aflag = 1;
@@ -508,6 +528,7 @@ main(int argc, char *argv[])
 	}
 #endif
 
+#ifndef __rtems__
 	/*
 	 * Discard setgid privileges if not the running kernel so that bad
 	 * guys can't print interesting stuff from kernel memory.
@@ -530,6 +551,7 @@ main(int argc, char *argv[])
 			mbpr(NULL, 0);
 		exit(0);
 	}
+#endif
 #if 0
 	/*
 	 * Keep file descriptors open to avoid overhead
@@ -544,7 +566,9 @@ main(int argc, char *argv[])
 	 * used for the queries, which is slower.
 	 */
 #endif
+#ifndef __rtems__
 	kread(0, NULL, 0);
+#endif
 	if (iflag && !sflag) {
 		intpr(interval, nl[N_IFNET].n_value, NULL);
 		exit(0);
@@ -679,6 +703,7 @@ printproto(tp, name)
 		(*pr)(off, name, af, tp->pr_protocol);
 }
 
+#ifndef __rtems__
 /*
  * Read kernel memory, return 0 on success.
  */
@@ -718,6 +743,7 @@ kread(u_long addr, void *buf, size_t size)
 	}
 	return (0);
 }
+#endif
 
 const char *
 plural(uintmax_t n)
@@ -803,3 +829,16 @@ usage(void)
 "       netstat -gs [-s] [-f address_family] [-M core] [-N system]");
 	exit(1);
 }
+
+#ifdef __rtems__
+  #include <rtems/shell.h>
+
+  rtems_shell_cmd_t rtems_shell_NETSTAT_Command = {
+    "netstat",                     /* name */
+    "netstat [args]",              /* usage */
+    "net",                         /* topic */
+    main_netstat,                  /* command */
+    NULL,                          /* alias */
+    NULL                           /* next */
+  };
+#endif
diff --git a/freebsd-userspace/commands/usr.bin/netstat/mbuf.c b/freebsd-userspace/commands/usr.bin/netstat/mbuf.c
index dd10525..268fd86 100644
--- a/freebsd-userspace/commands/usr.bin/netstat/mbuf.c
+++ b/freebsd-userspace/commands/usr.bin/netstat/mbuf.c
@@ -56,12 +56,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 
 #include <err.h>
-#ifdef __rtems__
-/* XXX what to do? */
-#else
+#ifndef __rtems__
 #include <kvm.h>
-#include <memstat.h>
 #endif
+#include <memstat.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -110,6 +108,7 @@ mbpr(void *kvmd, u_long mbaddr)
 			goto out;
 		}
 	} else {
+#ifndef __rtems__
 		if (memstat_kvm_all(mtlp, kvmd) < 0) {
 			error = memstat_mtl_geterror(mtlp);
 			if (error == MEMSTAT_ERROR_KVM)
@@ -120,6 +119,7 @@ mbpr(void *kvmd, u_long mbaddr)
 				    memstat_strerror(error));
 			goto out;
 		}
+#endif
 	}
 
 	mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME);
diff --git a/freebsd-userspace/commands/usr.bin/netstat/unix.c b/freebsd-userspace/commands/usr.bin/netstat/unix.c
index 17d5203..2e18c9a 100644
--- a/freebsd-userspace/commands/usr.bin/netstat/unix.c
+++ b/freebsd-userspace/commands/usr.bin/netstat/unix.c
@@ -59,7 +59,9 @@ __FBSDID("$FreeBSD$");
 #endif
 #include <sys/sysctl.h>
 #include <sys/un.h>
+#ifndef __rtems__
 #include <sys/unpcb.h>
+#endif
 
 #include <netinet/in.h>
 
@@ -70,7 +72,9 @@ __FBSDID("$FreeBSD$");
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
+#ifndef __rtems__
 #include <kvm.h>
+#endif
 #include "netstat.h"
 
 static	void unixdomainpr(struct xunpcb *, struct xsocket *);
@@ -106,6 +110,7 @@ pcblist_sysctl(int type, char **bufp)
 	return (0);
 }
 
+#ifndef __rtems__
 static int
 pcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp)
 {
@@ -292,3 +297,4 @@ unixdomainpr(struct xunpcb *xunp, struct xsocket *so)
 		    sa->sun_path);
 	putchar('\n');
 }
+#endif
diff --git a/freebsd-userspace/include/nlist.h b/freebsd-userspace/include/nlist.h
new file mode 100644
index 0000000..3dccf9e
--- /dev/null
+++ b/freebsd-userspace/include/nlist.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)nlist.h	8.2 (Berkeley) 1/21/94
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NLIST_H_
+#define	_NLIST_H_
+
+#include <sys/nlist_aout.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int nlist(const char *, struct nlist *);
+__END_DECLS
+
+#endif /* !_NLIST_H_ */
diff --git a/freebsd-userspace/lib/libmemstat/libmemstat.3 b/freebsd-userspace/lib/libmemstat/libmemstat.3
new file mode 100644
index 0000000..9a4877b
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/libmemstat.3
@@ -0,0 +1,496 @@
+.\" Copyright (c) 2005 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 27, 2005
+.Dt LIBMEMSTAT 3
+.Os
+.Sh NAME
+.Nm libmemstat
+.Nd "library interface to retrieve kernel memory allocator statistics"
+.Sh LIBRARY
+.Lb libmemstat
+.Sh SYNOPSIS
+.In sys/types.h
+.In memstat.h
+.Ss General Functions
+.Ft "const char *"
+.Fn memstat_strerror "int error"
+.Ss Memory Type List Management Functions
+.Ft "struct memory_type_list *"
+.Fn memstat_mtl_alloc "void"
+.Ft "struct memory_type *"
+.Fn memstat_mtl_first "struct memory_type_list *list"
+.Ft "struct memory_type *"
+.Fn memstat_mtl_next "struct memory_type *mtp"
+.Ft "struct memory_type *"
+.Fo memstat_mtl_find
+.Fa "struct memory_type_list *list" "int allocator" "const char *name"
+.Fc
+.Ft void
+.Fn memstat_mtl_free "struct memory_type_list *list"
+.Ft int
+.Fn memstat_mtl_geterror "struct memory_type_list *list"
+.Ss Allocator Query Functions
+.Ft int
+.Fn memstat_kvm_all "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_kvm_malloc "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_kvm_uma "struct memory_type_list *list" "void *kvm_handle"
+.Ft int
+.Fn memstat_sysctl_all "struct memory_type_list *list" "int flags"
+.Ft int
+.Fn memstat_sysctl_malloc "struct memory_type_list *list" "int flags"
+.Ft int
+.Fn memstat_sysctl_uma "struct memory_type_list *list" "int flags"
+.Ss Memory Type Accessor Methods
+.Ft "const char *"
+.Fn memstat_get_name "const struct memory_type *mtp"
+.Ft int
+.Fn memstat_get_allocator "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_countlimit "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_byteslimit "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_sizemask "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_size "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_memalloced "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_memfreed "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_numallocs "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_numfrees "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_bytes "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_count "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_free "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_failures "const struct memory_type *mtp"
+.Ft "void *"
+.Fn memstat_get_caller_pointer "const struct memory_type *mtp" "int index"
+.Ft void
+.Fo memstat_set_caller_pointer
+.Fa "struct memory_type *mtp" "int index" "void *value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_caller_uint64 "const struct memory_type *mtp" "int index"
+.Ft void
+.Fo memstat_set_caller_uint64
+.Fa "struct memory_type *mtp" "int index" "uint64_t value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_zonefree "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_kegfree "const struct memory_type *mtp"
+.Ft uint64_t
+.Fn memstat_get_percpu_memalloced "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_memfreed "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_numallocs "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_numfrees "const struct memory_type *mtp" "int cpu"
+.Ft uint64_t
+.Fn memstat_get_percpu_sizemask "const struct memory_type *mtp" "int cpu"
+.Ft "void *"
+.Fo memstat_get_percpu_caller_pointer
+.Fa "const struct memory_type *mtp" "int cpu" "int index"
+.Fc
+.Ft void
+.Fo memstat_set_percpu_caller_pointer
+.Fa "struct memory_type *mtp" "int cpu" "int index" "void *value"
+.Fc
+.Ft uint64_t
+.Fo memstat_get_percpu_caller_uint64
+.Fa "const struct memory_type *mtp" "int cpu" "int index"
+.Fc
+.Ft void
+.Fo memstat_set_percpu_caller_uint64
+.Fa "struct memory_type *mtp" "int cpu" "int index" "uint64_t value"
+.Fc
+.Ft uint64_t
+.Fn memstat_get_percpu_free "const struct memory_type *mtp" "int cpu"
+.Sh DESCRIPTION
+.Nm
+provides an interface to retrieve kernel memory allocator statistics, for
+the purposes of debugging and system monitoring, insulating applications
+from implementation details of the allocators, and allowing a tool to
+transparently support multiple allocators.
+.Nm
+supports both retrieving a single statistics snapshot, as well as
+incrementally updating statistics for long-term monitoring.
+.Pp
+.Nm
+describes each memory type using a
+.Vt "struct memory_type" ,
+an opaque memory type accessed by the application using accessor functions
+in the library.
+.Nm
+returns and updates chains of
+.Vt "struct memory_type"
+via a
+.Vt "struct memory_type_list" ,
+which will be allocated by calling
+.Fn memstat_mtl_alloc ,
+and freed on completion using
+.Fn memstat_mtl_free .
+Lists of memory types are populated via calls that query the kernel for
+statistics information; currently:
+.Fn memstat_kvm_all ,
+.Fn memstat_kvm_malloc ,
+.Fn memstat_kvm_uma ,
+.Fn memstat_sysctl_all ,
+.Fn memstat_sysctl_uma ,
+and
+.Fn memstat_sysctl_malloc .
+Repeated calls will incrementally update the list of memory types, permitting
+tracking over time without recreating all list state.
+If an error is detected during a query call, error condition information may
+be retrieved using
+.Fn memstat_mtl_geterror ,
+and converted to a user-readable string using
+.Fn memstat_strerror .
+.Pp
+Freeing the list will free all memory type data in the list, and so
+invalidates any outstanding pointers to entries in the list.
+.Vt "struct memory_type"
+entries in the list may be iterated over using
+.Fn memstat_mtl_first
+and
+.Fn memstat_mtl_next ,
+which respectively return the first entry in a list, and the next entry in a
+list.
+.Fn memstat_mtl_find ,
+which will return a pointer to the first entry matching the passed
+parameters.
+.Pp
+A series of accessor methods is provided to access fields of the structure,
+including retrieving statistics and properties, as well as setting of caller
+owned fields.
+Direct application access to the data structure fields is not supported.
+.Ss Library Vt memory_type Ss Fields
+Each
+.Vt "struct memory_type"
+holds a description of the memory type, including its name and the allocator
+it is managed by, as well as current statistics on use.
+Some statistics are directly measured, others are derived from directly
+measured statistics.
+Certain high level statistics are present across all available allocators,
+such as the number of allocation and free operations; other measurements,
+such as the quantity of free items in per-CPU caches, or administrative
+limit on the number of allocations, is available only for specific
+allocators.
+.Ss Caller Vt memory_type Ss Fields
+.Vt "struct memory_type"
+includes fields to allow the application to store data, in the form of
+pointers and 64-bit integers, with memory types.
+For example, the application author might make use of one of the caller
+pointers to reference a more complex data structure tracking long-term
+behavior of the memory type, or a window system object that is used to
+render the state of the memory type.
+General and per-CPU storage is provided with each
+.Vt "struct memory_type"
+in the form of an array of pointers and integers.
+The array entries are accessed via the
+.Fa index
+argument to the get and set accessor methods.
+Possible values of
+.Fa index
+range between
+0
+and
+.Dv MEMSTAT_MAXCALLER .
+.Pp
+Caller-owned fields are initialized to
+0
+or
+.Dv NULL
+when a new
+.Vt "struct memory_type"
+is allocated and attached to a memory type list; these fields retain their
+values across queries that update library-owned fields.
+.Ss Allocator Types
+Currently,
+.Nm
+supports two kernel allocators:
+.Dv ALLOCATOR_UMA
+for
+.Xr uma 9 ,
+and
+.Dv ALLOCATOR_MALLOC
+for
+.Xr malloc 9 .
+These values may be passed to
+.Fn memstat_mtl_find ,
+and will be returned by
+.Fn memstat_get_allocator .
+Two additional constants in the allocator name space are defined:
+.Dv ALLOCATOR_UNKNOWN ,
+which will only be returned as a result of a library error, and
+.Dv ALLOCATOR_ANY ,
+which can be used to specify that returning types matching any allocator is
+permittible from
+.Fn memstat_mtl_find .
+.Ss Access Method List
+The following accessor methods are defined, of which some will be valid for
+a given memory type:
+.Bl -tag -width indent
+.It Fn memstat_get_name
+Return a pointer to the name of the memory type.
+Memory for the name is owned by
+.Nm
+and will be valid through a call to
+.Fn memstat_mtl_free .
+Note that names will be unique with respect to a single allocator, but that
+the same name might be used by different memory types owned by different
+memory allocators.
+.It Fn memstat_get_allocator
+Return an integer identifier for the memory allocator that owns the memory
+type.
+.It Fn memstat_get_countlimit
+If the memory type has an administrative limit on the number of simultaneous
+allocations, return it.
+.It Fn memstat_get_byteslimit
+If the memory type has an administrative limit on the number of bytes of
+memory that may be simultaenously allocated for the memory type, return it.
+.It Fn memstat_get_sizemask
+If the memory type supports variable allocation sizes, return a bitmask of
+sizes allocated for the memory type.
+.It Fn memstat_get_size
+If the memory type supports a fixed allocation size, return that size.
+.It Fn memstat_get_memalloced
+Return the total number of bytes allocated for the memory type over its
+lifetime.
+.It Fn memstat_get_memfreed
+Return the total number of bytes freed for the memory type over its lifetime.
+.It Fn memstat_get_numallocs
+Return the total number of allocations for the memory type over its lifetime.
+.It Fn memstat_get_numfrees
+Return the total number of frees for the memory type over its lifetime.
+.It Fn memstat_get_bytes
+Return the current number of bytes allocated to the memory type.
+.It Fn memstat_get_count
+Return the current number of allocations for the memory type.
+.It Fn memstat_get_free
+If the memory allocator supports a cache, return the number of items in the
+cache.
+.It Fn memstat_get_failures
+If the memory allocator and type permit allocation failures, return the
+number of allocation failures measured.
+.It Fn memstat_get_caller_pointer
+Return a caller-owned pointer for the memory type.
+.It Fn memstat_set_caller_pointer
+Set a caller-owned pointer for the memory type.
+.It Fn memstat_get_caller_uint64
+Return a caller-owned integer for the memory type.
+.It Fn memstat_set_caller_uint64
+Set a caller-owned integer for the memory type.
+.It Fn memstat_get_zonefree
+If the memory allocator supports a multi-level allocation structure, return
+the number of cached items in the zone.
+These items will be in a fully constructed state available for immediate
+use.
+.It Fn memstat_get_kegfree
+If the memory allocator supports a multi-level allocation structure, return
+the number of cached items in the keg.
+These items may be in a partially constructed state, and may require further
+processing before they can be made available for use.
+.It Fn memstat_get_percpu_memalloced
+If the memory allocator supports per-CPU statistics, return the number of
+bytes of memory allocated for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_memfreed
+If the memory allocator supports per-CPU statistics, return the number of
+bytes of memory freed from the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_numallocs
+If the memory allocator supports per-CPU statistics, return the number of
+allocations for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_numfrees
+If the memory allocator supports per-CPU statistics, return the number of
+frees for the memory type on the CPU over its lifetime.
+.It Fn memstat_get_percpu_sizemask
+If the memory allocator supports variable size memory allocation and per-CPU
+statistics, return the size bitmask for the memory type on the CPU.
+.It Fn memstat_get_percpu_caller_pointer
+Return a caller-owned per-CPU pointer for the memory type.
+.It Fn memstat_set_percpu_caller_pointer
+Set a caller-owned per-CPU pointer for the memory type.
+.It Fn memstat_get_percpu_caller_uint64
+Return a caller-owned per-CPU integer for the memory type.
+.It Fn memsttat_set_percpu_caller_uint64
+Set a caller-owned per-CPU integer for the memory type.
+.It Fn memstat_get_percpu_free
+If the memory allocator supports a per-CPU cache, return the number of free
+items in the per-CPU cache of the designated CPU.
+.El
+.Sh RETURN VALUES
+.Nm
+functions fall into three categories: functions returning a pointer to an
+object, functions returning an integer return value, and functions
+implementing accessor methods returning data from a
+.Vt "struct memory_type" .
+.Pp
+Functions returning a pointer to an object will generally return
+.Dv NULL
+on failure.
+.Fn memstat_mtl_alloc
+will return an error value via
+.Va errno ,
+which will consist of the value
+.Er ENOMEM .
+Functions
+.Fn memstat_mtl_first ,
+.Fn memstat_mtl_next ,
+and
+.Fn memstat_mtl_find
+will return
+.Dv NULL
+when there is no entry or match in the list; however, this is not considered
+a failure mode and no error value is available.
+.Pp
+Functions returning an integer success value will return
+0
+on success, or
+\-1
+on failure.
+If a failure is returned, the list error access method,
+.Fn memstat_mtl_geterror ,
+may be used to retrieve the error state.
+The string representation of the error may be retrieved using
+.Fn memstat_strerror .
+Possible error values are:
+.Bl -tag -width ".Dv MEMSTAT_ERROR_KVM_SHORTREAD"
+.It Dv MEMSTAT_ERROR_UNDEFINED
+Undefined error.
+Occurs if
+.Fn memstat_mtl_geterror
+is called on a list before an error associated with the list has occurred.
+.It Dv MEMSTAT_ERROR_NOMEMORY
+Insufficient memory.
+Occurs if library calls to
+.Xr malloc 3
+fail, or if a system call to retrieve kernel statistics fails with
+.Er ENOMEM .
+.It Dv MEMSTAT_ERROR_VERSION
+Returned if the current version of
+.Nm
+is unable to interpret the statistics data returned by the kernel due to an
+explicit version mismatch, or to differences in data structures that cannot
+be reconciled.
+.It Dv MEMSTAT_ERROR_PERMISSION
+Returned if a statistics source returns
+.Va errno
+values of
+.Er EACCES
+or
+.Er EPERM .
+.It Dv MEMSTAT_ERROR_TOOMANYCPUS
+Returned if the compile-time limit on the number of CPUs in
+.Nm
+is lower than the number of CPUs returned by a statistics data source.
+.It Dv MEMSTAT_ERROR_DATAERROR
+Returned if
+.Nm
+is unable to interpret statistics data returned by the data source, even
+though there does not appear to be a version problem.
+.It Dv MEMSTAT_ERROR_KVM
+Returned if
+.Nm
+experiences an error while using
+.Xr kvm 3
+interfaces to query statistics data.
+Use
+.Xr kvm_geterr 3
+to retrieve the error.
+.It Dv MEMSTAT_ERROR_KVM_NOSYMBOL
+Returned if
+.Nm
+is unable to read a required symbol from the kernel being operated on.
+.It Dv MEMSTAT_ERROR_KVM_SHORTREAD
+Returned if
+.Nm
+attempts to read data from a live memory image or kernel core dump and
+insufficient data is returned.
+.El
+.Pp
+Finally, functions returning data from a
+.Vt "struct memory_type"
+pointer are not permitted to fail, and directly return either a statistic
+or pointer to a string.
+.Sh EXAMPLES
+Create a memory type list, query the
+.Xr uma 9
+memory allocator for available statistics, and print out the number of
+allocations performed by the
+.Dv mbuf
+zone.
+.Bd -literal -offset indent
+struct memory_type_list *mtlp;
+struct memory_type *mtp;
+uint64_t mbuf_count;
+
+mtlp = memstat_mtl_alloc();
+if (mtlp == NULL)
+    err(-1, "memstat_mtl_alloc");
+if (memstat_sysctl_uma(mtlp, 0) < 0)
+    err(-1, "memstat_sysctl_uma");
+mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, "mbuf");
+if (mtp == NULL)
+    errx(-1, "memstat_mtl_find: mbuf not found");
+mbuf_count = memstat_get_count(mtp);
+memstat_mtl_free(mtlp);
+
+printf("mbufs: %llu\en", (unsigned long long)mbuf_count);
+.Ed
+.Sh SEE ALSO
+.Xr malloc 9 ,
+.Xr uma 9
+.Sh HISTORY
+The
+.Nm
+library appeared in
+.Fx 6.0 .
+.Sh AUTHORS
+The kernel memory allocator changes necessary to support a general purpose
+monitoring library, along with the library, were written by
+.An Robert Watson Aq rwatson at FreeBSD.org .
+.Sh BUGS
+There are memory allocators in the kernel, such as the VM page allocator
+and
+.Nm sf_buf
+allocator, which are not currently supported by
+.Nm .
+.Pp
+Once a memory type is present on a memory type list, it will not be removed
+even if the kernel no longer presents information on the type via its
+monitoring interfaces.
+In order to flush removed memory types, it is necessary to free the entire
+list and allocate a new one.
diff --git a/freebsd-userspace/lib/libmemstat/memstat.c b/freebsd-userspace/lib/libmemstat/memstat.c
new file mode 100644
index 0000000..28e4813
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat.c
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+const char *
+memstat_strerror(int error)
+{
+
+	switch (error) {
+	case MEMSTAT_ERROR_NOMEMORY:
+		return ("Cannot allocate memory");
+	case MEMSTAT_ERROR_VERSION:
+		return ("Version mismatch");
+	case MEMSTAT_ERROR_PERMISSION:
+		return ("Permission denied");
+	case MEMSTAT_ERROR_TOOMANYCPUS:
+		return ("Too many CPUs");
+	case MEMSTAT_ERROR_DATAERROR:
+		return ("Data format error");
+	case MEMSTAT_ERROR_KVM:
+		return ("KVM error");
+	case MEMSTAT_ERROR_KVM_NOSYMBOL:
+		return ("KVM unable to find symbol");
+	case MEMSTAT_ERROR_KVM_SHORTREAD:
+		return ("KVM short read");
+	case MEMSTAT_ERROR_UNDEFINED:
+	default:
+		return ("Unknown error");
+	}
+}
+
+struct memory_type_list *
+memstat_mtl_alloc(void)
+{
+	struct memory_type_list *mtlp;
+
+	mtlp = malloc(sizeof(*mtlp));
+	if (mtlp == NULL)
+		return (NULL);
+
+	LIST_INIT(&mtlp->mtl_list);
+	mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED;
+	return (mtlp);
+}
+
+struct memory_type *
+memstat_mtl_first(struct memory_type_list *list)
+{
+
+	return (LIST_FIRST(&list->mtl_list));
+}
+
+struct memory_type *
+memstat_mtl_next(struct memory_type *mtp)
+{
+
+	return (LIST_NEXT(mtp, mt_list));
+}
+
+void
+_memstat_mtl_empty(struct memory_type_list *list)
+{
+	struct memory_type *mtp;
+
+	while ((mtp = LIST_FIRST(&list->mtl_list))) {
+		LIST_REMOVE(mtp, mt_list);
+		free(mtp);
+	}
+}
+
+void
+memstat_mtl_free(struct memory_type_list *list)
+{
+
+	_memstat_mtl_empty(list);
+	free(list);
+}
+
+int
+memstat_mtl_geterror(struct memory_type_list *list)
+{
+
+	return (list->mtl_error);
+}
+
+/*
+ * Look for an existing memory_type entry in a memory_type list, based on the
+ * allocator and name of the type.  If not found, return NULL.  No errno or
+ * memstat error.
+ */
+struct memory_type *
+memstat_mtl_find(struct memory_type_list *list, int allocator,
+    const char *name)
+{
+	struct memory_type *mtp;
+
+	LIST_FOREACH(mtp, &list->mtl_list, mt_list) {
+		if ((mtp->mt_allocator == allocator ||
+		    allocator == ALLOCATOR_ANY) &&
+		    strcmp(mtp->mt_name, name) == 0)
+			return (mtp);
+	}
+	return (NULL);
+}
+
+/*
+ * Allocate a new memory_type with the specificed allocator type and name,
+ * then insert into the list.  The structure will be zero'd.
+ *
+ * libmemstat(3) internal function.
+ */
+struct memory_type *
+_memstat_mt_allocate(struct memory_type_list *list, int allocator,
+    const char *name)
+{
+	struct memory_type *mtp;
+
+	mtp = malloc(sizeof(*mtp));
+	if (mtp == NULL)
+		return (NULL);
+
+	bzero(mtp, sizeof(*mtp));
+
+	mtp->mt_allocator = allocator;
+	strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME);
+	LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list);
+	return (mtp);
+}
+
+/*
+ * Reset any libmemstat(3)-owned statistics in a memory_type record so that
+ * it can be reused without incremental addition problems.  Caller-owned
+ * memory is left "as-is", and must be updated by the caller if desired.
+ *
+ * libmemstat(3) internal function.
+ */
+void
+_memstat_mt_reset_stats(struct memory_type *mtp)
+{
+	int i;
+
+	mtp->mt_countlimit = 0;
+	mtp->mt_byteslimit = 0;
+	mtp->mt_sizemask = 0;
+	mtp->mt_size = 0;
+
+	mtp->mt_memalloced = 0;
+	mtp->mt_memfreed = 0;
+	mtp->mt_numallocs = 0;
+	mtp->mt_numfrees = 0;
+	mtp->mt_bytes = 0;
+	mtp->mt_count = 0;
+	mtp->mt_free = 0;
+	mtp->mt_failures = 0;
+
+	mtp->mt_zonefree = 0;
+	mtp->mt_kegfree = 0;
+
+	for (i = 0; i < MEMSTAT_MAXCPU; i++) {
+		mtp->mt_percpu_alloc[i].mtp_memalloced = 0;
+		mtp->mt_percpu_alloc[i].mtp_memfreed = 0;
+		mtp->mt_percpu_alloc[i].mtp_numallocs = 0;
+		mtp->mt_percpu_alloc[i].mtp_numfrees = 0;
+		mtp->mt_percpu_alloc[i].mtp_sizemask = 0;
+		mtp->mt_percpu_cache[i].mtp_free = 0;
+	}
+}
+
+/*
+ * Accessor methods for struct memory_type.  Avoids encoding the structure
+ * ABI into the application.
+ */
+const char *
+memstat_get_name(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_name);
+}
+
+int
+memstat_get_allocator(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_allocator);
+}
+
+uint64_t
+memstat_get_countlimit(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_countlimit);
+}
+
+uint64_t
+memstat_get_byteslimit(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_byteslimit);
+}
+
+uint64_t
+memstat_get_sizemask(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_sizemask);
+}
+
+uint64_t
+memstat_get_size(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_size);
+}
+
+uint64_t
+memstat_get_memalloced(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_memalloced);
+}
+
+uint64_t
+memstat_get_memfreed(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_memfreed);
+}
+
+uint64_t
+memstat_get_numallocs(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_numallocs);
+}
+
+uint64_t
+memstat_get_numfrees(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_numfrees);
+}
+
+uint64_t
+memstat_get_bytes(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_bytes);
+}
+
+uint64_t
+memstat_get_count(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_count);
+}
+
+uint64_t
+memstat_get_free(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_free);
+}
+
+uint64_t
+memstat_get_failures(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_failures);
+}
+
+void *
+memstat_get_caller_pointer(const struct memory_type *mtp, int index)
+{
+
+	return (mtp->mt_caller_pointer[index]);
+}
+
+void
+memstat_set_caller_pointer(struct memory_type *mtp, int index, void *value)
+{
+
+	mtp->mt_caller_pointer[index] = value;
+}
+
+uint64_t
+memstat_get_caller_uint64(const struct memory_type *mtp, int index)
+{
+
+	return (mtp->mt_caller_uint64[index]);
+}
+
+void
+memstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value)
+{
+
+	mtp->mt_caller_uint64[index] = value;
+}
+
+uint64_t
+memstat_get_zonefree(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_zonefree);
+}
+
+uint64_t
+memstat_get_kegfree(const struct memory_type *mtp)
+{
+
+	return (mtp->mt_kegfree);
+}
+
+uint64_t
+memstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_memalloced);
+}
+
+uint64_t
+memstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_memfreed);
+}
+
+uint64_t
+memstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_numallocs);
+}
+
+uint64_t
+memstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_numfrees);
+}
+
+uint64_t
+memstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_sizemask);
+}
+
+void *
+memstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu,
+    int index)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]);
+}
+
+void
+memstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu,
+    int index, void *value)
+{
+
+	mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value;
+}
+
+uint64_t
+memstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu,
+    int index)
+{
+
+	return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]);
+}
+
+void
+memstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index,
+    uint64_t value)
+{
+
+	mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value;
+}
+
+uint64_t
+memstat_get_percpu_free(const struct memory_type *mtp, int cpu)
+{
+
+	return (mtp->mt_percpu_cache[cpu].mtp_free);
+}
diff --git a/freebsd-userspace/lib/libmemstat/memstat.h b/freebsd-userspace/lib/libmemstat/memstat.h
new file mode 100644
index 0000000..5991a8f
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat.h
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MEMSTAT_H_
+#define	_MEMSTAT_H_
+
+#ifdef __rtems__
+#include <stdint.h>
+#endif
+
+/*
+ * Number of CPU slots in library-internal data structures.  This should be
+ * at least the value of MAXCPU from param.h.
+ */
+#define	MEMSTAT_MAXCPU	32
+
+/*
+ * Amount of caller data to maintain for each caller data slot.  Applications
+ * must not request more than this number of caller save data, or risk
+ * corrupting internal libmemstat(3) data structures.  A compile time check
+ * in the application is probably appropriate.
+ */
+#define	MEMSTAT_MAXCALLER	16
+
+/*
+ * libmemstat(3) is able to extract memory data from different allocators;
+ * when it does so, it tags which allocator it got the data from so that
+ * consumers can determine which fields are usable, as data returned varies
+ * some.
+ */
+#define	ALLOCATOR_UNKNOWN	0
+#define	ALLOCATOR_MALLOC	1
+#define	ALLOCATOR_UMA		2
+#define	ALLOCATOR_ANY		255
+
+/*
+ * Library maximum type name.  Should be max(set of name maximums over
+ * various allocators).
+ */
+#define	MEMTYPE_MAXNAME		32
+
+/*
+ * Library error conditions, mostly from the underlying data sources.  On
+ * failure, functions typically return (-1) or (NULL); on success, (0) or a
+ * valid data pointer.  The error from the last operation is stored in
+ * struct memory_type_list, and accessed via memstat_get_error(list).
+ */
+#define	MEMSTAT_ERROR_UNDEFINED		0	/* Initialization value. */
+#define	MEMSTAT_ERROR_NOMEMORY		1	/* Out of memory. */
+#define	MEMSTAT_ERROR_VERSION		2	/* Unsupported version. */
+#define	MEMSTAT_ERROR_PERMISSION	3	/* Permission denied. */
+#define	MEMSTAT_ERROR_TOOMANYCPUS	4	/* Too many CPUs. */
+#define	MEMSTAT_ERROR_DATAERROR		5	/* Error in stat data. */
+#define	MEMSTAT_ERROR_KVM		6	/* See kvm_geterr() for err. */
+#define	MEMSTAT_ERROR_KVM_NOSYMBOL	7	/* Symbol not available. */
+#define	MEMSTAT_ERROR_KVM_SHORTREAD	8	/* Short kvm_read return. */
+
+/*
+ * Forward declare struct memory_type, which holds per-type properties and
+ * statistics.  This is an opaque type, to be frobbed only from within the
+ * library, in order to avoid building ABI assumptions into the application.
+ * Accessor methods should be used to get and sometimes set the fields from
+ * consumers of the library.
+ */
+struct memory_type;
+
+/*
+ * struct memory_type_list is the head of a list of memory types and
+ * statistics.
+ */
+struct memory_type_list;
+
+__BEGIN_DECLS
+/*
+ * Functions that operate without memory type or memory type list context.
+ */
+const char	*memstat_strerror(int error);
+
+/*
+ * Functions for managing memory type and statistics data.
+ */
+struct memory_type_list	*memstat_mtl_alloc(void);
+struct memory_type	*memstat_mtl_first(struct memory_type_list *list);
+struct memory_type	*memstat_mtl_next(struct memory_type *mtp);
+struct memory_type	*memstat_mtl_find(struct memory_type_list *list,
+			    int allocator, const char *name);
+void	memstat_mtl_free(struct memory_type_list *list);
+int	memstat_mtl_geterror(struct memory_type_list *list);
+
+/*
+ * Functions to retrieve data from a live kernel using sysctl.
+ */
+int	memstat_sysctl_all(struct memory_type_list *list, int flags);
+int	memstat_sysctl_malloc(struct memory_type_list *list, int flags);
+int	memstat_sysctl_uma(struct memory_type_list *list, int flags);
+
+/*
+ * Functions to retrieve data from a kernel core (or /dev/kmem).
+ */
+int	memstat_kvm_all(struct memory_type_list *list, void *kvm_handle);
+int	memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle);
+int	memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle);
+
+/*
+ * Accessor methods for struct memory_type.
+ */
+const char	*memstat_get_name(const struct memory_type *mtp);
+int		 memstat_get_allocator(const struct memory_type *mtp);
+uint64_t	 memstat_get_countlimit(const struct memory_type *mtp);
+uint64_t	 memstat_get_byteslimit(const struct memory_type *mtp);
+uint64_t	 memstat_get_sizemask(const struct memory_type *mtp);
+uint64_t	 memstat_get_size(const struct memory_type *mtp);
+uint64_t	 memstat_get_memalloced(const struct memory_type *mtp);
+uint64_t	 memstat_get_memfreed(const struct memory_type *mtp);
+uint64_t	 memstat_get_numallocs(const struct memory_type *mtp);
+uint64_t	 memstat_get_numfrees(const struct memory_type *mtp);
+uint64_t	 memstat_get_bytes(const struct memory_type *mtp);
+uint64_t	 memstat_get_count(const struct memory_type *mtp);
+uint64_t	 memstat_get_free(const struct memory_type *mtp);
+uint64_t	 memstat_get_failures(const struct memory_type *mtp);
+void		*memstat_get_caller_pointer(const struct memory_type *mtp,
+		    int index);
+void		 memstat_set_caller_pointer(struct memory_type *mtp,
+		    int index, void *value);
+uint64_t	 memstat_get_caller_uint64(const struct memory_type *mtp,
+		    int index);
+void		 memstat_set_caller_uint64(struct memory_type *mtp, int index,
+		    uint64_t value);
+uint64_t	 memstat_get_zonefree(const struct memory_type *mtp);
+uint64_t	 memstat_get_kegfree(const struct memory_type *mtp);
+uint64_t	 memstat_get_percpu_memalloced(const struct memory_type *mtp,
+		    int cpu);
+uint64_t	 memstat_get_percpu_memfreed(const struct memory_type *mtp,
+		    int cpu);
+uint64_t	 memstat_get_percpu_numallocs(const struct memory_type *mtp,
+		    int cpu);
+uint64_t	 memstat_get_percpu_numfrees(const struct memory_type *mtp,
+		    int cpu);
+uint64_t	 memstat_get_percpu_sizemask(const struct memory_type *mtp,
+		    int cpu);
+void		*memstat_get_percpu_caller_pointer(
+		    const struct memory_type *mtp, int cpu, int index);
+void		 memstat_set_percpu_caller_pointer(struct memory_type *mtp,
+		    int cpu, int index, void *value);
+uint64_t	 memstat_get_percpu_caller_uint64(
+		    const struct memory_type *mtp, int cpu, int index);
+void		 memstat_set_percpu_caller_uint64(struct memory_type *mtp,
+		    int cpu, int index, uint64_t value);
+uint64_t	 memstat_get_percpu_free(const struct memory_type *mtp,
+		    int cpu);
+__END_DECLS
+
+#endif /* !_MEMSTAT_H_ */
diff --git a/freebsd-userspace/lib/libmemstat/memstat_all.c b/freebsd-userspace/lib/libmemstat/memstat_all.c
new file mode 100644
index 0000000..bd74b8a
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat_all.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "memstat.h"
+
+/*
+ * Query all available memory allocator sources.  Currently this consists of
+ * malloc(9) and UMA(9).
+ */
+int
+memstat_sysctl_all(struct memory_type_list *mtlp, int flags)
+{
+
+	if (memstat_sysctl_malloc(mtlp, flags) < 0)
+		return (-1);
+	if (memstat_sysctl_uma(mtlp, flags) < 0)
+		return (-1);
+	return (0);
+}
+
+int
+memstat_kvm_all(struct memory_type_list *mtlp, void *kvm_handle)
+{
+
+	if (memstat_kvm_malloc(mtlp, kvm_handle) < 0)
+		return (-1);
+	if (memstat_kvm_uma(mtlp, kvm_handle) < 0)
+		return (-1);
+	return (0);
+}
diff --git a/freebsd-userspace/lib/libmemstat/memstat_internal.h b/freebsd-userspace/lib/libmemstat/memstat_internal.h
new file mode 100644
index 0000000..7123518
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat_internal.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MEMSTAT_INTERNAL_H_
+#define	_MEMSTAT_INTERNAL_H_
+
+/*
+ * memstat maintains its own internal notion of statistics on each memory
+ * type, common across UMA and kernel malloc.  Some fields are straight from
+ * the allocator statistics, others are derived when extracted from the
+ * kernel.  A struct memory_type will describe each type supported by an
+ * allocator.  memory_type structures can be chained into lists.
+ */
+struct memory_type {
+	/*
+	 * Static properties of type.
+	 */
+	int	 mt_allocator;		/* malloc(9), uma(9), etc. */
+	char	 mt_name[MEMTYPE_MAXNAME];	/* name of memory type. */
+
+	/*
+	 * (Relatively) static zone settings, that don't uniquely identify
+	 * the zone, but also don't change much.
+	 */
+	uint64_t	 mt_countlimit;	/* 0, or maximum allocations. */
+	uint64_t	 mt_byteslimit;	/* 0, or maximum bytes. */
+	uint64_t	 mt_sizemask;	/* malloc: allocated size bitmask. */
+	uint64_t	 mt_size;	/* uma: size of objects. */
+
+	/*
+	 * Zone or type information that includes all caches and any central
+	 * zone state.  Depending on the allocator, this may be synthesized
+	 * from several sources, or directly measured.
+	 */
+	uint64_t	 mt_memalloced;	/* Bytes allocated over life time. */
+	uint64_t	 mt_memfreed;	/* Bytes freed over life time. */
+	uint64_t	 mt_numallocs;	/* Allocations over life time. */
+	uint64_t	 mt_numfrees;	/* Frees over life time. */
+	uint64_t	 mt_bytes;	/* Bytes currently allocated. */
+	uint64_t	 mt_count;	/* Number of current allocations. */
+	uint64_t	 mt_free;	/* Number of cached free items. */
+	uint64_t	 mt_failures;	/* Number of allocation failures. */
+
+	/*
+	 * Caller-owned memory.
+	 */
+	void		*mt_caller_pointer[MEMSTAT_MAXCALLER];	/* Pointers. */
+	uint64_t	 mt_caller_uint64[MEMSTAT_MAXCALLER];	/* Integers. */
+
+	/*
+	 * For allocators making use of per-CPU caches, we also provide raw
+	 * statistics from the central allocator and each per-CPU cache,
+	 * which (combined) sometimes make up the above general statistics.
+	 *
+	 * First, central zone/type state, all numbers excluding any items
+	 * cached in per-CPU caches.
+	 *
+	 * XXXRW: Might be desirable to separately expose allocation stats
+	 * from zone, which should (combined with per-cpu) add up to the
+	 * global stats above.
+	 */
+	uint64_t	 mt_zonefree;	/* Free items in zone. */
+	uint64_t	 mt_kegfree;	/* Free items in keg. */
+
+	/*
+	 * Per-CPU measurements fall into two categories: per-CPU allocation,
+	 * and per-CPU cache state.
+	 */
+	struct {
+		uint64_t	 mtp_memalloced;/* Per-CPU mt_memalloced. */
+		uint64_t	 mtp_memfreed;	/* Per-CPU mt_memfreed. */
+		uint64_t	 mtp_numallocs;	/* Per-CPU mt_numallocs. */
+		uint64_t	 mtp_numfrees;	/* Per-CPU mt_numfrees. */
+		uint64_t	 mtp_sizemask;	/* Per-CPU mt_sizemask. */
+		void		*mtp_caller_pointer[MEMSTAT_MAXCALLER];
+		uint64_t	 mtp_caller_uint64[MEMSTAT_MAXCALLER];
+	}	mt_percpu_alloc[MEMSTAT_MAXCPU];
+
+	struct {
+		uint64_t	 mtp_free;	/* Per-CPU cache free items. */
+	}	mt_percpu_cache[MEMSTAT_MAXCPU];
+
+	LIST_ENTRY(memory_type)	mt_list;	/* List of types. */
+};
+
+/*
+ * Description of struct memory_type_list is in memstat.h.
+ */
+struct memory_type_list {
+	LIST_HEAD(, memory_type)	mtl_list;
+	int				mtl_error;
+};
+
+void			 _memstat_mtl_empty(struct memory_type_list *list);
+struct memory_type	*_memstat_mt_allocate(struct memory_type_list *list,
+			    int allocator, const char *name);
+void			 _memstat_mt_reset_stats(struct memory_type *mtp);
+
+#endif /* !_MEMSTAT_INTERNAL_H_ */
diff --git a/freebsd-userspace/lib/libmemstat/memstat_malloc.c b/freebsd-userspace/lib/libmemstat/memstat_malloc.c
new file mode 100644
index 0000000..96ff8a1
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat_malloc.c
@@ -0,0 +1,417 @@
+#include "port_before.h"
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#ifdef __rtems__
+#include <freebsd/sys/malloc.h>
+#else
+#include <sys/malloc.h>
+#endif
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#ifndef __rtems__
+#include <kvm.h>
+#endif
+#include <nlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+static struct nlist namelist[] = {
+#define	X_KMEMSTATISTICS	0
+	{ .n_name = "_kmemstatistics" },
+#define	X_MP_MAXCPUS		1
+	{ .n_name = "_mp_maxcpus" },
+	{ .n_name = "" },
+};
+
+/*
+ * Extract malloc(9) statistics from the running kernel, and store all memory
+ * type information in the passed list.  For each type, check the list for an
+ * existing entry with the right name/allocator -- if present, update that
+ * entry.  Otherwise, add a new entry.  On error, the entire list will be
+ * cleared, as entries will be in an inconsistent state.
+ *
+ * To reduce the level of work for a list that starts empty, we keep around a
+ * hint as to whether it was empty when we began, so we can avoid searching
+ * the list for entries to update.  Updates are O(n^2) due to searching for
+ * each entry before adding it.
+ */
+int
+memstat_sysctl_malloc(struct memory_type_list *list, int flags)
+{
+	struct malloc_type_stream_header *mtshp;
+	struct malloc_type_header *mthp;
+	struct malloc_type_stats *mtsp;
+	struct memory_type *mtp;
+	int count, hint_dontsearch, i, j, maxcpus;
+	char *buffer, *p;
+	size_t size;
+
+	hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+	/*
+	 * Query the number of CPUs, number of malloc types so that we can
+	 * guess an initial buffer size.  We loop until we succeed or really
+	 * fail.  Note that the value of maxcpus we query using sysctl is not
+	 * the version we use when processing the real data -- that is read
+	 * from the header.
+	 */
+retry:
+	size = sizeof(maxcpus);
+	if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+	if (size != sizeof(maxcpus)) {
+		list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+
+	if (maxcpus > MEMSTAT_MAXCPU) {
+		list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+		return (-1);
+	}
+
+	size = sizeof(count);
+	if (sysctlbyname("kern.malloc_count", &count, &size, NULL, 0) < 0) {
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_VERSION;
+		return (-1);
+	}
+	if (size != sizeof(count)) {
+		list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+
+	size = sizeof(*mthp) + count * (sizeof(*mthp) + sizeof(*mtsp) *
+	    maxcpus);
+
+	buffer = malloc(size);
+	if (buffer == NULL) {
+		list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+		return (-1);
+	}
+
+	if (sysctlbyname("kern.malloc_stats", buffer, &size, NULL, 0) < 0) {
+		/*
+		 * XXXRW: ENOMEM is an ambiguous return, we should bound the
+		 * number of loops, perhaps.
+		 */
+		if (errno == ENOMEM) {
+			free(buffer);
+			goto retry;
+		}
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+
+	if (size == 0) {
+		free(buffer);
+		return (0);
+	}
+
+	if (size < sizeof(*mtshp)) {
+		list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+	p = buffer;
+	mtshp = (struct malloc_type_stream_header *)p;
+	p += sizeof(*mtshp);
+
+	if (mtshp->mtsh_version != MALLOC_TYPE_STREAM_VERSION) {
+		list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+
+	if (mtshp->mtsh_maxcpus > MEMSTAT_MAXCPU) {
+		list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+		free(buffer);
+		return (-1);
+	}
+
+	/*
+	 * For the remainder of this function, we are quite trusting about
+	 * the layout of structures and sizes, since we've determined we have
+	 * a matching version and acceptable CPU count.
+	 */
+	maxcpus = mtshp->mtsh_maxcpus;
+	count = mtshp->mtsh_count;
+	for (i = 0; i < count; i++) {
+		mthp = (struct malloc_type_header *)p;
+		p += sizeof(*mthp);
+
+		if (hint_dontsearch == 0) {
+			mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC,
+			    mthp->mth_name);
+		} else
+			mtp = NULL;
+		if (mtp == NULL)
+			mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
+			    mthp->mth_name);
+		if (mtp == NULL) {
+			_memstat_mtl_empty(list);
+			free(buffer);
+			list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+			return (-1);
+		}
+
+		/*
+		 * Reset the statistics on a current node.
+		 */
+		_memstat_mt_reset_stats(mtp);
+
+		for (j = 0; j < maxcpus; j++) {
+			mtsp = (struct malloc_type_stats *)p;
+			p += sizeof(*mtsp);
+
+			/*
+			 * Sumarize raw statistics across CPUs into coalesced
+			 * statistics.
+			 */
+			mtp->mt_memalloced += mtsp->mts_memalloced;
+			mtp->mt_memfreed += mtsp->mts_memfreed;
+			mtp->mt_numallocs += mtsp->mts_numallocs;
+			mtp->mt_numfrees += mtsp->mts_numfrees;
+			mtp->mt_sizemask |= mtsp->mts_size;
+
+			/*
+			 * Copies of per-CPU statistics.
+			 */
+			mtp->mt_percpu_alloc[j].mtp_memalloced =
+			    mtsp->mts_memalloced;
+			mtp->mt_percpu_alloc[j].mtp_memfreed =
+			    mtsp->mts_memfreed;
+			mtp->mt_percpu_alloc[j].mtp_numallocs =
+			    mtsp->mts_numallocs;
+			mtp->mt_percpu_alloc[j].mtp_numfrees =
+			    mtsp->mts_numfrees;
+			mtp->mt_percpu_alloc[j].mtp_sizemask =
+			    mtsp->mts_size;
+		}
+
+		/*
+		 * Derived cross-CPU statistics.
+		 */
+		mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+		mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+	}
+
+	free(buffer);
+
+	return (0);
+}
+
+#ifndef __rtems__
+static int
+kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
+    size_t offset)
+{
+	ssize_t ret;
+
+	ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
+	    size);
+	if (ret < 0)
+		return (MEMSTAT_ERROR_KVM);
+	if ((size_t)ret != size)
+		return (MEMSTAT_ERROR_KVM_SHORTREAD);
+	return (0);
+}
+
+static int
+kread_string(kvm_t *kvm, const void *kvm_pointer, char *buffer, int buflen)
+{
+	ssize_t ret;
+	int i;
+
+	for (i = 0; i < buflen; i++) {
+		ret = kvm_read(kvm, __DECONST(unsigned long, kvm_pointer) +
+		    i, &(buffer[i]), sizeof(char));
+		if (ret < 0)
+			return (MEMSTAT_ERROR_KVM);
+		if ((size_t)ret != sizeof(char))
+			return (MEMSTAT_ERROR_KVM_SHORTREAD);
+		if (buffer[i] == '\0')
+			return (0);
+	}
+	/* Truncate. */
+	buffer[i-1] = '\0';
+	return (0);
+}
+
+static int
+kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
+    size_t offset)
+{
+	ssize_t ret;
+
+	ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
+	if (ret < 0)
+		return (MEMSTAT_ERROR_KVM);
+	if ((size_t)ret != size)
+		return (MEMSTAT_ERROR_KVM_SHORTREAD);
+	return (0);
+}
+
+int
+memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle)
+{
+	struct memory_type *mtp;
+	void *kmemstatistics;
+	int hint_dontsearch, j, mp_maxcpus, ret;
+	char name[MEMTYPE_MAXNAME];
+	struct malloc_type_stats mts[MEMSTAT_MAXCPU], *mtsp;
+	struct malloc_type_internal *mtip;
+	struct malloc_type type, *typep;
+	kvm_t *kvm;
+
+	kvm = (kvm_t *)kvm_handle;
+
+	hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+	if (kvm_nlist(kvm, namelist) != 0) {
+		list->mtl_error = MEMSTAT_ERROR_KVM;
+		return (-1);
+	}
+
+	if (namelist[X_KMEMSTATISTICS].n_type == 0 ||
+	    namelist[X_KMEMSTATISTICS].n_value == 0) {
+		list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
+		return (-1);
+	}
+
+	ret = kread_symbol(kvm, X_MP_MAXCPUS, &mp_maxcpus,
+	    sizeof(mp_maxcpus), 0);
+	if (ret != 0) {
+		list->mtl_error = ret;
+		return (-1);
+	}
+
+	if (mp_maxcpus > MEMSTAT_MAXCPU) {
+		list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+		return (-1);
+	}
+
+	ret = kread_symbol(kvm, X_KMEMSTATISTICS, &kmemstatistics,
+	    sizeof(kmemstatistics), 0);
+	if (ret != 0) {
+		list->mtl_error = ret;
+		return (-1);
+	}
+
+	for (typep = kmemstatistics; typep != NULL; typep = type.ks_next) {
+		ret = kread(kvm, typep, &type, sizeof(type), 0);
+		if (ret != 0) {
+			_memstat_mtl_empty(list);
+			list->mtl_error = ret;
+			return (-1);
+		}
+		ret = kread_string(kvm, (void *)type.ks_shortdesc, name,
+		    MEMTYPE_MAXNAME);
+		if (ret != 0) {
+			_memstat_mtl_empty(list);
+			list->mtl_error = ret;
+			return (-1);
+		}
+
+		/*
+		 * Since our compile-time value for MAXCPU may differ from the
+		 * kernel's, we populate our own array.
+		 */
+		mtip = type.ks_handle;
+		ret = kread(kvm, mtip->mti_stats, mts, mp_maxcpus *
+		    sizeof(struct malloc_type_stats), 0);
+		if (ret != 0) {
+			_memstat_mtl_empty(list);
+			list->mtl_error = ret;
+			return (-1);
+		}
+
+		if (hint_dontsearch == 0) {
+			mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC, name);
+		} else
+			mtp = NULL;
+		if (mtp == NULL)
+			mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
+			    name);
+		if (mtp == NULL) {
+			_memstat_mtl_empty(list);
+			list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+			return (-1);
+		}
+
+		/*
+		 * This logic is replicated from kern_malloc.c, and should
+		 * be kept in sync.
+		 */
+		_memstat_mt_reset_stats(mtp);
+		for (j = 0; j < mp_maxcpus; j++) {
+			mtsp = &mts[j];
+			mtp->mt_memalloced += mtsp->mts_memalloced;
+			mtp->mt_memfreed += mtsp->mts_memfreed;
+			mtp->mt_numallocs += mtsp->mts_numallocs;
+			mtp->mt_numfrees += mtsp->mts_numfrees;
+			mtp->mt_sizemask |= mtsp->mts_size;
+
+			mtp->mt_percpu_alloc[j].mtp_memalloced =
+			    mtsp->mts_memalloced;
+			mtp->mt_percpu_alloc[j].mtp_memfreed =
+			    mtsp->mts_memfreed;
+			mtp->mt_percpu_alloc[j].mtp_numallocs =
+			    mtsp->mts_numallocs;
+			mtp->mt_percpu_alloc[j].mtp_numfrees =
+			    mtsp->mts_numfrees;
+			mtp->mt_percpu_alloc[j].mtp_sizemask =
+			    mtsp->mts_size;
+		}
+
+		mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+		mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+	}
+
+	return (0);
+}
+#endif
diff --git a/freebsd-userspace/lib/libmemstat/memstat_uma.c b/freebsd-userspace/lib/libmemstat/memstat_uma.c
new file mode 100644
index 0000000..deac50d
--- /dev/null
+++ b/freebsd-userspace/lib/libmemstat/memstat_uma.c
@@ -0,0 +1,478 @@
+#include "port_before.h"
+/*-
+ * Copyright (c) 2005-2006 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#define	LIBMEMSTAT	/* Cause vm_page.h not to include opt_vmpage.h */
+#ifdef __rtems__
+#include <freebsd/sys/types.h>
+#include <freebsd/vm/vm.h>
+// #include <vm/vm_page.h>
+#include <freebsd/vm/uma.h>
+#include <freebsd/vm/uma_int.h>
+#else
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+#endif
+
+
+#include <err.h>
+#include <errno.h>
+#ifndef __rtems__
+#include <kvm.h>
+#endif
+#include <nlist.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memstat.h"
+#include "memstat_internal.h"
+
+static struct nlist namelist[] = {
+#define	X_UMA_KEGS	0
+	{ .n_name = "_uma_kegs" },
+#define	X_MP_MAXID	1
+	{ .n_name = "_mp_maxid" },
+#define	X_ALL_CPUS	2
+	{ .n_name = "_all_cpus" },
+	{ .n_name = "" },
+};
+
+/*
+ * Extract uma(9) statistics from the running kernel, and store all memory
+ * type information in the passed list.  For each type, check the list for an
+ * existing entry with the right name/allocator -- if present, update that
+ * entry.  Otherwise, add a new entry.  On error, the entire list will be
+ * cleared, as entries will be in an inconsistent state.
+ *
+ * To reduce the level of work for a list that starts empty, we keep around a
+ * hint as to whether it was empty when we began, so we can avoid searching
+ * the list for entries to update.  Updates are O(n^2) due to searching for
+ * each entry before adding it.
+ */
+int
+memstat_sysctl_uma(struct memory_type_list *list, int flags)
+{
+	struct uma_stream_header *ushp;
+	struct uma_type_header *uthp;
+	struct uma_percpu_stat *upsp;
+	struct memory_type *mtp;
+	int count, hint_dontsearch, i, j, maxcpus;
+	char *buffer, *p;
+	size_t size;
+
+	hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+
+	/*
+	 * Query the number of CPUs, number of malloc types so that we can
+	 * guess an initial buffer size.  We loop until we succeed or really
+	 * fail.  Note that the value of maxcpus we query using sysctl is not
+	 * the version we use when processing the real data -- that is read
+	 * from the header.
+	 */
+retry:
+	size = sizeof(maxcpus);
+	if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+	if (size != sizeof(maxcpus)) {
+		list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+
+	if (maxcpus > MEMSTAT_MAXCPU) {
+		list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+		return (-1);
+	}
+
+	size = sizeof(count);
+	if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) {
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_VERSION;
+		return (-1);
+	}
+	if (size != sizeof(count)) {
+		list->mtl_error = MEMSTAT_ERROR_DATAERROR;
+		return (-1);
+	}
+
+	size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) *
+	    maxcpus);
+
+	buffer = malloc(size);
+	if (buffer == NULL) {
+		list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+		return (-1);
+	}
+
+	if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) {
+		/*
+		 * XXXRW: ENOMEM is an ambiguous return, we should bound the
+		 * number of loops, perhaps.
+		 */
+		if (errno == ENOMEM) {
+			free(buffer);
+			goto retry;
+		}
+		if (errno == EACCES || errno == EPERM)
+			list->mtl_error = MEMSTAT_ERROR_PERMISSION;
+		else
+			list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+
+	if (size == 0) {
+		free(buffer);
+		return (0);
+	}
+
+	if (size < sizeof(*ushp)) {
+		list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+	p = buffer;
+	ushp = (struct uma_stream_header *)p;
+	p += sizeof(*ushp);
+
+	if (ushp->ush_version != UMA_STREAM_VERSION) {
+		list->mtl_error = MEMSTAT_ERROR_VERSION;
+		free(buffer);
+		return (-1);
+	}
+
+	if (ushp->ush_maxcpus > MEMSTAT_MAXCPU) {
+		list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS;
+		free(buffer);
+		return (-1);
+	}
+
+	/*
+	 * For the remainder of this function, we are quite trusting about
+	 * the layout of structures and sizes, since we've determined we have
+	 * a matching version and acceptable CPU count.
+	 */
+	maxcpus = ushp->ush_maxcpus;
+	count = ushp->ush_count;
+	for (i = 0; i < count; i++) {
+		uthp = (struct uma_type_header *)p;
+		p += sizeof(*uthp);
+
+		if (hint_dontsearch == 0) {
+			mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
+			    uthp->uth_name);
+		} else
+			mtp = NULL;
+		if (mtp == NULL)
+			mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
+			    uthp->uth_name);
+		if (mtp == NULL) {
+			_memstat_mtl_empty(list);
+			free(buffer);
+			list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+			return (-1);
+		}
+
+		/*
+		 * Reset the statistics on a current node.
+		 */
+		_memstat_mt_reset_stats(mtp);
+
+		mtp->mt_numallocs = uthp->uth_allocs;
+		mtp->mt_numfrees = uthp->uth_frees;
+		mtp->mt_failures = uthp->uth_fails;
+
+		for (j = 0; j < maxcpus; j++) {
+			upsp = (struct uma_percpu_stat *)p;
+			p += sizeof(*upsp);
+
+			mtp->mt_percpu_cache[j].mtp_free =
+			    upsp->ups_cache_free;
+			mtp->mt_free += upsp->ups_cache_free;
+			mtp->mt_numallocs += upsp->ups_allocs;
+			mtp->mt_numfrees += upsp->ups_frees;
+		}
+
+		mtp->mt_size = uthp->uth_size;
+		mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size;
+		mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size;
+		mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+		mtp->mt_countlimit = uthp->uth_limit;
+		mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size;
+
+		mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+		mtp->mt_zonefree = uthp->uth_zone_free;
+
+		/*
+		 * UMA secondary zones share a keg with the primary zone.  To
+		 * avoid double-reporting of free items, report keg free
+		 * items only in the primary zone.
+		 */
+		if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) {
+			mtp->mt_kegfree = uthp->uth_keg_free;
+			mtp->mt_free += mtp->mt_kegfree;
+		}
+		mtp->mt_free += mtp->mt_zonefree;
+	}
+
+	free(buffer);
+
+	return (0);
+}
+
+#ifndef __rtems__
+static int
+kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
+    size_t offset)
+{
+	ssize_t ret;
+
+	ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
+	    size);
+	if (ret < 0)
+		return (MEMSTAT_ERROR_KVM);
+	if ((size_t)ret != size)
+		return (MEMSTAT_ERROR_KVM_SHORTREAD);
+	return (0);
+}
+
+static int
+kread_string(kvm_t *kvm, void *kvm_pointer, char *buffer, int buflen)
+{
+	ssize_t ret;
+	int i;
+
+	for (i = 0; i < buflen; i++) {
+		ret = kvm_read(kvm, (unsigned long)kvm_pointer + i,
+		    &(buffer[i]), sizeof(char));
+		if (ret < 0)
+			return (MEMSTAT_ERROR_KVM);
+		if ((size_t)ret != sizeof(char))
+			return (MEMSTAT_ERROR_KVM_SHORTREAD);
+		if (buffer[i] == '\0')
+			return (0);
+	}
+	/* Truncate. */
+	buffer[i-1] = '\0';
+	return (0);
+}
+
+static int
+kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
+    size_t offset)
+{
+	ssize_t ret;
+
+	ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
+	if (ret < 0)
+		return (MEMSTAT_ERROR_KVM);
+	if ((size_t)ret != size)
+		return (MEMSTAT_ERROR_KVM_SHORTREAD);
+	return (0);
+}
+
+/*
+ * memstat_kvm_uma() is similar to memstat_sysctl_uma(), only it extracts
+ * UMA(9) statistics from a kernel core/memory file.
+ */
+int
+memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle)
+{
+	LIST_HEAD(, uma_keg) uma_kegs;
+	struct memory_type *mtp;
+	struct uma_bucket *ubp, ub;
+	struct uma_cache *ucp, *ucp_array;
+	struct uma_zone *uzp, uz;
+	struct uma_keg *kzp, kz;
+	int hint_dontsearch, i, mp_maxid, ret;
+	char name[MEMTYPE_MAXNAME];
+	__cpumask_t all_cpus;
+	kvm_t *kvm;
+
+	kvm = (kvm_t *)kvm_handle;
+	hint_dontsearch = LIST_EMPTY(&list->mtl_list);
+	if (kvm_nlist(kvm, namelist) != 0) {
+		list->mtl_error = MEMSTAT_ERROR_KVM;
+		return (-1);
+	}
+	if (namelist[X_UMA_KEGS].n_type == 0 ||
+	    namelist[X_UMA_KEGS].n_value == 0) {
+		list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
+		return (-1);
+	}
+	ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0);
+	if (ret != 0) {
+		list->mtl_error = ret;
+		return (-1);
+	}
+	ret = kread_symbol(kvm, X_UMA_KEGS, &uma_kegs, sizeof(uma_kegs), 0);
+	if (ret != 0) {
+		list->mtl_error = ret;
+		return (-1);
+	}
+	ret = kread_symbol(kvm, X_ALL_CPUS, &all_cpus, sizeof(all_cpus), 0);
+	if (ret != 0) {
+		list->mtl_error = ret;
+		return (-1);
+	}
+	ucp_array = malloc(sizeof(struct uma_cache) * (mp_maxid + 1));
+	if (ucp_array == NULL) {
+		list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+		return (-1);
+	}
+	for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp =
+	    LIST_NEXT(&kz, uk_link)) {
+		ret = kread(kvm, kzp, &kz, sizeof(kz), 0);
+		if (ret != 0) {
+			free(ucp_array);
+			_memstat_mtl_empty(list);
+			list->mtl_error = ret;
+			return (-1);
+		}
+		for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp =
+		    LIST_NEXT(&uz, uz_link)) {
+			ret = kread(kvm, uzp, &uz, sizeof(uz), 0);
+			if (ret != 0) {
+				free(ucp_array);
+				_memstat_mtl_empty(list);
+				list->mtl_error = ret;
+				return (-1);
+			}
+			ret = kread(kvm, uzp, ucp_array,
+			    sizeof(struct uma_cache) * (mp_maxid + 1),
+			    offsetof(struct uma_zone, uz_cpu[0]));
+			if (ret != 0) {
+				free(ucp_array);
+				_memstat_mtl_empty(list);
+				list->mtl_error = ret;
+				return (-1);
+			}
+			ret = kread_string(kvm, uz.uz_name, name,
+			    MEMTYPE_MAXNAME);
+			if (ret != 0) {
+				free(ucp_array);
+				_memstat_mtl_empty(list);
+				list->mtl_error = ret;
+				return (-1);
+			}
+			if (hint_dontsearch == 0) {
+				mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
+				    name);
+			} else
+				mtp = NULL;
+			if (mtp == NULL)
+				mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
+				    name);
+			if (mtp == NULL) {
+				free(ucp_array);
+				_memstat_mtl_empty(list);
+				list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
+				return (-1);
+			}
+			/*
+			 * Reset the statistics on a current node.
+			 */
+			_memstat_mt_reset_stats(mtp);
+			mtp->mt_numallocs = uz.uz_allocs;
+			mtp->mt_numfrees = uz.uz_frees;
+			mtp->mt_failures = uz.uz_fails;
+			if (kz.uk_flags & UMA_ZFLAG_INTERNAL)
+				goto skip_percpu;
+			for (i = 0; i < mp_maxid + 1; i++) {
+				if ((all_cpus & (1 << i)) == 0)
+					continue;
+				ucp = &ucp_array[i];
+				mtp->mt_numallocs += ucp->uc_allocs;
+				mtp->mt_numfrees += ucp->uc_frees;
+
+				if (ucp->uc_allocbucket != NULL) {
+					ret = kread(kvm, ucp->uc_allocbucket,
+					    &ub, sizeof(ub), 0);
+					if (ret != 0) {
+						free(ucp_array);
+						_memstat_mtl_empty(list);
+						list->mtl_error = ret;
+						return (-1);
+					}
+					mtp->mt_free += ub.ub_cnt;
+				}
+				if (ucp->uc_freebucket != NULL) {
+					ret = kread(kvm, ucp->uc_freebucket,
+					    &ub, sizeof(ub), 0);
+					if (ret != 0) {
+						free(ucp_array);
+						_memstat_mtl_empty(list);
+						list->mtl_error = ret;
+						return (-1);
+					}
+					mtp->mt_free += ub.ub_cnt;
+				}
+			}
+skip_percpu:
+			mtp->mt_size = kz.uk_size;
+			mtp->mt_memalloced = mtp->mt_numallocs * mtp->mt_size;
+			mtp->mt_memfreed = mtp->mt_numfrees * mtp->mt_size;
+			mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
+			if (kz.uk_ppera > 1)
+				mtp->mt_countlimit = kz.uk_maxpages /
+				    kz.uk_ipers;
+			else
+				mtp->mt_countlimit = kz.uk_maxpages *
+				    kz.uk_ipers;
+			mtp->mt_byteslimit = mtp->mt_countlimit * mtp->mt_size;
+			mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
+			for (ubp = LIST_FIRST(&uz.uz_full_bucket); ubp !=
+			    NULL; ubp = LIST_NEXT(&ub, ub_link)) {
+				ret = kread(kvm, ubp, &ub, sizeof(ub), 0);
+				mtp->mt_zonefree += ub.ub_cnt;
+			}
+			if (!((kz.uk_flags & UMA_ZONE_SECONDARY) &&
+			    LIST_FIRST(&kz.uk_zones) != uzp)) {
+				mtp->mt_kegfree = kz.uk_free;
+				mtp->mt_free += mtp->mt_kegfree;
+			}
+			mtp->mt_free += mtp->mt_zonefree;
+		}
+	}
+	free(ucp_array);
+	return (0);
+}
+#endif
diff --git a/freebsd-userspace/lib/libutil/expand_number.3 b/freebsd-userspace/lib/libutil/expand_number.3
new file mode 100644
index 0000000..23e488d
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/expand_number.3
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2007 Eric Anderson <anderson at FreeBSD.org>
+.\" Copyright (c) 2007 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 16, 2007
+.Dt EXPAND_NUMBER 3
+.Os
+.Sh NAME
+.Nm expand_number
+.Nd format a number from human readable form
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fo expand_number
+.Fa "const char *buf" "int64_t *num"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn expand_number
+function unformats the
+.Fa buf
+string and stores a signed 64-bit quantity at address pointed out by the
+.Fa num
+argument.
+.Pp
+The
+.Fn expand_number
+function
+follows the SI power of two convention.
+.Pp
+The prefixes are:
+.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent
+.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier"
+.It Li k Ta No kilo Ta 1024
+.It Li M Ta No mega Ta 1048576
+.It Li G Ta No giga Ta 1073741824
+.It Li T Ta No tera Ta 1099511627776
+.It Li P Ta No peta Ta 1125899906842624
+.It Li E Ta No exa  Ta 1152921504606846976
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn expand_number
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The given string contains no digits.
+.It Bq Er EINVAL
+An unrecognized prefix was given.
+.It Bq Er ERANGE
+Result doesn't fit into 64 bits.
+.El
+.Sh SEE ALSO
+.Xr humanize_number 3
+.Sh HISTORY
+The
+.Fn expand_number
+function first appeared in
+.Fx 6.3 .
diff --git a/freebsd-userspace/lib/libutil/expand_number.c b/freebsd-userspace/lib/libutil/expand_number.c
new file mode 100644
index 0000000..4c8d6f5
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/expand_number.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2007 Eric Anderson <anderson at FreeBSD.org>
+ * Copyright (c) 2007 Pawel Jakub Dawidek <pjd at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libutil.h>
+#include <stdint.h>
+
+/*
+ * Convert an expression of the following forms to a int64_t.
+ * 	1) A positive decimal number.
+ *	2) A positive decimal number followed by a 'b' or 'B' (mult by 1).
+ *	3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
+ *	4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
+ *	5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
+ *	6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40).
+ *	7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50).
+ *	8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).
+ */
+int
+expand_number(const char *buf, int64_t *num)
+{
+	static const char unit[] = "bkmgtpe";
+	char *endptr, s;
+	int64_t number;
+	int i;
+
+	number = strtoimax(buf, &endptr, 0);
+
+	if (endptr == buf) {
+		/* No valid digits. */
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (*endptr == '\0') {
+		/* No unit. */
+		*num = number;
+		return (0);
+	}
+
+	s = tolower(*endptr);
+	switch (s) {
+	case 'b':
+	case 'k':
+	case 'm':
+	case 'g':
+	case 't':
+	case 'p':
+	case 'e':
+		break;
+	default:
+		/* Unrecognized unit. */
+		errno = EINVAL;
+		return (-1);
+	}
+
+	for (i = 0; unit[i] != '\0'; i++) {
+		if (s == unit[i])
+			break;
+		if ((number < 0 && (number << 10) > number) ||
+		    (number >= 0 && (number << 10) < number)) {
+			errno = ERANGE;
+			return (-1);
+		}
+		number <<= 10;
+	}
+
+	*num = number;
+	return (0);
+}
diff --git a/freebsd-userspace/lib/libutil/humanize_number.3 b/freebsd-userspace/lib/libutil/humanize_number.3
new file mode 100644
index 0000000..76d5677
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/humanize_number.3
@@ -0,0 +1,157 @@
+.\"	$NetBSD: humanize_number.3,v 1.4 2003/04/16 13:34:37 wiz Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn and by Tomas Svensson.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"        This product includes software developed by the NetBSD
+.\"        Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd May 25, 2004
+.Dt HUMANIZE_NUMBER 3
+.Os
+.Sh NAME
+.Nm humanize_number
+.Nd format a number into a human readable form
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In libutil.h
+.Ft int
+.Fo humanize_number
+.Fa "char *buf" "size_t len" "int64_t number" "const char *suffix"
+.Fa "int scale" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn humanize_number
+function formats the signed 64-bit quantity given in
+.Fa number
+into
+.Fa buffer .
+A space and then
+.Fa suffix
+is appended to the end.
+The buffer pointed to by
+.Fa buffer
+must be at least
+.Fa len
+bytes long.
+.Pp
+If the formatted number (including
+.Fa suffix )
+would be too long to fit into
+.Fa buffer ,
+then divide
+.Fa number
+by 1024 until it will.
+In this case, prefix
+.Fa suffix
+with the appropriate SI designator.
+The
+.Fn humanize_number
+function
+follows the traditional computer science conventions rather than the proposed
+SI power of two convention.
+.Pp
+The prefixes are:
+.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent
+.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" Ta Sy "Multiplier 1000x"
+.It Li k Ta No kilo Ta 1024 Ta 1000
+.It Li M Ta No mega Ta 1048576 Ta 1000000
+.It Li G Ta No giga Ta 1073741824 Ta 1000000000
+.It Li T Ta No tera Ta 1099511627776 Ta 1000000000000
+.It Li P Ta No peta Ta 1125899906842624 Ta 1000000000000000
+.It Li E Ta No exa Ta 1152921504606846976 Ta 1000000000000000000
+.El
+.Pp
+The
+.Fa len
+argument must be at least 4 plus the length of
+.Fa suffix ,
+in order to ensure a useful result is generated into
+.Fa buffer .
+To use a specific prefix, specify this as
+.Fa scale
+(multiplier = 1024 ^ scale).
+This cannot be combined with any of the
+.Fa scale
+flags below.
+.Pp
+The following flags may be passed in
+.Fa scale :
+.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
+.It Dv HN_AUTOSCALE
+Format the buffer using the lowest multiplier possible.
+.It Dv HN_GETSCALE
+Return the prefix index number (the number of times
+.Fa number
+must be divided to fit) instead of formatting it to the buffer.
+.El
+.Pp
+The following flags may be passed in
+.Fa flags :
+.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
+.It Dv HN_DECIMAL
+If the final result is less than 10, display it using one digit.
+.It Dv HN_NOSPACE
+Do not put a space between
+.Fa number
+and the prefix.
+.It Dv HN_B
+Use
+.Ql B
+(bytes) as prefix if the original result does not have a prefix.
+.It Dv HN_DIVISOR_1000
+Divide
+.Fa number
+with 1000 instead of 1024.
+.El
+.Sh RETURN VALUES
+The
+.Fn humanize_number
+function returns the number of characters stored in
+.Fa buffer
+(excluding the terminating
+.Dv NUL )
+upon success, or \-1 upon failure.
+If
+.Dv HN_GETSCALE
+is specified, the prefix index number will be returned instead.
+.Sh SEE ALSO
+.Xr expand_number 3
+.Sh HISTORY
+The
+.Fn humanize_number
+function first appeared in
+.Nx 2.0
+and then in
+.Fx 5.3 .
diff --git a/freebsd-userspace/lib/libutil/humanize_number.c b/freebsd-userspace/lib/libutil/humanize_number.c
new file mode 100644
index 0000000..de98587
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/humanize_number.c
@@ -0,0 +1,146 @@
+/*	$NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $	*/
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <libutil.h>
+
+int
+humanize_number(char *buf, size_t len, int64_t bytes,
+    const char *suffix, int scale, int flags)
+{
+	const char *prefixes, *sep;
+	int	b, i, r, maxscale, s1, s2, sign;
+	int64_t	divisor, max;
+	size_t	baselen;
+
+	assert(buf != NULL);
+	assert(suffix != NULL);
+	assert(scale >= 0);
+
+	if (flags & HN_DIVISOR_1000) {
+		/* SI for decimal multiplies */
+		divisor = 1000;
+		if (flags & HN_B)
+			prefixes = "B\0k\0M\0G\0T\0P\0E";
+		else
+			prefixes = "\0\0k\0M\0G\0T\0P\0E";
+	} else {
+		/*
+		 * binary multiplies
+		 * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+		 */
+		divisor = 1024;
+		if (flags & HN_B)
+			prefixes = "B\0K\0M\0G\0T\0P\0E";
+		else
+			prefixes = "\0\0K\0M\0G\0T\0P\0E";
+	}
+
+#define	SCALE2PREFIX(scale)	(&prefixes[(scale) << 1])
+	maxscale = 7;
+
+	if (scale >= maxscale &&
+	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+		return (-1);
+
+	if (buf == NULL || suffix == NULL)
+		return (-1);
+
+	if (len > 0)
+		buf[0] = '\0';
+	if (bytes < 0) {
+		sign = -1;
+		bytes *= -100;
+		baselen = 3;		/* sign, digit, prefix */
+	} else {
+		sign = 1;
+		bytes *= 100;
+		baselen = 2;		/* digit, prefix */
+	}
+	if (flags & HN_NOSPACE)
+		sep = "";
+	else {
+		sep = " ";
+		baselen++;
+	}
+	baselen += strlen(suffix);
+
+	/* Check if enough room for `x y' + suffix + `\0' */
+	if (len < baselen + 1)
+		return (-1);
+
+	if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+		/* See if there is additional columns can be used. */
+		for (max = 100, i = len - baselen; i-- > 0;)
+			max *= 10;
+
+		/*
+		 * Divide the number until it fits the given column.
+		 * If there will be an overflow by the rounding below,
+		 * divide once more.
+		 */
+		for (i = 0; bytes >= max - 50 && i < maxscale; i++)
+			bytes /= divisor;
+
+		if (scale & HN_GETSCALE)
+			return (i);
+	} else
+		for (i = 0; i < scale && i < maxscale; i++)
+			bytes /= divisor;
+
+	/* If a value <= 9.9 after rounding and ... */
+	if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+		/* baselen + \0 + .N */
+		if (len < baselen + 1 + 2)
+			return (-1);
+		b = ((int)bytes + 5) / 10;
+		s1 = b / 10;
+		s2 = b % 10;
+		r = snprintf(buf, len, "%d%s%d%s%s%s",
+		    sign * s1, localeconv()->decimal_point, s2,
+		    sep, SCALE2PREFIX(i), suffix);
+	} else
+		r = snprintf(buf, len, "%" PRId64 "%s%s%s",
+		    sign * ((bytes + 50) / 100),
+		    sep, SCALE2PREFIX(i), suffix);
+
+	return (r);
+}
diff --git a/freebsd-userspace/lib/libutil/libutil.h b/freebsd-userspace/lib/libutil/libutil.h
new file mode 100644
index 0000000..3187fb3
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/libutil.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1996  Peter Wemm <peter at FreeBSD.org>.
+ * All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBUTIL_H_
+#define	_LIBUTIL_H_
+
+#define PROPERTY_MAX_NAME	64
+#define PROPERTY_MAX_VALUE	512
+
+/* for properties.c */
+typedef struct _property {
+	struct _property *next;
+	char *name;
+	char *value;
+} *properties;
+
+#ifdef _SYS_PARAM_H_
+/* for pidfile.c */
+struct pidfh {
+	int	pf_fd;
+	char	pf_path[MAXPATHLEN + 1];
+	__dev_t	pf_dev;
+	ino_t	pf_ino;
+};
+#endif
+
+/* Avoid pulling in all the include files for no need */
+struct termios;
+struct winsize;
+struct utmp;
+struct in_addr;
+struct kinfo_file;
+struct kinfo_vmentry;
+
+__BEGIN_DECLS
+void	clean_environment(const char * const *_white,
+	    const char * const *_more_white);
+int	extattr_namespace_to_string(int _attrnamespace, char **_string);
+int	extattr_string_to_namespace(const char *_string, int *_attrnamespace);
+int	flopen(const char *_path, int _flags, ...);
+void	hexdump(const void *ptr, int length, const char *hdr, int flags);
+void	login(struct utmp *_ut);
+int	login_tty(int _fd);
+int	logout(const char *_line);
+void	logwtmp(const char *_line, const char *_name, const char *_host);
+void	trimdomain(char *_fullhost, int _hostsize);
+int	openpty(int *_amaster, int *_aslave, char *_name,
+		     struct termios *_termp, struct winsize *_winp);
+int	forkpty(int *_amaster, char *_name,
+		     struct termios *_termp, struct winsize *_winp);
+int	humanize_number(char *_buf, size_t _len, int64_t _number,
+	    const char *_suffix, int _scale, int _flags);
+int	expand_number(const char *_buf, int64_t *_num);
+const char *uu_lockerr(int _uu_lockresult);
+int	uu_lock(const char *_ttyname);
+int	uu_unlock(const char *_ttyname);
+int	uu_lock_txfr(const char *_ttyname, pid_t _pid);
+int	_secure_path(const char *_path, uid_t _uid, gid_t _gid);
+properties properties_read(int fd);
+void	properties_free(properties list);
+char	*property_find(properties list, const char *name);
+char	*auth_getval(const char *name);
+int	realhostname(char *host, size_t hsize, const struct in_addr *ip);
+struct sockaddr;
+int	realhostname_sa(char *host, size_t hsize, struct sockaddr *addr,
+			     int addrlen);
+
+int	kld_isloaded(const char *name);
+int	kld_load(const char *name);
+struct kinfo_file *
+	kinfo_getfile(pid_t _pid, int *_cntp);
+struct kinfo_vmentry *
+	kinfo_getvmmap(pid_t _pid, int *_cntp);
+
+#ifdef _STDIO_H_	/* avoid adding new includes */
+char   *fparseln(FILE *, size_t *, size_t *, const char[3], int);
+#endif
+
+#ifdef _PWD_H_
+int	pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw);
+struct passwd *pw_dup(const struct passwd *_pw);
+int	pw_edit(int _notsetuid);
+int	pw_equal(const struct passwd *_pw1, const struct passwd *_pw2);
+void	pw_fini(void);
+int	pw_init(const char *_dir, const char *_master);
+char	*pw_make(const struct passwd *_pw);
+int	pw_mkdb(const char *_user);
+int	pw_lock(void);
+struct passwd *pw_scan(const char *_line, int _flags);
+const char *pw_tempname(void);
+int	pw_tmp(int _mfd);
+#endif
+
+#ifdef _GRP_H_
+int	gr_equal(const struct group *gr1, const struct group *gr2);
+char	*gr_make(const struct group *gr);
+struct group *gr_dup(const struct group *gr);
+struct group *gr_scan(const char *line);
+#endif
+
+#ifdef _SYS_PARAM_H_
+struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);
+int pidfile_write(struct pidfh *pfh);
+int pidfile_close(struct pidfh *pfh);
+int pidfile_remove(struct pidfh *pfh);
+#endif
+
+__END_DECLS
+
+#define UU_LOCK_INUSE (1)
+#define UU_LOCK_OK (0)
+#define UU_LOCK_OPEN_ERR (-1)
+#define UU_LOCK_READ_ERR (-2)
+#define UU_LOCK_CREAT_ERR (-3)
+#define UU_LOCK_WRITE_ERR (-4)
+#define UU_LOCK_LINK_ERR (-5)
+#define UU_LOCK_TRY_ERR (-6)
+#define UU_LOCK_OWNER_ERR (-7)
+
+/* return values from realhostname() */
+#define HOSTNAME_FOUND		(0)
+#define HOSTNAME_INCORRECTNAME	(1)
+#define HOSTNAME_INVALIDADDR	(2)
+#define HOSTNAME_INVALIDNAME	(3)
+
+/* fparseln(3) */
+#define	FPARSELN_UNESCESC	0x01
+#define	FPARSELN_UNESCCONT	0x02
+#define	FPARSELN_UNESCCOMM	0x04
+#define	FPARSELN_UNESCREST	0x08
+#define	FPARSELN_UNESCALL	0x0f
+
+/* pw_scan() */
+#define PWSCAN_MASTER		0x01
+#define PWSCAN_WARN		0x02
+
+/* humanize_number(3) */
+#define HN_DECIMAL		0x01
+#define HN_NOSPACE		0x02
+#define HN_B			0x04
+#define HN_DIVISOR_1000		0x08
+
+#define HN_GETSCALE		0x10
+#define HN_AUTOSCALE		0x20
+
+/* hexdump(3) */
+#define	HD_COLUMN_MASK		0xff
+#define	HD_DELIM_MASK		0xff00
+#define	HD_OMIT_COUNT		(1 << 16)
+#define	HD_OMIT_HEX		(1 << 17)
+#define	HD_OMIT_CHARS		(1 << 18)
+
+#endif /* !_LIBUTIL_H_ */
diff --git a/freebsd-userspace/rtems/include/rtems/netcmds-config.h b/freebsd-userspace/rtems/include/rtems/netcmds-config.h
index f684816..8938e97 100644
--- a/freebsd-userspace/rtems/include/rtems/netcmds-config.h
+++ b/freebsd-userspace/rtems/include/rtems/netcmds-config.h
@@ -27,7 +27,7 @@
 
   extern rtems_shell_cmd_t rtems_shell_IFCONFIG_Command;
   extern rtems_shell_cmd_t rtems_shell_ROUTE_Command;
-  // extern rtems_shell_cmd_t rtems_shell_NETSTATS_Command;
+  extern rtems_shell_cmd_t rtems_shell_NETSTAT_Command;
 // #endif
 
 #endif
diff --git a/freebsd-userspace/sys/sys/nlist_aout.h b/freebsd-userspace/sys/sys/nlist_aout.h
new file mode 100644
index 0000000..a4e11c3
--- /dev/null
+++ b/freebsd-userspace/sys/sys/nlist_aout.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)nlist.h	8.2 (Berkeley) 1/21/94
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_NLIST_AOUT_H_
+#define	_SYS_NLIST_AOUT_H_
+
+/*
+ * Symbol table entries in a.out files.
+ */
+
+/*
+ * Layout of each symbol.  The "#ifdef _AOUT_INCLUDE_" is so that
+ * programs including nlist.h can initialize nlist structures
+ * statically.
+ */
+struct nlist {
+#ifdef _AOUT_INCLUDE_
+	union {
+		char *n_name;	/* symbol name (in memory) */
+		long n_strx;	/* file string table offset (on disk) */
+	} n_un;
+#else
+	char *n_name;		/* symbol name (in memory) */
+	int : 8 * (sizeof(long) > sizeof(char *) ?
+	    sizeof(long) - sizeof(char *) : sizeof(char *) - sizeof(long));
+#endif
+	unsigned char n_type;	/* type defines */
+	char n_other;		/* ".type" and binding information */
+	short n_desc;		/* used by stab entries */
+	unsigned long n_value;	/* address/value of the symbol */
+};
+
+#define	n_hash	n_desc		/* used internally by ld(1); XXX */
+
+/*
+ * Defines for n_type.
+ */
+#define	N_UNDF	0x00		/* undefined */
+#define	N_ABS	0x02		/* absolute address */
+#define	N_TEXT	0x04		/* text segment */
+#define	N_DATA	0x06		/* data segment */
+#define	N_BSS	0x08		/* bss segment */
+#define	N_INDR	0x0a		/* alias definition */
+#define	N_SIZE	0x0c		/* pseudo type, defines a symbol's size */
+#define	N_COMM	0x12		/* common reference */
+/* GNU extensions */
+#define N_SETA	0x14		/* Absolute set element symbol */
+#define N_SETT  0x16		/* Text set element symbol */
+#define N_SETD  0x18		/* Data set element symbol */
+#define N_SETB  0x1a		/* Bss set element symbol */
+#define N_SETV  0x1c		/* Pointer to set vector in data area. */
+/* end GNU extensions */
+#define	N_FN	0x1e		/* file name (N_EXT on) */
+#define	N_WARN	0x1e		/* warning message (N_EXT off) */
+
+#define	N_EXT	0x01		/* external (global) bit, OR'ed in */
+#define	N_TYPE	0x1e		/* mask for all the type bits */
+#define	N_STAB	0xe0		/* mask for debugger symbols -- stab(5) */
+
+/*
+ * Defines for n_other.  It contains the ".type" (AUX) field in the least
+ * significant 4 bits, and the binding (for weak symbols) in the most
+ * significant 4 bits.
+ */
+#define N_AUX(p)	((p)->n_other & 0xf)
+#define N_BIND(p)	(((unsigned int)(p)->n_other >> 4) & 0xf)
+#define N_OTHER(r, v)	(((unsigned int)(r) << 4) | ((v) & 0xf))
+
+#define AUX_OBJECT	1	/* data object */
+#define AUX_FUNC	2	/* function */
+
+/*#define BIND_LOCAL	0	not used */
+/*#define BIND_GLOBAL	1	not used */
+#define BIND_WEAK	2	/* weak binding */
+
+#define	N_FORMAT	"%08x"	/* namelist value format; XXX */
+
+#endif /* !_SYS_NLIST_AOUT_H_ */




More information about the vc mailing list