summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@oarcorp.com>2012-10-17 11:13:36 -0500
committerJoel Sherrill <joel.sherrill@oarcorp.com>2012-10-17 11:13:36 -0500
commitb6ac989f8a189c24500efa9b54ec466badfd3072 (patch)
treedb534dfdfc3772a66748af861d1d36fb1d9ad35e
parentAdded rtems exit code to ping, route, and ifconfig commands. (diff)
downloadrtems-libbsd-b6ac989f8a189c24500efa9b54ec466badfd3072.tar.bz2
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.
-rw-r--r--freebsd-userspace/Makefile18
-rw-r--r--freebsd-userspace/commands/usr.bin/netstat/if.c8
-rw-r--r--freebsd-userspace/commands/usr.bin/netstat/inet.c21
-rw-r--r--freebsd-userspace/commands/usr.bin/netstat/main.c39
-rw-r--r--freebsd-userspace/commands/usr.bin/netstat/mbuf.c8
-rw-r--r--freebsd-userspace/commands/usr.bin/netstat/unix.c6
-rw-r--r--freebsd-userspace/include/nlist.h53
-rw-r--r--freebsd-userspace/lib/libmemstat/libmemstat.3496
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat.c421
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat.h178
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat_all.c58
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat_internal.h124
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat_malloc.c417
-rw-r--r--freebsd-userspace/lib/libmemstat/memstat_uma.c478
-rw-r--r--freebsd-userspace/lib/libutil/expand_number.386
-rw-r--r--freebsd-userspace/lib/libutil/expand_number.c100
-rw-r--r--freebsd-userspace/lib/libutil/humanize_number.3157
-rw-r--r--freebsd-userspace/lib/libutil/humanize_number.c146
-rw-r--r--freebsd-userspace/lib/libutil/libutil.h188
-rw-r--r--freebsd-userspace/rtems/include/rtems/netcmds-config.h2
-rw-r--r--freebsd-userspace/sys/sys/nlist_aout.h113
21 files changed, 3105 insertions, 12 deletions
diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index 566e742b..5cdc7ab1 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 d91db8c1..b487e100 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 37b650c5..f6d111f3 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 09b26a26..f1916048 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 dd105259..268fd861 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 17d52031..2e18c9ae 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 00000000..3dccf9e7
--- /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 00000000..9a4877b0
--- /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@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 00000000..28e48138
--- /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 00000000..5991a8f2
--- /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 00000000..bd74b8ac
--- /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 00000000..7123518e
--- /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 00000000..96ff8a16
--- /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 00000000..deac50d7
--- /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 00000000..23e488d3
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/expand_number.3
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
+.\" Copyright (c) 2007 Pawel Jakub Dawidek <pjd@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 00000000..4c8d6f5b
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/expand_number.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
+ * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@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 00000000..76d5677c
--- /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 00000000..de985870
--- /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 00000000..3187fb37
--- /dev/null
+++ b/freebsd-userspace/lib/libutil/libutil.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1996 Peter Wemm <peter@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 f684816d..8938e97b 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 00000000..a4e11c39
--- /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_ */