diff options
author | Joel Sherrill <joel.sherrill@oarcorp.com> | 2012-10-17 11:13:36 -0500 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@oarcorp.com> | 2012-10-17 11:13:36 -0500 |
commit | b6ac989f8a189c24500efa9b54ec466badfd3072 (patch) | |
tree | db534dfdfc3772a66748af861d1d36fb1d9ad35e | |
parent | Added rtems exit code to ping, route, and ifconfig commands. (diff) | |
download | rtems-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.
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_ */ |